From 54f9c1b329a9c16022b17e03ca63cfef09a6815c Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 14:26:25 +0000 Subject: [PATCH 01/29] fix(gitignore): anchor docs/ to repo root so nested www/content/docs is tracked --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 86573aa..b1e0ec0 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ npm-debug.log* .claude/ # Local planning/design docs — never published to GitHub -docs/ +# Anchored to repo root so it does NOT match nested docs dirs like www/content/docs/ +/docs/ From 178546e77044695e81268434eaf722b2c6d9f267 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 14:26:26 +0000 Subject: [PATCH 02/29] chore(docs): scaffold Fumadocs site in www/ (Next 16, React 19, Orama local search) --- www/.gitignore | 26 + www/README.md | 43 + www/app/(home)/layout.tsx | 6 + www/app/(home)/page.tsx | 16 + www/app/api/search/route.ts | 7 + www/app/docs/[[...slug]]/page.tsx | 63 + www/app/docs/layout.tsx | 11 + www/app/global.css | 12 + www/app/layout.tsx | 17 + www/app/llms-full.txt/route.ts | 10 + www/app/llms.mdx/docs/[[...slug]]/route.ts | 23 + www/app/llms.txt/route.ts | 8 + www/app/og/docs/[...slug]/route.tsx | 28 + www/components/mdx.tsx | 15 + www/content/docs/index.mdx | 13 + www/content/docs/test.mdx | 17 + www/lib/cn.ts | 1 + www/lib/layout.shared.tsx | 12 + www/lib/shared.ts | 11 + www/lib/source.ts | 37 + www/next.config.mjs | 10 + www/package-lock.json | 6125 ++++++++++++++++++++ www/package.json | 31 + www/postcss.config.mjs | 7 + www/proxy.ts | 29 + www/source.config.ts | 23 + www/tsconfig.json | 35 + 27 files changed, 6636 insertions(+) create mode 100644 www/.gitignore create mode 100644 www/README.md create mode 100644 www/app/(home)/layout.tsx create mode 100644 www/app/(home)/page.tsx create mode 100644 www/app/api/search/route.ts create mode 100644 www/app/docs/[[...slug]]/page.tsx create mode 100644 www/app/docs/layout.tsx create mode 100644 www/app/global.css create mode 100644 www/app/layout.tsx create mode 100644 www/app/llms-full.txt/route.ts create mode 100644 www/app/llms.mdx/docs/[[...slug]]/route.ts create mode 100644 www/app/llms.txt/route.ts create mode 100644 www/app/og/docs/[...slug]/route.tsx create mode 100644 www/components/mdx.tsx create mode 100644 www/content/docs/index.mdx create mode 100644 www/content/docs/test.mdx create mode 100644 www/lib/cn.ts create mode 100644 www/lib/layout.shared.tsx create mode 100644 www/lib/shared.ts create mode 100644 www/lib/source.ts create mode 100644 www/next.config.mjs create mode 100644 www/package-lock.json create mode 100644 www/package.json create mode 100644 www/postcss.config.mjs create mode 100644 www/proxy.ts create mode 100644 www/source.config.ts create mode 100644 www/tsconfig.json diff --git a/www/.gitignore b/www/.gitignore new file mode 100644 index 0000000..9e429e4 --- /dev/null +++ b/www/.gitignore @@ -0,0 +1,26 @@ +# deps +/node_modules + +# generated content +.source + +# test & build +/coverage +/.next/ +/out/ +/build +*.tsbuildinfo + +# misc +.DS_Store +*.pem +/.pnp +.pnp.js +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# others +.env*.local +.vercel +next-env.d.ts \ No newline at end of file diff --git a/www/README.md b/www/README.md new file mode 100644 index 0000000..15fd17e --- /dev/null +++ b/www/README.md @@ -0,0 +1,43 @@ +This is a Next.js application generated with +[Create Fumadocs](https://github.com/fuma-nama/fumadocs). + +Run development server: + +```bash +npm run dev +# or +pnpm dev +# or +yarn dev +``` + +Open http://localhost:3000 with your browser to see the result. + +## Explore + +In the project, you can see: + +- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content. +- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep. + +| Route | Description | +| ------------------------- | ------------------------------------------------------ | +| `app/(home)` | The route group for your landing page and other pages. | +| `app/docs` | The documentation layout and pages. | +| `app/api/search/route.ts` | The Route Handler for search. | + +### Fumadocs MDX + +A `source.config.ts` config file has been included, you can customise different options like frontmatter schema. + +Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details. + +## Learn More + +To learn more about Next.js and Fumadocs, take a look at the following +resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js + features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs diff --git a/www/app/(home)/layout.tsx b/www/app/(home)/layout.tsx new file mode 100644 index 0000000..77379fa --- /dev/null +++ b/www/app/(home)/layout.tsx @@ -0,0 +1,6 @@ +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { baseOptions } from '@/lib/layout.shared'; + +export default function Layout({ children }: LayoutProps<'/'>) { + return {children}; +} diff --git a/www/app/(home)/page.tsx b/www/app/(home)/page.tsx new file mode 100644 index 0000000..c936084 --- /dev/null +++ b/www/app/(home)/page.tsx @@ -0,0 +1,16 @@ +import Link from 'next/link'; + +export default function HomePage() { + return ( +
+

Hello World

+

+ You can open{' '} + + /docs + {' '} + and see the documentation. +

+
+ ); +} diff --git a/www/app/api/search/route.ts b/www/app/api/search/route.ts new file mode 100644 index 0000000..7ba7e82 --- /dev/null +++ b/www/app/api/search/route.ts @@ -0,0 +1,7 @@ +import { source } from '@/lib/source'; +import { createFromSource } from 'fumadocs-core/search/server'; + +export const { GET } = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', +}); diff --git a/www/app/docs/[[...slug]]/page.tsx b/www/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..7a0a558 --- /dev/null +++ b/www/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,63 @@ +import { getPageImageUrl, getPageMarkdownUrl, source } from '@/lib/source'; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, + MarkdownCopyButton, + ViewOptionsPopover, +} from 'fumadocs-ui/layouts/docs/page'; +import { notFound } from 'next/navigation'; +import { getMDXComponents } from '@/components/mdx'; +import type { Metadata } from 'next'; +import { createRelativeLink } from 'fumadocs-ui/mdx'; +import { gitConfig } from '@/lib/shared'; + +export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + const MDX = page.data.body; + const markdownUrl = getPageMarkdownUrl(page).url; + + return ( + + {page.data.title} + {page.data.description} +
+ + +
+ + + +
+ ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImageUrl(page).url, + }, + }; +} diff --git a/www/app/docs/layout.tsx b/www/app/docs/layout.tsx new file mode 100644 index 0000000..a373143 --- /dev/null +++ b/www/app/docs/layout.tsx @@ -0,0 +1,11 @@ +import { source } from '@/lib/source'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import { baseOptions } from '@/lib/layout.shared'; + +export default function Layout({ children }: LayoutProps<'/docs'>) { + return ( + + {children} + + ); +} diff --git a/www/app/global.css b/www/app/global.css new file mode 100644 index 0000000..f86f3c9 --- /dev/null +++ b/www/app/global.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; + +html { + scrollbar-gutter: stable; +} + +html > body[data-scroll-locked] { + margin-right: 0px !important; + --removed-body-scroll-bar-size: 0px !important; +} diff --git a/www/app/layout.tsx b/www/app/layout.tsx new file mode 100644 index 0000000..22fdca3 --- /dev/null +++ b/www/app/layout.tsx @@ -0,0 +1,17 @@ +import { RootProvider } from 'fumadocs-ui/provider/next'; +import './global.css'; +import { Inter } from 'next/font/google'; + +const inter = Inter({ + subsets: ['latin'], +}); + +export default function Layout({ children }: LayoutProps<'/'>) { + return ( + + + {children} + + + ); +} diff --git a/www/app/llms-full.txt/route.ts b/www/app/llms-full.txt/route.ts new file mode 100644 index 0000000..d494d2c --- /dev/null +++ b/www/app/llms-full.txt/route.ts @@ -0,0 +1,10 @@ +import { getLLMText, source } from '@/lib/source'; + +export const revalidate = false; + +export async function GET() { + const scan = source.getPages().map(getLLMText); + const scanned = await Promise.all(scan); + + return new Response(scanned.join('\n\n')); +} diff --git a/www/app/llms.mdx/docs/[[...slug]]/route.ts b/www/app/llms.mdx/docs/[[...slug]]/route.ts new file mode 100644 index 0000000..250181a --- /dev/null +++ b/www/app/llms.mdx/docs/[[...slug]]/route.ts @@ -0,0 +1,23 @@ +import { getLLMText, getPageMarkdownUrl, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/llms.mdx/docs/[[...slug]]'>) { + const { slug } = await params; + const page = source.getPage(slug?.slice(0, -1)); + if (!page) notFound(); + + return new Response(await getLLMText(page), { + headers: { + 'Content-Type': 'text/markdown', + }, + }); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageMarkdownUrl(page).segments, + })); +} diff --git a/www/app/llms.txt/route.ts b/www/app/llms.txt/route.ts new file mode 100644 index 0000000..fc80cb6 --- /dev/null +++ b/www/app/llms.txt/route.ts @@ -0,0 +1,8 @@ +import { source } from '@/lib/source'; +import { llms } from 'fumadocs-core/source'; + +export const revalidate = false; + +export function GET() { + return new Response(llms(source).index()); +} diff --git a/www/app/og/docs/[...slug]/route.tsx b/www/app/og/docs/[...slug]/route.tsx new file mode 100644 index 0000000..e33c421 --- /dev/null +++ b/www/app/og/docs/[...slug]/route.tsx @@ -0,0 +1,28 @@ +import { getPageImageUrl, source } from '@/lib/source'; +import { notFound } from 'next/navigation'; +import { ImageResponse } from 'next/og'; +import { generate as DefaultImage } from 'fumadocs-ui/og'; +import { appName } from '@/lib/shared'; + +export const revalidate = false; + +export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); + + return new ImageResponse( + , + { + width: 1200, + height: 630, + }, + ); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImageUrl(page).segments, + })); +} diff --git a/www/components/mdx.tsx b/www/components/mdx.tsx new file mode 100644 index 0000000..a640575 --- /dev/null +++ b/www/components/mdx.tsx @@ -0,0 +1,15 @@ +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import type { MDXComponents } from 'mdx/types'; + +export function getMDXComponents(components?: MDXComponents) { + return { + ...defaultMdxComponents, + ...components, + } satisfies MDXComponents; +} + +export const useMDXComponents = getMDXComponents; + +declare global { + type MDXProvidedComponents = ReturnType; +} diff --git a/www/content/docs/index.mdx b/www/content/docs/index.mdx new file mode 100644 index 0000000..1ede18e --- /dev/null +++ b/www/content/docs/index.mdx @@ -0,0 +1,13 @@ +--- +title: Hello World +description: Your first document +--- + +Welcome to the docs! You can start writing documents in `/content/docs`. + +## What is Next? + + + + + diff --git a/www/content/docs/test.mdx b/www/content/docs/test.mdx new file mode 100644 index 0000000..f475f4a --- /dev/null +++ b/www/content/docs/test.mdx @@ -0,0 +1,17 @@ +--- +title: Components +description: Components +--- + +## Code Block + +```js +console.log('Hello World'); +``` + +## Cards + + + + + diff --git a/www/lib/cn.ts b/www/lib/cn.ts new file mode 100644 index 0000000..241ffb3 --- /dev/null +++ b/www/lib/cn.ts @@ -0,0 +1 @@ +export { cn } from 'cnfast'; diff --git a/www/lib/layout.shared.tsx b/www/lib/layout.shared.tsx new file mode 100644 index 0000000..88b9ca8 --- /dev/null +++ b/www/lib/layout.shared.tsx @@ -0,0 +1,12 @@ +import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; +import { appName, gitConfig } from './shared'; + +export function baseOptions(): BaseLayoutProps { + return { + nav: { + // JSX supported + title: appName, + }, + githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`, + }; +} diff --git a/www/lib/shared.ts b/www/lib/shared.ts new file mode 100644 index 0000000..812926e --- /dev/null +++ b/www/lib/shared.ts @@ -0,0 +1,11 @@ +export const appName = 'My App'; +export const docsRoute = '/docs'; +export const docsImageRoute = '/og/docs'; +export const docsContentRoute = '/llms.mdx/docs'; + +// fill this with your actual GitHub info, for example: +export const gitConfig = { + user: 'fuma-nama', + repo: 'fumadocs', + branch: 'main', +}; diff --git a/www/lib/source.ts b/www/lib/source.ts new file mode 100644 index 0000000..ae637be --- /dev/null +++ b/www/lib/source.ts @@ -0,0 +1,37 @@ +import { docs } from 'collections/server'; +import { loader } from 'fumadocs-core/source'; +import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons'; +import { docsContentRoute, docsImageRoute, docsRoute } from './shared'; + +// See https://fumadocs.dev/docs/headless/source-api for more info +export const source = loader({ + baseUrl: docsRoute, + source: docs.toFumadocsSource(), + plugins: [lucideIconsPlugin()], +}); + +export function getPageImageUrl(page: (typeof source)['$inferPage']) { + const segments = [...page.slugs, 'image.png']; + + return { + segments, + url: '/' + [page.locale, ...docsImageRoute.split('/'), ...segments].filter(Boolean).join('/'), + }; +} + +export function getPageMarkdownUrl(page: (typeof source)['$inferPage']) { + const segments = [...page.slugs, 'content.md']; + + return { + segments, + url: '/' + [page.locale, ...docsContentRoute.split('/'), ...segments].filter(Boolean).join('/'), + }; +} + +export async function getLLMText(page: (typeof source)['$inferPage']) { + const processed = await page.data.getText('processed'); + + return `# ${page.data.title} (${page.url}) + +${processed}`; +} diff --git a/www/next.config.mjs b/www/next.config.mjs new file mode 100644 index 0000000..457dcf2 --- /dev/null +++ b/www/next.config.mjs @@ -0,0 +1,10 @@ +import { createMDX } from 'fumadocs-mdx/next'; + +const withMDX = createMDX(); + +/** @type {import('next').NextConfig} */ +const config = { + reactStrictMode: true, +}; + +export default withMDX(config); diff --git a/www/package-lock.json b/www/package-lock.json new file mode 100644 index 0000000..741b15d --- /dev/null +++ b/www/package-lock.json @@ -0,0 +1,6125 @@ +{ + "name": "tablecraft-docs", + "version": "0.0.8", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tablecraft-docs", + "version": "0.0.8", + "dependencies": { + "cnfast": "^0.0.8", + "fumadocs-core": "^16.12.1", + "fumadocs-mdx": "^15.2.0", + "fumadocs-ui": "^16.12.1", + "lucide-react": "^1.25.0", + "next": "16.2.11", + "react": "^19.2.8", + "react-dom": "^19.2.8" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3.3", + "@types/mdx": "^2.0.14", + "@types/node": "^26.1.1", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "postcss": "^8.5.21", + "tailwindcss": "^4.3.3", + "typescript": "^6.0.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@fuma-translate/react": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@fuma-translate/react/-/react-1.0.2.tgz", + "integrity": "sha512-uOiOtBx3nRXR8Nu1GzBf1tApgF1FErDBTHxRIAQeyQdyOoZbrNRN6H4kDCWObY4qyGeGbHydG0DHzgeUgFDMIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@fumadocs/tailwind": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fumadocs/tailwind/-/tailwind-0.1.1.tgz", + "integrity": "sha512-BnPe52UxSaG8yKlHMKBxXw8h6GpK5qO55ci6+Qd5JnquTvIw6SpfbC1P+qAi82PuPWv1KZAWY8bxRk4+x9ctXw==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": "^4.0.0" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@next/env": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz", + "integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz", + "integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz", + "integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz", + "integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz", + "integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz", + "integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz", + "integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz", + "integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz", + "integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@orama/orama": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/@orama/orama/-/orama-3.1.18.tgz", + "integrity": "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20.0.0" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.3.tgz", + "integrity": "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", + "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.20.tgz", + "integrity": "sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collapsible": "1.1.20", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz", + "integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.20.tgz", + "integrity": "sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.15.tgz", + "integrity": "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", + "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz", + "integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz", + "integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.4.tgz", + "integrity": "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz", + "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-effect-event": "0.0.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz", + "integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz", + "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", + "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.22.tgz", + "integrity": "sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-previous": "1.1.4", + "@radix-ui/react-visually-hidden": "1.2.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.23.tgz", + "integrity": "sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-dismissable-layer": "1.1.19", + "@radix-ui/react-focus-guards": "1.1.6", + "@radix-ui/react-focus-scope": "1.1.16", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-popper": "1.3.7", + "@radix-ui/react-portal": "1.1.17", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-slot": "1.3.3", + "@radix-ui/react-use-controllable-state": "1.2.6", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz", + "integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/react-use-rect": "1.1.4", + "@radix-ui/react-use-size": "1.1.4", + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz", + "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz", + "integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz", + "integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.3.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz", + "integrity": "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-collection": "1.1.15", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/react-use-is-hydrated": "0.1.3", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.18.tgz", + "integrity": "sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.3", + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz", + "integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.21.tgz", + "integrity": "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-context": "1.2.2", + "@radix-ui/react-direction": "1.1.4", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-presence": "1.1.10", + "@radix-ui/react-primitive": "2.1.10", + "@radix-ui/react-roving-focus": "1.1.19", + "@radix-ui/react-use-controllable-state": "1.2.6" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz", + "integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz", + "integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.7", + "@radix-ui/react-use-effect-event": "0.0.5", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", + "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz", + "integrity": "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", + "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz", + "integrity": "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz", + "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz", + "integrity": "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz", + "integrity": "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.10" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz", + "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.1.tgz", + "integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.3.1", + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.1.tgz", + "integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.1.tgz", + "integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.1.tgz", + "integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.1.tgz", + "integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz", + "integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", + "integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", + "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "postcss": "^8.5.16", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", + "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "license": "ISC" + }, + "node_modules/@yuku-analyzer/binding-darwin-arm64": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-darwin-arm64/-/binding-darwin-arm64-0.6.12.tgz", + "integrity": "sha512-9rpIP7IeybjyvWUf6WnU24h1qo+JdxIHr1o3yb06HoE8tM3S/Jh5RrUw9aw5P9BKSIvSPbLyVlItX7PcD3o5bQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-analyzer/binding-darwin-x64": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-darwin-x64/-/binding-darwin-x64-0.6.12.tgz", + "integrity": "sha512-ELLhNT4FGnqY8yh0W3cSs9rGMSeUyhib1aYD84RupjlfsrDTrQRoDhWu01Dv6xCfYgASYaj1Abntk91A7njNag==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-analyzer/binding-freebsd-x64": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-freebsd-x64/-/binding-freebsd-x64-0.6.12.tgz", + "integrity": "sha512-s76XocUMlK9liTyipALFb2K64ku35u/wg238A0NW8U5CUDsuIe/8tu5TzdLjJAGxnd0IV+gBneDt9cJJzLeFRQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-arm-gnu": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.6.12.tgz", + "integrity": "sha512-hm8Tq0umop3RGu6dOMF61q69tYn1bDp1CeYD5ZjuGFQJclp0moVtjzY4z0bzusicKeZ9+k5LRroR0p5HWC2hDw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-arm-musl": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-arm-musl/-/binding-linux-arm-musl-0.6.12.tgz", + "integrity": "sha512-CxtPKLddogHAB3ZHVWaUl+U8jx0pdriTSbQ1K/orlDqU0GDhg8LuIRyUscP7r2/62fGGMzkc119fE71I4Nl1Fg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-arm64-gnu": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.6.12.tgz", + "integrity": "sha512-EOyLcpAmF5qAVDKmKvV7xt8oBGeWQ92CqFI4s7h7TRlrF6TfGRrh8PwawGn92gFploNLAYj/1Z9Q1gVvwGgG9g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-arm64-musl": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.6.12.tgz", + "integrity": "sha512-T3eCYy6bMnVRMQEYAbDcpj08/XM93dBTtnn/DDocJN21RARe+KCzWKeL26J3yd3bOW3WVjVLq09BfdpAGB0buQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-x64-gnu": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.6.12.tgz", + "integrity": "sha512-1Y+noIuvnDugIVsoIr5NduZqX7KuFTzICSkvG8RW3OKK9URVeTOicKK217i44ABZSSZJ7A0E7vzifapx0c9VDw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-linux-x64-musl": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-linux-x64-musl/-/binding-linux-x64-musl-0.6.12.tgz", + "integrity": "sha512-woN/GuG95Fd6bp+ZQfmiFrZnoA2hdu3vfVSc89A8LElnYpzFaJM81sOZp8f3tVOVUJxbt7KAUiCLwSy34MJKqA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-analyzer/binding-win32-arm64": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-win32-arm64/-/binding-win32-arm64-0.6.12.tgz", + "integrity": "sha512-8OVFnKbK+lgsL6MqILPLpzlsa00K4KiKsdbHH94hpGcrqaz1jv+k0Y7ujSaoYTWw5Bb7Lr9GJ3L1n1hT2sXoYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-analyzer/binding-win32-x64": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@yuku-analyzer/binding-win32-x64/-/binding-win32-x64-0.6.12.tgz", + "integrity": "sha512-3w8w1Xc5njwgbGTcn3JfDxWuQnFvtSll1D8gBlk4U8CI5v7ibKOMIdABucCXH8WtsRREG0ME5Vn0i422eX3zLQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-toolchain/types": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/@yuku-toolchain/types/-/types-0.6.11.tgz", + "integrity": "sha512-i1JYFNJaKNCgyJ/nVoR8GK7wvlXF+ShYzFHBauWcvg8IoiXInK7pVziHcgNz/MWLPNr/Mb/CtmXccrJMkKqSHQ==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.3.tgz", + "integrity": "sha512-sbT0Ui/CZwyAyy7icT1Gw5P1LKRlFaHwaF6tDCW5YHq2X5SeeZFphBuIagopSfwSSZq3sQcbmEL072yphxm7ew==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cnfast": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/cnfast/-/cnfast-0.0.8.tgz", + "integrity": "sha512-EjXKMfGfdwtV4AcNSQ6AwQaVzpC1B7IxeiwA3FlhTXz+YFlMKVi4c1JX9tgD2QOlahQXjB8KUXrBaYG+3v871Q==", + "license": "MIT", + "bin": { + "cnfast": "bin/cli.js" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", + "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.5.0.tgz", + "integrity": "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/framer-motion": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.2.tgz", + "integrity": "sha512-5XY9luDiu0oHfHBjpDthFMh0ES+122w6p/papSJBweMkO8Sn+PW2QaEgRblQBpWFnuvZS5qvarpt/hO2pjGmnw==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.2", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fumadocs-core": { + "version": "16.12.1", + "resolved": "https://registry.npmjs.org/fumadocs-core/-/fumadocs-core-16.12.1.tgz", + "integrity": "sha512-6NnDxUqe0hIiShbWjqvLXvPYV0n0gi01UHmDAkDs5KVcfxfgOPz5bAbj45JDY0Ykq39Mr8z1xRt9h/HwIhe8fw==", + "license": "MIT", + "dependencies": { + "@orama/orama": "^3.1.18", + "estree-util-value-to-estree": "^3.5.0", + "github-slugger": "^2.0.0", + "hast-util-to-estree": "^3.1.3", + "hast-util-to-jsx-runtime": "^2.3.6", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-markdown": "^2.1.2", + "npm-to-yarn": "3.1.0", + "remark": "^15.0.1", + "remark-gfm": "^4.0.1", + "remark-rehype": "^11.1.2", + "scroll-into-view-if-needed": "^3.1.0", + "shiki": "^4.3.1", + "tinyglobby": "^0.2.17", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@mdx-js/mdx": "*", + "@mixedbread/sdk": "0.x.x", + "@orama/core": "1.x.x", + "@oramacloud/client": "2.x.x", + "@tanstack/react-router": "1.x.x", + "@types/estree-jsx": "*", + "@types/hast": "*", + "@types/mdast": "*", + "@types/react": "*", + "algoliasearch": "5.x.x", + "flexsearch": "*", + "lucide-react": "*", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router": "7.x.x || 8.x.x", + "waku": "*", + "zod": "4.x.x" + }, + "peerDependenciesMeta": { + "@mdx-js/mdx": { + "optional": true + }, + "@mixedbread/sdk": { + "optional": true + }, + "@orama/core": { + "optional": true + }, + "@oramacloud/client": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "@types/estree-jsx": { + "optional": true + }, + "@types/hast": { + "optional": true + }, + "@types/mdast": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "algoliasearch": { + "optional": true + }, + "flexsearch": { + "optional": true + }, + "lucide-react": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-router": { + "optional": true + }, + "waku": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/fumadocs-mdx": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/fumadocs-mdx/-/fumadocs-mdx-15.2.0.tgz", + "integrity": "sha512-+yBP8QYw5wA9LF5eVdMhwbP7KT1OF4B/YfC6PZoD2jz0amZi1B+6QHTI6XoRRSTmhWrI4cL5LU1DspW0itk+NA==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.1.1", + "@standard-schema/spec": "^1.1.0", + "chokidar": "^5.0.0", + "esbuild": "^0.28.1", + "estree-util-value-to-estree": "^3.5.0", + "github-slugger": "^2.0.0", + "magic-string": "^0.30.21", + "mdast-util-mdx": "^3.0.0", + "picocolors": "^1.1.1", + "picomatch": "^4.0.5", + "tinyexec": "^1.2.4", + "tinyglobby": "^0.2.17", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3", + "yaml": "^2.9.0", + "yuku-analyzer": "^0.6.3", + "zod": "^4.4.3" + }, + "bin": { + "fumadocs-mdx": "bin.js" + }, + "peerDependencies": { + "@fumadocs/satteri": "0.x.x", + "@types/mdast": "*", + "@types/mdx": "*", + "@types/react": "*", + "fumadocs-core": "^16.7.0", + "mdast-util-directive": "*", + "next": "^15.3.0 || ^16.0.0", + "react": "^19.2.0", + "rolldown": "*", + "satteri": "^0.9.4", + "vite": "7.x.x || 8.x.x" + }, + "peerDependenciesMeta": { + "@fumadocs/satteri": { + "optional": true + }, + "@types/mdast": { + "optional": true + }, + "@types/mdx": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "mdast-util-directive": { + "optional": true + }, + "next": { + "optional": true + }, + "react": { + "optional": true + }, + "rolldown": { + "optional": true + }, + "satteri": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/fumadocs-ui": { + "version": "16.12.1", + "resolved": "https://registry.npmjs.org/fumadocs-ui/-/fumadocs-ui-16.12.1.tgz", + "integrity": "sha512-/YYERe99PJYw09RiYmCetdcu9uIjrUff+uoYk1EzgTLNtKlt2FNJJCcWYykG76wWlT28hXRs1bt8eFVq9dIU9w==", + "license": "MIT", + "dependencies": { + "@fuma-translate/react": "^1.0.2", + "@fumadocs/tailwind": "0.1.1", + "@radix-ui/react-accordion": "^1.2.17", + "@radix-ui/react-collapsible": "^1.1.17", + "@radix-ui/react-dialog": "^1.1.20", + "@radix-ui/react-direction": "^1.1.2", + "@radix-ui/react-navigation-menu": "^1.2.19", + "@radix-ui/react-popover": "^1.1.20", + "@radix-ui/react-presence": "^1.1.8", + "@radix-ui/react-scroll-area": "^1.2.15", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-tabs": "^1.1.18", + "class-variance-authority": "^0.7.1", + "cnfast": "^0.0.8", + "lucide-react": "^1.25.0", + "motion": "^12.42.2", + "next-themes": "^0.4.6", + "react-remove-scroll": "^2.7.2", + "rehype-raw": "^7.0.0", + "scroll-into-view-if-needed": "^3.1.0", + "shiki": "^4.3.1", + "unist-util-visit": "^5.1.0" + }, + "peerDependencies": { + "@types/mdx": "*", + "@types/react": "*", + "fumadocs-core": "16.12.1", + "next": "16.x.x", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "takumi-js": "*" + }, + "peerDependenciesMeta": { + "@types/mdx": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "next": { + "optional": true + }, + "takumi-js": { + "optional": true + } + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lucide-react": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.27.0.tgz", + "integrity": "sha512-rJicGl/3Fly/E0rOH1YmPZ6e49JCnKknh1ox1vpHnkfjujAkKA6sqUZvH3MTAaXXjgexyUwgNwTJzTtYuAFYJw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/motion": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.42.2.tgz", + "integrity": "sha512-Atvv11yUKIid41cVrRBDVX5m8tF8kNpExRSlbpt6APClhDjtwQssgFHhQzejxw7/7YYbjHSPKBVbHo05BuJT5Q==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.42.2", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.42.2", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.2.tgz", + "integrity": "sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz", + "integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.11", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.11", + "@next/swc-darwin-x64": "16.2.11", + "@next/swc-linux-arm64-gnu": "16.2.11", + "@next/swc-linux-arm64-musl": "16.2.11", + "@next/swc-linux-x64-gnu": "16.2.11", + "@next/swc-linux-x64-musl": "16.2.11", + "@next/swc-win32-arm64-msvc": "16.2.11", + "@next/swc-win32-x64-msvc": "16.2.11", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/npm-to-yarn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-to-yarn/-/npm-to-yarn-3.1.0.tgz", + "integrity": "sha512-9gNsO/JB3LeWOZXBX09cKMsCPwVcu1ExIf+GUuTN9G+0zZvLIK0nU9+lE9jue3MSKAxPdrh0rO072mWNvciqeQ==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/nebrelbug/npm-to-yarn?sponsor=1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shiki": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.1.tgz", + "integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.3.1", + "@shikijs/engine-javascript": "4.3.1", + "@shikijs/engine-oniguruma": "4.3.1", + "@shikijs/langs": "4.3.1", + "@shikijs/themes": "4.3.1", + "@shikijs/types": "4.3.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yuku-analyzer": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/yuku-analyzer/-/yuku-analyzer-0.6.12.tgz", + "integrity": "sha512-0zu/gwv6nKA3wm2GMjM1iczw9rbt77ijEyR5tXpPQ8AZcXIpXlll66BXOtMHgYudLn91bJx0ybhpARoJWm5/dw==", + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "0.6.11", + "yuku-ast": "0.6.11" + }, + "optionalDependencies": { + "@yuku-analyzer/binding-darwin-arm64": "0.6.12", + "@yuku-analyzer/binding-darwin-x64": "0.6.12", + "@yuku-analyzer/binding-freebsd-x64": "0.6.12", + "@yuku-analyzer/binding-linux-arm-gnu": "0.6.12", + "@yuku-analyzer/binding-linux-arm-musl": "0.6.12", + "@yuku-analyzer/binding-linux-arm64-gnu": "0.6.12", + "@yuku-analyzer/binding-linux-arm64-musl": "0.6.12", + "@yuku-analyzer/binding-linux-x64-gnu": "0.6.12", + "@yuku-analyzer/binding-linux-x64-musl": "0.6.12", + "@yuku-analyzer/binding-win32-arm64": "0.6.12", + "@yuku-analyzer/binding-win32-x64": "0.6.12" + } + }, + "node_modules/yuku-ast": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/yuku-ast/-/yuku-ast-0.6.11.tgz", + "integrity": "sha512-ZfXkFYVsDewS45+kv3WiA/qNB73CRfxFDEQwfnRMUAR4AD5zRI7PRqxmI2U3Jz/oG41GneTVW6mxDOQal0lgeA==", + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "0.6.8" + } + }, + "node_modules/yuku-ast/node_modules/@yuku-toolchain/types": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@yuku-toolchain/types/-/types-0.6.8.tgz", + "integrity": "sha512-AbUd1775RVkOxJkh8hkldIWoU6kRMTCsZFSZq8Ny53q7GkbaVe5UCfleNZ3RWCoz/ZKE8qwfeB7Cj0xqhLWsKA==", + "license": "MIT" + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/www/package.json b/www/package.json new file mode 100644 index 0000000..fd23050 --- /dev/null +++ b/www/package.json @@ -0,0 +1,31 @@ +{ + "name": "tablecraft-docs", + "version": "0.0.8", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "start": "next start", + "types:check": "fumadocs-mdx && next typegen && tsc --noEmit" + }, + "dependencies": { + "cnfast": "^0.0.8", + "fumadocs-core": "^16.12.1", + "fumadocs-mdx": "^15.2.0", + "fumadocs-ui": "^16.12.1", + "lucide-react": "^1.25.0", + "next": "16.2.11", + "react": "^19.2.8", + "react-dom": "^19.2.8" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3.3", + "@types/mdx": "^2.0.14", + "@types/node": "^26.1.1", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "postcss": "^8.5.21", + "tailwindcss": "^4.3.3", + "typescript": "^6.0.3" + } +} diff --git a/www/postcss.config.mjs b/www/postcss.config.mjs new file mode 100644 index 0000000..297374d --- /dev/null +++ b/www/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; + +export default config; diff --git a/www/proxy.ts b/www/proxy.ts new file mode 100644 index 0000000..c5ce1be --- /dev/null +++ b/www/proxy.ts @@ -0,0 +1,29 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { isMarkdownPreferred, rewritePath } from 'fumadocs-core/negotiation'; +import { docsContentRoute, docsRoute } from '@/lib/shared'; + +const { rewrite: rewriteDocs } = rewritePath( + `${docsRoute}{/*path}`, + `${docsContentRoute}{/*path}/content.md`, +); +const { rewrite: rewriteSuffix } = rewritePath( + `${docsRoute}{/*path}.md`, + `${docsContentRoute}{/*path}/content.md`, +); + +export default function proxy(request: NextRequest) { + const result = rewriteSuffix(request.nextUrl.pathname); + if (result) { + return NextResponse.rewrite(new URL(result, request.nextUrl)); + } + + if (isMarkdownPreferred(request)) { + const result = rewriteDocs(request.nextUrl.pathname); + + if (result) { + return NextResponse.rewrite(new URL(result, request.nextUrl)); + } + } + + return NextResponse.next(); +} diff --git a/www/source.config.ts b/www/source.config.ts new file mode 100644 index 0000000..a35628a --- /dev/null +++ b/www/source.config.ts @@ -0,0 +1,23 @@ +import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; +import { metaSchema, pageSchema } from 'fumadocs-core/source/schema'; + +// You can customize Zod schemas for frontmatter and `meta.json` here +// see https://fumadocs.dev/docs/mdx/collections +export const docs = defineDocs({ + dir: 'content/docs', + docs: { + schema: pageSchema, + postprocess: { + includeProcessedMarkdown: true, + }, + }, + meta: { + schema: metaSchema, + }, +}); + +export default defineConfig({ + mdxOptions: { + // MDX options + }, +}); diff --git a/www/tsconfig.json b/www/tsconfig.json new file mode 100644 index 0000000..e6be490 --- /dev/null +++ b/www/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "paths": { + "@/*": ["./*"], + "collections/*": ["./.source/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} From fbce16e5776207232b2e9b76e715f5d3f19f547c Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 14:39:31 +0000 Subject: [PATCH 03/29] test(config): exclude www/ from root vitest run Prevents future test files under www/ (the Fumadocs docs site) from being collected by the library's root test suite. Mirrors the existing demo/** exclusion. --- vitest.config.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vitest.config.ts b/vitest.config.ts index 6bfc2ee..2e319e5 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,9 +5,10 @@ export default defineConfig({ environment: 'jsdom', globals: true, setupFiles: ['./tests/setup.ts'], - // The demo is a standalone app with its own deps and its own `npm test`. - // Keep it out of the library's test run (its imports resolve only inside - // demo/node_modules, which the library CI never installs). - exclude: [...configDefaults.exclude, 'demo/**'], + // The demo and www (Fumadocs docs site) are standalone apps with their own + // deps and their own `npm test`/build. Keep them out of the library's test + // run (their imports resolve only inside their own node_modules, which the + // library CI never installs). + exclude: [...configDefaults.exclude, 'demo/**', 'www/**'], }, }) From cf960240d1c6513de5f86b1566a82cfb7d20eea2 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 14:39:35 +0000 Subject: [PATCH 04/29] chore(docs): anchor turbopack workspace root to www/ Sets turbopack.root in www/next.config.mjs so Next.js doesn't infer the workspace root from the repo root (both package-lock.json and www/package-lock.json exist). Silences the workspace-root warning during next dev/build. --- www/next.config.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/next.config.mjs b/www/next.config.mjs index 457dcf2..9a61aee 100644 --- a/www/next.config.mjs +++ b/www/next.config.mjs @@ -1,3 +1,4 @@ +import { fileURLToPath } from 'node:url'; import { createMDX } from 'fumadocs-mdx/next'; const withMDX = createMDX(); @@ -5,6 +6,9 @@ const withMDX = createMDX(); /** @type {import('next').NextConfig} */ const config = { reactStrictMode: true, + turbopack: { + root: fileURLToPath(new URL('.', import.meta.url)), + }, }; export default withMDX(config); From f2b73ebf9117f48e4f9e7cc30914d6db44e0f105 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 16:57:51 +0000 Subject: [PATCH 05/29] feat(docs): add tablecraft and TanStack deps for live example harness --- www/package-lock.json | 145 +++++++++++++++++++++++++++++++++++++++--- www/package.json | 7 +- 2 files changed, 143 insertions(+), 9 deletions(-) diff --git a/www/package-lock.json b/www/package-lock.json index 741b15d..0ff2e60 100644 --- a/www/package-lock.json +++ b/www/package-lock.json @@ -8,6 +8,10 @@ "name": "tablecraft-docs", "version": "0.0.8", "dependencies": { + "@marvinackerman/tablecraft": "^2.6.0", + "@tanstack/react-query": "^5.101.4", + "@tanstack/react-table": "^8.21.3", + "@tanstack/react-virtual": "^3.14.8", "cnfast": "^0.0.8", "fumadocs-core": "^16.12.1", "fumadocs-mdx": "^15.2.0", @@ -15,7 +19,8 @@ "lucide-react": "^1.25.0", "next": "16.2.11", "react": "^19.2.8", - "react-dom": "^19.2.8" + "react-dom": "^19.2.8", + "zod": "^3.25.76" }, "devDependencies": { "@tailwindcss/postcss": "^4.3.3", @@ -1050,6 +1055,35 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@marvinackerman/tablecraft": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@marvinackerman/tablecraft/-/tablecraft-2.6.0.tgz", + "integrity": "sha512-Uu/wgRwNxhvXr8RuL527M55VrzW5QBpAQmuFFotE7VLVqnU0Y7IV27GaCd08MyRSSzLOhFgn5scF9FJF/ZTAyQ==", + "license": "MIT", + "peerDependencies": { + "@tanstack/react-table": ">=8", + "@tanstack/react-virtual": ">=3", + "react": ">=18", + "zod": ">=3.23.0" + }, + "peerDependenciesMeta": { + "@tanstack/react-query": { + "optional": true + }, + "@tanstack/react-virtual": { + "optional": true + }, + "@testing-library/react": { + "optional": true + }, + "match-sorter": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/@mdx-js/mdx": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", @@ -2355,6 +2389,92 @@ "tailwindcss": "4.3.3" } }, + "node_modules/@tanstack/query-core": { + "version": "5.101.4", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.4.tgz", + "integrity": "sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.101.4", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.4.tgz", + "integrity": "sha512-yRg2pfOCxIs4ZJW3XYYHU/WgtD04FHSnfHlpRT7h7pR77hwkdRG4wxbKe4aq6P0RvXUTBSQpQeadS1SUYUe+KA==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.101.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.14.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.8.tgz", + "integrity": "sha512-O39GJQpAYEJcIu3uN1//YtmhjSEOyw75vg9CKCatBDPiD5hKtZQoJHfferyrB/LdOD3UWaoMLWtdEjarwIwdDw==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.6", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.6.tgz", + "integrity": "sha512-h0/Ebo18CkOrChlQIhNtQkM5ySUnh/GumQ/D1st3hG2HWUPEF+ILUc2k29UtivCi/9G7w7G3/f7Xyd5cCFbKBw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -2423,7 +2543,7 @@ "version": "19.2.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -2433,7 +2553,7 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -2804,7 +2924,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/debug": { @@ -3316,6 +3436,15 @@ } } }, + "node_modules/fumadocs-mdx/node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/fumadocs-ui": { "version": "16.12.1", "resolved": "https://registry.npmjs.org/fumadocs-ui/-/fumadocs-ui-16.12.1.tgz", @@ -5751,7 +5880,7 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/tapable": { @@ -6103,9 +6232,9 @@ "license": "MIT" }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/www/package.json b/www/package.json index fd23050..dabf9a7 100644 --- a/www/package.json +++ b/www/package.json @@ -9,6 +9,10 @@ "types:check": "fumadocs-mdx && next typegen && tsc --noEmit" }, "dependencies": { + "@marvinackerman/tablecraft": "^2.6.0", + "@tanstack/react-query": "^5.101.4", + "@tanstack/react-table": "^8.21.3", + "@tanstack/react-virtual": "^3.14.8", "cnfast": "^0.0.8", "fumadocs-core": "^16.12.1", "fumadocs-mdx": "^15.2.0", @@ -16,7 +20,8 @@ "lucide-react": "^1.25.0", "next": "16.2.11", "react": "^19.2.8", - "react-dom": "^19.2.8" + "react-dom": "^19.2.8", + "zod": "^3.25.76" }, "devDependencies": { "@tailwindcss/postcss": "^4.3.3", From 1992a38c5caa2b059b705d49c87abc58fa2a2b76 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 16:57:58 +0000 Subject: [PATCH 06/29] feat(docs): add BasicTableExample component and sample user data --- www/components/examples/BasicTableExample.tsx | 43 +++++++++++++++++++ www/components/examples/sample-data.ts | 15 +++++++ 2 files changed, 58 insertions(+) create mode 100644 www/components/examples/BasicTableExample.tsx create mode 100644 www/components/examples/sample-data.ts diff --git a/www/components/examples/BasicTableExample.tsx b/www/components/examples/BasicTableExample.tsx new file mode 100644 index 0000000..82cc897 --- /dev/null +++ b/www/components/examples/BasicTableExample.tsx @@ -0,0 +1,43 @@ +'use client' +import { useTable, createColumns } from '@marvinackerman/tablecraft' +import { flexRender } from '@tanstack/react-table' +import { sampleUsers, type User } from './sample-data' + +const columns = createColumns([ + { accessorKey: 'name', header: 'Name' }, + { accessorKey: 'email', header: 'Email' }, + { accessorKey: 'role', header: 'Role' }, + { accessorKey: 'age', header: 'Age' }, +]) + +export default function BasicTableExample() { + const { table } = useTable({ data: sampleUsers, columns }) + return ( +
+ + + {table.getHeaderGroups().map((hg) => ( + + {hg.headers.map((h) => ( + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ {flexRender(h.column.columnDef.header, h.getContext())} +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+
+ ) +} diff --git a/www/components/examples/sample-data.ts b/www/components/examples/sample-data.ts new file mode 100644 index 0000000..856d8a6 --- /dev/null +++ b/www/components/examples/sample-data.ts @@ -0,0 +1,15 @@ +export type User = { + id: number + name: string + email: string + role: string + age: number +} + +export const sampleUsers: User[] = [ + { id: 1, name: 'Ada Lovelace', email: 'ada@example.com', role: 'Admin', age: 36 }, + { id: 2, name: 'Alan Turing', email: 'alan@example.com', role: 'Engineer', age: 41 }, + { id: 3, name: 'Grace Hopper', email: 'grace@example.com', role: 'Engineer', age: 45 }, + { id: 4, name: 'Katherine Johnson', email: 'katherine@example.com', role: 'Analyst', age: 39 }, + { id: 5, name: 'Edsger Dijkstra', email: 'edsger@example.com', role: 'Admin', age: 52 }, +] From 76846c94114377367f5ef5df12a8df69057aa3fd Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 16:58:03 +0000 Subject: [PATCH 07/29] feat(docs): embed live BasicTableExample in smoke docs page --- www/content/docs/index.mdx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/www/content/docs/index.mdx b/www/content/docs/index.mdx index 1ede18e..5c41d18 100644 --- a/www/content/docs/index.mdx +++ b/www/content/docs/index.mdx @@ -1,13 +1,12 @@ --- -title: Hello World -description: Your first document +title: tablecraft +description: A headless, type-safe table toolkit built on TanStack Table --- -Welcome to the docs! You can start writing documents in `/content/docs`. +import BasicTableExample from '@/components/examples/BasicTableExample' -## What is Next? +# tablecraft - - - - +A live tablecraft table, rendered right here in the docs: + + From 670bf36b9e3a06ab980354d03a37066766874971 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:15:19 +0000 Subject: [PATCH 08/29] style(docs): apply Terminal Aurora theme and fonts --- www/app/global.css | 46 ++++++++++++++++++++++++++++++++++++++++++++++ www/app/layout.tsx | 21 ++++++++++++++++++--- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/www/app/global.css b/www/app/global.css index f86f3c9..7498c87 100644 --- a/www/app/global.css +++ b/www/app/global.css @@ -2,6 +2,52 @@ @import 'fumadocs-ui/css/neutral.css'; @import 'fumadocs-ui/css/preset.css'; +/* Terminal Aurora — maps the demo's dark theme onto Fumadocs' --color-fd-* tokens. */ +@theme inline { + --font-sans: var(--font-sans); + --font-mono: var(--font-mono); + --font-display: var(--font-display); +} + +.dark { + --color-fd-background: #0a0a0b; + --color-fd-foreground: #ededf2; + --color-fd-muted: #131317; + --color-fd-muted-foreground: #8a8a96; + --color-fd-popover: #1a1a20; + --color-fd-popover-foreground: #ededf2; + --color-fd-card: #131317; + --color-fd-card-foreground: #ededf2; + --color-fd-border: #262630; + --color-fd-primary: #7c5cff; + --color-fd-primary-foreground: #ededf2; + --color-fd-secondary: #1a1a20; + --color-fd-secondary-foreground: #ededf2; + --color-fd-accent: #34e5db; + --color-fd-accent-foreground: #0a0a0b; + --color-fd-ring: #b3a4ff; +} + +body { + font-family: var(--font-sans), sans-serif; +} + +code, +pre, +kbd, +samp { + font-family: var(--font-mono), monospace; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-display), sans-serif; +} + html { scrollbar-gutter: stable; } diff --git a/www/app/layout.tsx b/www/app/layout.tsx index 22fdca3..aa5c115 100644 --- a/www/app/layout.tsx +++ b/www/app/layout.tsx @@ -1,14 +1,29 @@ import { RootProvider } from 'fumadocs-ui/provider/next'; import './global.css'; -import { Inter } from 'next/font/google'; +import { Manrope, JetBrains_Mono, Bricolage_Grotesque } from 'next/font/google'; -const inter = Inter({ +const sans = Manrope({ subsets: ['latin'], + variable: '--font-sans', +}); + +const mono = JetBrains_Mono({ + subsets: ['latin'], + variable: '--font-mono', +}); + +const display = Bricolage_Grotesque({ + subsets: ['latin'], + variable: '--font-display', }); export default function Layout({ children }: LayoutProps<'/'>) { return ( - + {children} From 864261c234156ccf4a4e51a34e3f4f072ebed121 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:22:34 +0000 Subject: [PATCH 09/29] style(docs): use subtle elevated hover accent instead of cyan --- www/app/global.css | 4 ++-- www/app/layout.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/www/app/global.css b/www/app/global.css index 7498c87..96bf1c8 100644 --- a/www/app/global.css +++ b/www/app/global.css @@ -23,8 +23,8 @@ --color-fd-primary-foreground: #ededf2; --color-fd-secondary: #1a1a20; --color-fd-secondary-foreground: #ededf2; - --color-fd-accent: #34e5db; - --color-fd-accent-foreground: #0a0a0b; + --color-fd-accent: #1a1a20; + --color-fd-accent-foreground: #ededf2; --color-fd-ring: #b3a4ff; } diff --git a/www/app/layout.tsx b/www/app/layout.tsx index aa5c115..23e9e9a 100644 --- a/www/app/layout.tsx +++ b/www/app/layout.tsx @@ -21,7 +21,7 @@ export default function Layout({ children }: LayoutProps<'/'>) { return ( From 671733b594669fdac07f1af79a4dcf5d6beada8b Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:29:05 +0000 Subject: [PATCH 10/29] docs(www): write Introduction page with code-first example --- www/content/docs/index.mdx | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/www/content/docs/index.mdx b/www/content/docs/index.mdx index 5c41d18..d1c66dc 100644 --- a/www/content/docs/index.mdx +++ b/www/content/docs/index.mdx @@ -1,12 +1,50 @@ --- -title: tablecraft -description: A headless, type-safe table toolkit built on TanStack Table +title: Introduction +description: A TypeScript-first, headless wrapper around TanStack Table that eliminates boilerplate without taking away control. --- import BasicTableExample from '@/components/examples/BasicTableExample' # tablecraft -A live tablecraft table, rendered right here in the docs: +tablecraft is a TypeScript-first, headless, batteries-included wrapper around +[TanStack Table](https://tanstack.com/table). TanStack Table is intentionally +unopinionated about markup and state — that's its strength, but it means every +project re-writes the same 80–150 lines of `useState` and `useMemo` wiring for +sorting, pagination, and filters. tablecraft collapses that boilerplate into a +single hook call while leaving the full TanStack Table instance available as +an escape hatch. There's no bundled CSS and no component library — you own +every element of markup, so tablecraft never fights your design system. + +## Mental model + +Call `useTable` with your data and column definitions. It wires up the +TanStack Table row model and hands back everything you need to render: the +`table` instance itself (for `getHeaderGroups()`, `getRowModel()`, and +`flexRender`), plus a small set of feature objects — `pagination`, `sorting`, +`globalFilter`, and more — each scoped to the feature it controls. You render +the `` markup yourself; tablecraft only supplies the state and the +handlers behind it. + +Here's the setup behind the live example below: + +```tsx +import { useTable, createColumns } from '@marvinackerman/tablecraft' +import { flexRender } from '@tanstack/react-table' + +const columns = createColumns([ + { accessorKey: 'name', header: 'Name' }, + { accessorKey: 'email', header: 'Email' }, + { accessorKey: 'role', header: 'Role' }, + { accessorKey: 'age', header: 'Age' }, +]) + +function UsersTable({ users }: { users: User[] }) { + const { table } = useTable({ data: users, columns }) + // render table.getHeaderGroups() / table.getRowModel() with flexRender +} +``` + +And the live result, rendered right here in the docs: From 46e5c585020221a3106428059ba6ea20d12f1edd Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:29:06 +0000 Subject: [PATCH 11/29] docs(www): add Installation page with peer deps and entry points --- www/content/docs/installation.mdx | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 www/content/docs/installation.mdx diff --git a/www/content/docs/installation.mdx b/www/content/docs/installation.mdx new file mode 100644 index 0000000..815420c --- /dev/null +++ b/www/content/docs/installation.mdx @@ -0,0 +1,48 @@ +--- +title: Installation +--- + +## Install + +```bash +npm install @marvinackerman/tablecraft +``` + +## Required peer dependencies + +tablecraft's core entry (`useTable`, `createColumns`, and friends) is built on +top of TanStack Table and TanStack Virtual, and needs React itself. Install +these alongside it: + +```bash +npm install @tanstack/react-table@">=8" react@">=18" @tanstack/react-virtual@">=3" +``` + +| Package | Version floor | Why | +|---|---|---| +| `@tanstack/react-table` | `>=8` | tablecraft wraps its row model, column, and state APIs | +| `react` | `>=18` | hooks-based, requires a React 18+ runtime | +| `@tanstack/react-virtual` | `>=3` | powers `useVirtualRows` for windowed row rendering | + +## Optional peer dependencies + +These are only needed if you use the feature they back — install them as you +reach for that feature, not up front: + +| Package | Needed for | +|---|---| +| `zod` | The `@marvinackerman/tablecraft/zod` entry (`columnsFromZod`, `zodValidator`) — derive columns and row-edit validation from a single Zod schema. Works with Zod 3 and 4. | +| `@tanstack/react-query` | `useQueryTable` and `useInfiniteTable` — server-driven and infinite-scroll tables backed by TanStack Query. | +| `match-sorter` | Fuzzy search (`fuzzy: true` on `useTable`). Loaded via `require()`, so this only applies in CJS/Node bundlers — in ESM-only bundlers (e.g. Vite), pass your own filter function instead and skip this dependency entirely. | + +## Entry points + +tablecraft publishes four entry points, so you only pull in the code paths +you actually use: + +| Entry | Exports | +|---|---| +| `@marvinackerman/tablecraft` | The core hooks — `useTable`, `createColumns`, `useQueryTable`, `useInfiniteTable`, `useInfiniteScroll`, `useVirtualRows`, and friends. | +| `@marvinackerman/tablecraft/zod` | `columnsFromZod`, `zodValidator` — requires the optional `zod` peer. | +| `@marvinackerman/tablecraft/devtools` | `TablecraftDevtools` — inspect table state during development. | +| `@marvinackerman/tablecraft/testing` | Test helpers, built against `@testing-library/react`. | From e99a66c7d8a140b0d4764b74ef1aea785b8058ad Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:29:14 +0000 Subject: [PATCH 12/29] docs(www): set getting-started nav order --- www/content/docs/meta.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 www/content/docs/meta.json diff --git a/www/content/docs/meta.json b/www/content/docs/meta.json new file mode 100644 index 0000000..51e889c --- /dev/null +++ b/www/content/docs/meta.json @@ -0,0 +1,3 @@ +{ + "pages": ["index", "installation", "guides", "api"] +} From 48e98fa3389ae943886de5e079c055838df302dd Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:29:15 +0000 Subject: [PATCH 13/29] docs(www): remove template placeholder page --- www/content/docs/test.mdx | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 www/content/docs/test.mdx diff --git a/www/content/docs/test.mdx b/www/content/docs/test.mdx deleted file mode 100644 index f475f4a..0000000 --- a/www/content/docs/test.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Components -description: Components ---- - -## Code Block - -```js -console.log('Hello World'); -``` - -## Cards - - - - - From 0ac3c551e83fbec1a69959a7a1a72eec8df4602a Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 17:33:42 +0000 Subject: [PATCH 14/29] docs(www): add zod version floor to installation --- www/content/docs/installation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/content/docs/installation.mdx b/www/content/docs/installation.mdx index 815420c..c100513 100644 --- a/www/content/docs/installation.mdx +++ b/www/content/docs/installation.mdx @@ -31,7 +31,7 @@ reach for that feature, not up front: | Package | Needed for | |---|---| -| `zod` | The `@marvinackerman/tablecraft/zod` entry (`columnsFromZod`, `zodValidator`) — derive columns and row-edit validation from a single Zod schema. Works with Zod 3 and 4. | +| `zod` `>=3.23.0` | The `@marvinackerman/tablecraft/zod` entry (`columnsFromZod`, `zodValidator`) — derive columns and row-edit validation from a single Zod schema. Works with Zod 3 and 4. | | `@tanstack/react-query` | `useQueryTable` and `useInfiniteTable` — server-driven and infinite-scroll tables backed by TanStack Query. | | `match-sorter` | Fuzzy search (`fuzzy: true` on `useTable`). Loaded via `require()`, so this only applies in CJS/Node bundlers — in ESM-only bundlers (e.g. Vite), pass your own filter function instead and skip this dependency entirely. | From 9da26d359582fcd3aca67969bffccb10d7a7eb5f Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:18:11 +0000 Subject: [PATCH 15/29] docs(www): add API reference pages for core table hooks Cover useTable, useServerTable, useQueryTable, useInfiniteTable, and useInfiniteScroll, migrated from README and reconciled against the installed 2.6.0 .d.ts types. --- www/content/docs/api/use-infinite-scroll.mdx | 57 ++++++ www/content/docs/api/use-infinite-table.mdx | 110 +++++++++++ www/content/docs/api/use-query-table.mdx | 99 ++++++++++ www/content/docs/api/use-server-table.mdx | 54 ++++++ www/content/docs/api/use-table.mdx | 192 +++++++++++++++++++ 5 files changed, 512 insertions(+) create mode 100644 www/content/docs/api/use-infinite-scroll.mdx create mode 100644 www/content/docs/api/use-infinite-table.mdx create mode 100644 www/content/docs/api/use-query-table.mdx create mode 100644 www/content/docs/api/use-server-table.mdx create mode 100644 www/content/docs/api/use-table.mdx diff --git a/www/content/docs/api/use-infinite-scroll.mdx b/www/content/docs/api/use-infinite-scroll.mdx new file mode 100644 index 0000000..c960a24 --- /dev/null +++ b/www/content/docs/api/use-infinite-scroll.mdx @@ -0,0 +1,57 @@ +--- +title: useInfiniteScroll +description: Automatic scroll wiring for useInfiniteTable — fires loadMore when a sentinel element enters the viewport. +--- + +Pairs with [`useInfiniteTable`](/docs/api/use-infinite-table) to trigger +`loadMore` automatically when a sentinel element enters the viewport. Handles +observer cleanup on unmount, reconnect when options change, and stale-closure +prevention internally. + +## Signature + +```ts +function useInfiniteScroll( + loadMore: () => void, + options?: UseInfiniteScrollOptions +): (node: Element | null) => void +``` + +Returns a ref callback to attach to a sentinel element at the bottom of your +list. + +## Options + +| Option | Type | Default | Description | +|---|---|---|---| +| `enabled` | `boolean` | `true` | Gate the observer. Pass `hasNextPage && !isFetchingNextPage` to prevent double-firing | +| `rootMargin` | `string` | `'0px'` | IntersectionObserver `rootMargin` — e.g. `'200px'` to load ahead of scroll position | + +## Usage + +```tsx +import { useInfiniteScroll } from '@marvinackerman/tablecraft' + +const { table, loadMore, hasNextPage, isFetchingNextPage } = useInfiniteTable({ /* ... */ }) + +const sentinelRef = useInfiniteScroll(loadMore, { + enabled: hasNextPage && !isFetchingNextPage, // never double-fires +}) + +return ( + <> +
+ + {table.getRowModel().rows.map((row) => ( + {/* ... */} + ))} + +
+ + {/* Place sentinel below the last row — fires loadMore as it scrolls into view */} +
+ + {isFetchingNextPage &&

Loading more…

} + +) +``` diff --git a/www/content/docs/api/use-infinite-table.mdx b/www/content/docs/api/use-infinite-table.mdx new file mode 100644 index 0000000..5ac2362 --- /dev/null +++ b/www/content/docs/api/use-infinite-table.mdx @@ -0,0 +1,110 @@ +--- +title: useInfiniteTable +description: Cursor-based infinite scroll powered by TanStack Query's useInfiniteQuery — accumulated pages, no pagination controls. +--- + +Cursor-based infinite scroll powered by TanStack Query's `useInfiniteQuery`. +Pages accumulate into a flat list — no pagination controls needed. When sort +or filter state changes, accumulated pages automatically reset to page 1 via +query key composition. + +Requires `@tanstack/react-query`: + +```bash +npm i @tanstack/react-query +``` + +## Signature + +```ts +function useInfiniteTable( + options: UseInfiniteTableOptions +): UseInfiniteTableReturn +``` + +## Options + +| Option | Type | Default | Description | +|---|---|---|---| +| `queryKey` | `unknown[]` | required | TanStack Query cache key | +| `queryFn` | `(context) => Promise<{ data: TData[], nextCursor?: TCursor }>` | required | Fetcher — return `nextCursor: undefined` to signal the last page | +| `columns` | `ColumnDef[]` | required | Column definitions | +| `initialPageParam` | `TCursor` | `0` | First value passed as `pageParam` | +| `sorting` | `SortingOptions \| boolean` | `true` | Enable sorting | +| `globalFilter` | `boolean` | `true` | Enable global search | +| `columnFilters` | `boolean` | `true` | Enable column filters | +| `rowSelection` | `RowSelectionOptions \| boolean` | `false` | Enable row selection | +| `columnVisibility` | `ColumnVisibilityOptions \| boolean` | `false` | Enable column visibility | +| `grouping` | `GroupingOptions \| boolean` | `false` | Enable row grouping | +| `columnPinning` | `ColumnPinningOptions \| boolean` | `false` | Enable column pinning | +| `staleTime` | `number` | — | TanStack Query `staleTime` | +| `gcTime` | `number` | — | TanStack Query `gcTime` | +| `enabled` | `boolean` | — | TanStack Query `enabled` | + +The `queryFn` context (`InfiniteTableFnContext`) receives: + +| Property | Type | +|---|---| +| `pageParam` | `TCursor` | +| `sorting` | `SortingState` | +| `columnFilters` | `ColumnFiltersState` | +| `globalFilter` | `string` | +| `grouping` | `GroupingState` | + +## Return + +| Property | Type | Description | +|---|---|---| +| `table` | `Table` | Full TanStack Table instance with all accumulated rows | +| `loadMore` | `() => void` | Fetch the next page | +| `hasNextPage` | `boolean` | `true` when `nextCursor` was returned from the last page | +| `isFetchingNextPage` | `boolean` | `true` while a `loadMore` call is in-flight | +| `isLoading` | `boolean` | `true` on the very first fetch | +| `isError` | `boolean` | `true` if the query threw | +| `error` | `Error \| null` | The thrown error, if any | +| `refetch` | `() => void` | Re-run the query from the beginning | +| `sorting` | `SortingReturn` | Same shape as `useTable` | +| `globalFilter` | `GlobalFilterReturn` | Same shape as `useTable` | +| `columnFilters` | `ColumnFiltersReturn` | Same shape as `useTable` | +| `rowSelection` | `RowSelectionReturn` | Opt-in — pass `rowSelection: true` | +| `columnVisibility` | `ColumnVisibilityReturn` | Opt-in — pass `columnVisibility: true` | +| `grouping` | `GroupingReturn` | Opt-in — pass `grouping: true` | +| `columnPinning` | `ColumnPinningReturn` | Opt-in — pass `columnPinning: true` | +| `emptyState` | `EmptyStateReturn` | Same shape as `useTable` | + +## Usage + +```tsx +import { useInfiniteTable } from '@marvinackerman/tablecraft' + +const { table, loadMore, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteTable({ + queryKey: ['users'], + initialPageParam: null as string | null, // TCursor inferred as string | null + queryFn: async ({ pageParam, sorting, globalFilter }) => { + const res = await api.getUsers({ + cursor: pageParam, // pageParam: string | null — fully typed + sort: sorting, + search: globalFilter, + }) + return { + data: res.data, + nextCursor: res.nextCursor, // string | null | undefined — typed + } + }, + columns, + sorting: true, + globalFilter: true, +}) + + +``` + +All rows across every loaded page are available in +`table.getRowModel().rows` as a single flat list — no page tracking needed. + +## Notes + +- Pair with [`useInfiniteScroll`](/docs/api/use-infinite-scroll) to trigger `loadMore` automatically instead of wiring a button. +- For paginated (non-accumulating) server tables, use [`useQueryTable`](/docs/api/use-query-table) instead. diff --git a/www/content/docs/api/use-query-table.mdx b/www/content/docs/api/use-query-table.mdx new file mode 100644 index 0000000..22623ea --- /dev/null +++ b/www/content/docs/api/use-query-table.mdx @@ -0,0 +1,99 @@ +--- +title: useQueryTable +description: Combines server-side tables with TanStack Query — automatic refetching on sort, page, or filter changes. +--- + +Combines the `useServerTable` model with TanStack Query. Automatically +re-fetches when sort, page, or filter state changes. + +Requires `@tanstack/react-query`: + +```bash +npm i @tanstack/react-query +``` + +## Signature + +```ts +function useQueryTable( + options: UseQueryTableOptions +): UseQueryTableReturn +``` + +## Options + +| Option | Type | Default | Description | +|---|---|---|---| +| `queryKey` | `unknown[]` | required | TanStack Query cache key | +| `queryFn` | `(context) => Promise<{ data: TData[], rowCount: number }>` | required | Fetcher | +| `columns` | `ColumnDef[]` | required | Column definitions | +| `pagination` | `PaginationOptions \| boolean` | — | Same shape as `useTable` | +| `sorting` | `SortingOptions \| boolean` | — | Same shape as `useTable` | +| `globalFilter` | `boolean` | — | Enable global search | +| `columnFilters` | `boolean` | — | Enable column filters | +| `rowSelection` | `RowSelectionOptions \| boolean` | — | Opt-in row selection | +| `columnVisibility` | `ColumnVisibilityOptions \| boolean` | — | Opt-in column visibility | +| `rowExpansion` | `RowExpansionOptions \| boolean` | — | Opt-in row expansion | +| `grouping` | `GroupingOptions \| boolean` | — | Opt-in row grouping | +| `columnPinning` | `ColumnPinningOptions \| boolean` | — | Opt-in column pinning | +| `fuzzy` | `boolean \| FilterFn` | — | Same caveat as `useTable` — `true` requires CJS/Node | +| `persist` | `PersistStorage \| false` | — | Same as `useTable` | +| `persistKey` | `string` | — | Storage key | +| `persistOptions` | `PersistOptions` | — | Which slices to persist | +| `syncUrl` | `boolean \| URLSyncOptions` | — | Same as `useTable` | +| `staleTime` | `number` | — | TanStack Query `staleTime` | +| `gcTime` | `number` | — | TanStack Query `gcTime` | +| `enabled` | `boolean` | — | TanStack Query `enabled` | +| `refetchOnWindowFocus` | `boolean` | — | TanStack Query pass-through | +| `refetchOnMount` | `boolean \| 'always'` | — | TanStack Query pass-through | +| `refetchOnReconnect` | `boolean \| 'always'` | — | TanStack Query pass-through | +| `refetchInterval` | `number \| false` | — | TanStack Query pass-through | +| `retry` | `boolean \| number` | — | TanStack Query pass-through | +| `queryOptions` | `Record` | — | Pass-through for any TanStack Query option not surfaced above | + +The `queryFn` context (`QueryTableFnContext`) receives: + +| Property | Type | +|---|---| +| `pagination` | `{ pageIndex: number, pageSize: number }` | +| `sorting` | `SortingState` | +| `columnFilters` | `ColumnFiltersState` | +| `globalFilter` | `string` | +| `grouping` | `GroupingState` | + +## Return + +`UseQueryTableReturn` extends [`UseTableReturn`](/docs/api/use-table) +and adds: + +| Property | Type | Description | +|---|---|---| +| `query` | `QueryState` | Raw query result — `data`, `isLoading`, `isError`, `isFetching`, `isPlaceholderData`, `error`, `refetch`, `status`, `fetchStatus` | + +## Usage + +```tsx +import { useQueryTable } from '@marvinackerman/tablecraft' + +const { table, pagination, sorting, query } = useQueryTable({ + queryKey: ['users'], + queryFn: async ({ pagination, sorting, globalFilter, columnFilters }) => { + const res = await api.getUsers({ + page: pagination.pageIndex, + pageSize: pagination.pageSize, + sort: sorting, + search: globalFilter, + }) + return { data: res.data, rowCount: res.total } + }, + columns, + pagination: { pageSize: 20 }, + sorting: true, + globalFilter: true, +}) +``` + +## Notes + +- `query` is the raw TanStack Query result — use `query.isLoading` / `query.isError` for loading and error UI. +- For cursor-based infinite lists instead of paginated pages, use [`useInfiniteTable`](/docs/api/use-infinite-table). diff --git a/www/content/docs/api/use-server-table.mdx b/www/content/docs/api/use-server-table.mdx new file mode 100644 index 0000000..16d6396 --- /dev/null +++ b/www/content/docs/api/use-server-table.mdx @@ -0,0 +1,54 @@ +--- +title: useServerTable +description: The server-driven variant of useTable — forces manual pagination and sorting for backend-owned data. +--- + +Forces `manualPagination` and `manualSorting` to `true`. Use this when your +backend handles sorting, pagination, and filtering. + +## Signature + +```ts +function useServerTable( + options: UseServerTableOptions +): UseTableReturn +``` + +`UseServerTableOptions` is [`UseTableOptions`](/docs/api/use-table) +minus `manualPagination` / `manualSorting`, with `rowCount` required instead of optional: + +| Option | Type | Description | +|---|---|---| +| `rowCount` | `number` | Required — total rows in the full dataset | +| `onPaginationChange` | `OnChangeFn` | Called when the user changes page/page size | +| `onSortingChange` | `OnChangeFn` | Called when the user changes sort | +| `onColumnFiltersChange` | `OnChangeFn` | Called when the user changes a column filter | +| ...rest | — | Every other [`useTable`](/docs/api/use-table) option | + +The return shape is identical to [`useTable`](/docs/api/use-table)'s +`UseTableReturn`. + +## Usage + +```tsx +import { useServerTable } from '@marvinackerman/tablecraft' + +const { table, pagination, sorting } = useServerTable({ + data: serverData, // current page from your API + columns, + rowCount: totalRows, // required — total rows in the dataset + pagination: { pageSize: 20 }, + onPaginationChange: (updater) => { + const next = typeof updater === 'function' ? updater(currentState) : updater + refetch({ page: next.pageIndex, pageSize: next.pageSize }) + }, + onSortingChange: (updater) => { + const next = typeof updater === 'function' ? updater(currentSort) : updater + refetch({ sort: next }) + }, +}) +``` + +## Notes + +- If you're fetching with TanStack Query, prefer [`useQueryTable`](/docs/api/use-query-table) — it wraps this same manual-mode behavior with query-key-driven refetching. diff --git a/www/content/docs/api/use-table.mdx b/www/content/docs/api/use-table.mdx new file mode 100644 index 0000000..efe1ef4 --- /dev/null +++ b/www/content/docs/api/use-table.mdx @@ -0,0 +1,192 @@ +--- +title: useTable +description: The primary hook — covers pagination, sorting, filtering, selection, expansion, grouping, pinning, persistence, and URL sync in one call. +--- + +The single hook that covers most use cases. Every option is optional; the +returned `table` is a full TanStack `Table` instance. + +## Signature + +```ts +function useTable( + options: UseTableOptions +): UseTableReturn +``` + +## Options + +| Option | Type | Description | +|---|---|---| +| `data` | `TData[]` | Row data (required) | +| `columns` | `ColumnDef[]` | Column definitions (required) | +| `pagination` | `PaginationOptions \| boolean` | `{ pageSize?, pageIndex? }`, or `true` (defaults), or `false` (disabled) | +| `manualPagination` | `boolean` | Server-driven pagination — pair with `rowCount` | +| `rowCount` | `number` | Total row count, used with `manualPagination` | +| `onPaginationChange` | `OnChangeFn` | Custom pagination change handler | +| `sorting` | `SortingOptions \| boolean` | `{ defaultSort? }`, or `true`, or `false` | +| `manualSorting` | `boolean` | Server-driven sorting | +| `onSortingChange` | `OnChangeFn` | Custom sorting change handler | +| `globalFilter` | `boolean` | Enable global text filter | +| `onGlobalFilterChange` | `(value: string) => void` | Custom global filter handler | +| `columnFilters` | `boolean` | Enable per-column filters | +| `onColumnFiltersChange` | `OnChangeFn` | Custom column filter handler | +| `rowSelection` | `RowSelectionOptions \| boolean` | `true`, or `{ enableMultiRowSelection? }` | +| `columnVisibility` | `ColumnVisibilityOptions \| boolean` | `true`, or `{ defaultVisibility? }` | +| `rowExpansion` | `RowExpansionOptions \| boolean` | `true`, or `{ defaultExpanded?, allowMultiple?, paginateExpandedRows?, getSubRows? }` | +| `grouping` | `GroupingOptions \| boolean` | `true`, or `{ defaultGrouping?, manualGrouping?, groupedColumnMode? }` | +| `columnPinning` | `ColumnPinningOptions \| boolean` | `true`, or `{ defaultPinning? }` | +| `fuzzy` | `boolean \| FilterFn` | `true` loads `match-sorter` via `require()` — CJS/Node only. In ESM-only bundlers (Vite, browsers), pass a `FilterFn` directly instead. | +| `persist` | `'localStorage' \| 'sessionStorage' \| false` | Persist state across reloads — see [Persistence & URL sync](/docs/api/persistence-url) | +| `persistKey` | `string` | Storage key — required when `persist` is set | +| `persistOptions` | `PersistOptions` | Which state slices to persist | +| `syncUrl` | `boolean \| URLSyncOptions` | Sync state to the URL — see [Persistence & URL sync](/docs/api/persistence-url) | + +## Usage + +```tsx +import { useTable } from '@marvinackerman/tablecraft' + +const { + table, // Full TanStack Table instance + pagination, + sorting, + globalFilter, + columnFilters, + rowSelection, + columnVisibility, + rowExpansion, + grouping, + columnPinning, + emptyState, +} = useTable({ + data, + columns, + pagination: { pageSize: 20 }, + sorting: { defaultSort: [{ id: 'name', desc: false }] }, + globalFilter: true, + columnFilters: true, + rowSelection: true, + columnVisibility: { defaultVisibility: { email: false } }, + rowExpansion: { getSubRows: (row) => row.children }, + grouping: { defaultGrouping: ['role'] }, + fuzzy: true, + persist: 'localStorage', + persistKey: 'my-table', + persistOptions: { sorting: true, pagination: true }, + syncUrl: true, +}) +``` + +## Return + +### `pagination` + +| Property | Type | Description | +|---|---|---| +| `pageIndex` | `number` | Current page (0-indexed) | +| `pageSize` | `number` | Rows per page | +| `pageCount` | `number` | Total pages | +| `canPreviousPage` | `boolean` | Can go back | +| `canNextPage` | `boolean` | Can go forward | +| `previousPage` | `() => void` | Go to previous page | +| `nextPage` | `() => void` | Go to next page | +| `setPageIndex` | `(index: number) => void` | Jump to page | +| `setPageSize` | `(size: number) => void` | Change page size | + +### `sorting` + +| Property | Type | Description | +|---|---|---| +| `sortingState` | `SortingState` | Current sort state | +| `setSorting` | `OnChangeFn` | Set sort state directly | +| `clearSorting` | `() => void` | Clear all sorting | + +### `globalFilter` + +| Property | Type | Description | +|---|---|---| +| `value` | `string` | Current search string | +| `setValue` | `(val: string) => void` | Set the search string | +| `clear` | `() => void` | Clear the search string | + +### `columnFilters` + +| Property | Type | Description | +|---|---|---| +| `state` | `ColumnFiltersState` | Current per-column filter values | +| `setFilter` | `(columnId, value) => void` | Set a single column's filter | +| `clearFilter` | `(columnId) => void` | Clear one column's filter | +| `clearAll` | `() => void` | Clear all column filters | + +### `rowSelection` + +| Property | Type | Description | +|---|---|---| +| `state` | `RowSelectionState` | Current selection map | +| `toggleRow` | `(rowId: string) => void` | Toggle a row | +| `toggleAll` | `() => void` | Select / deselect all | +| `clearSelection` | `() => void` | Clear all | +| `selectedRowIds` | `string[]` | IDs of selected rows | +| `selectedCount` | `number` | Number selected | +| `isSelected` | `(rowId: string) => boolean` | Check if selected | + +### `columnVisibility` + +| Property | Type | Description | +|---|---|---| +| `state` | `VisibilityState` | Current visibility map | +| `toggleColumn` | `(columnId: string) => void` | Toggle a column | +| `showColumn` | `(columnId: string) => void` | Show a column | +| `hideColumn` | `(columnId: string) => void` | Hide a column | +| `showAll` | `() => void` | Show every column | +| `hiddenColumns` | `string[]` | Currently hidden column IDs | + +### `rowExpansion` + +| Property | Type | Description | +|---|---|---| +| `state` | `ExpandedState` | Current expanded rows | +| `toggleRow` | `(rowId: string) => void` | Toggle expand | +| `expandRow` | `(rowId: string) => void` | Expand a row | +| `collapseRow` | `(rowId: string) => void` | Collapse a row | +| `clearExpansion` | `() => void` | Collapse all | +| `expandedRowIds` | `string[]` | IDs of expanded rows | +| `isExpanded` | `(rowId: string) => boolean` | Check if expanded | + +### `grouping` + +| Property | Type | Description | +|---|---|---| +| `state` | `GroupingState` | Current grouped columns | +| `toggleGrouping` | `(columnId: string) => void` | Toggle group by column | +| `setGrouping` | `(cols: GroupingState) => void` | Set grouping directly | +| `clearGrouping` | `() => void` | Remove all grouping | +| `isGrouped` | `(columnId: string) => boolean` | Check if grouped | +| `groupedColumns` | `string[]` | Currently grouped column IDs | + +### `columnPinning` + +| Property | Type | Description | +|---|---|---| +| `state` | `ColumnPinningState` | Raw TanStack pinning state | +| `pinLeft` | `(columnId: string) => void` | Pin column to left edge | +| `pinRight` | `(columnId: string) => void` | Pin column to right edge | +| `unpin` | `(columnId: string) => void` | Remove pin from column | +| `clearPinning` | `() => void` | Unpin all columns | +| `isPinned` | `(columnId: string) => 'left' \| 'right' \| false` | Query pin status | +| `leftColumns` | `string[]` | Currently left-pinned column IDs | +| `rightColumns` | `string[]` | Currently right-pinned column IDs | + +### `emptyState` + +| Property | Type | Description | +|---|---|---| +| `isEmpty` | `boolean` | `true` when data has 0 rows total | +| `isFilteredEmpty` | `boolean` | `true` when data exists but filters return 0 rows | + +## Notes + +- `position: sticky` for pinned columns is plain CSS — tablecraft only provides state and the pixel offsets (`column.getStart('left')`, `column.getAfter('right')`). No UI lock-in. +- `columnPinning` is also available on [`useQueryTable`](/docs/api/use-query-table) and [`useInfiniteTable`](/docs/api/use-infinite-table) with the identical option shape. +- See [Persistence & URL sync](/docs/api/persistence-url) for `persist*` / `syncUrl` details, and [State hooks](/docs/api/state-hooks) if you're composing `useReactTable` yourself instead of using `useTable`. From 9b0af9eea91cb1d78ea2e8a9465f896b71896604 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:18:25 +0000 Subject: [PATCH 16/29] docs(www): add API reference pages for state hooks and editing Cover the 9 granular state hooks (usePaginationState, useSortState, etc.) and the two editing hooks (useEditableRows, useMultiRowEditing). --- www/content/docs/api/editing.mdx | 176 ++++++++++++++++++++++++++ www/content/docs/api/state-hooks.mdx | 179 +++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 www/content/docs/api/editing.mdx create mode 100644 www/content/docs/api/state-hooks.mdx diff --git a/www/content/docs/api/editing.mdx b/www/content/docs/api/editing.mdx new file mode 100644 index 0000000..6f16418 --- /dev/null +++ b/www/content/docs/api/editing.mdx @@ -0,0 +1,176 @@ +--- +title: Editing +description: useEditableRows for single-row inline editing, and useMultiRowEditing for editing and saving multiple rows at once. +--- + +Both hooks are standalone opt-in hooks — no form library required. They work +with Zod, Yup, or plain validation via a shared error-map contract: +`onSave` returns `void` (or `undefined`) to commit, or a +`Partial>` of field errors to stay in edit mode. + +## `useEditableRows` + +Single-row inline editing. + +```ts +function useEditableRows( + table: Table, + options?: EditableOptions +): EditableReturn +``` + +**Options** + +| Option | Type | Description | +|---|---|---| +| `onSave` | `(rowId: string, draft: TData) => void \| Partial> \| Promise<...>` | Called on save. Return an error map to stay in edit mode, or nothing to commit. | + +**Return** + +| Property | Type | Description | +|---|---|---| +| `editingRowId` | `string \| null` | Which row is being edited | +| `draftData` | `Partial` | Current draft field values | +| `isDirty` | `boolean` | Whether any field has changed | +| `dirtyFields` | `(keyof TData)[]` | Which fields changed | +| `errors` | `Partial>` | Field-level validation errors | +| `isSaving` | `boolean` | `true` while `onSave` promise is in flight | +| `isEditing` | `(rowId: string) => boolean` | Check if a row is in edit mode | +| `startEditing` | `(rowId: string) => void` | Enter edit mode (snapshots original) | +| `setField` | `(field: K, value: TData[K]) => void` | Update a draft field | +| `saveEditing` | `() => Promise` | Run `onSave`, commit or show errors | +| `cancelEditing` | `() => void` | Discard changes, exit edit mode | + +**Usage** + +```tsx +import { useTable, useEditableRows } from '@marvinackerman/tablecraft' + +const { table } = useTable({ data, columns }) +const editable = useEditableRows(table, { + onSave: async (rowId, draft) => { + // Return an error map to show validation errors and stay in edit mode + if (!draft.name) return { name: 'Name is required' } + + // Or use any schema library + const result = schema.safeParse(draft) + if (!result.success) return formatErrors(result.error) + + // Return nothing (or undefined) to commit and exit edit mode + await api.updateUser(rowId, draft) + }, +}) + +// In your row render: +{table.getRowModel().rows.map((row) => ( + + {editable.isEditing(row.id) ? ( + <> + + editable.setField('name', e.target.value)} + /> + {editable.errors.name && {editable.errors.name}} + + + + + + + ) : ( + <> + {row.original.name} + + + + + )} + +))} +``` + +## `useMultiRowEditing` + +Edit, validate, and save multiple rows simultaneously — per-row save and bulk +save are both supported. + +```ts +function useMultiRowEditing( + table: Table, + options?: MultiRowEditingOptions +): MultiRowEditingReturn +``` + +**Options** + +| Option | Type | Description | +|---|---|---| +| `onSave` | `(rowId, draft) => void \| errors \| Promise<...>` | Per-row save callback. Return a non-empty errors object to stay in edit mode. | +| `onSaveAll` | `(rows: { rowId, draft }[]) => void \| Record \| Promise<...>` | Batch save callback. If omitted, `saveAll()` calls `onSave` for each dirty row in parallel. | + +**Return** + +| Property | Type | Description | +|---|---|---| +| `editingRowIds` | `string[]` | Rows currently in edit mode | +| `savingRows` | `string[]` | Rows mid per-row save | +| `isSavingAll` | `boolean` | `true` during `saveAll()` | +| `hasUnsavedChanges` | `boolean` | `true` if any row has unsaved changes | +| `startEditing(id)` | `fn` | Enter edit mode for a row (no-op if already editing) | +| `setField(id, field, value)` | `fn` | Update a draft field | +| `saveRow(id)` | `async fn` | Save one row via `onSave` | +| `cancelRow(id)` | `fn` | Discard draft and exit edit mode for one row | +| `saveAll()` | `async fn` | Save all dirty rows | +| `cancelAll()` | `fn` | Discard all drafts and exit edit mode | +| `isEditing(id)` | `fn → boolean` | Is this row in edit mode? | +| `isDirty(id)` | `fn → boolean` | Does this row have unsaved changes? | +| `dirtyFields(id)` | `fn → (keyof TData)[]` | Which fields have changed? | +| `getDraft(id)` | `fn → Partial` | Current draft for a row | +| `getErrors(id)` | `fn → Partial>` | Current field errors for a row | +| `isSavingRow(id)` | `fn → boolean` | Is this row currently being saved? | + +**Usage** + +```tsx +import { useTable, useMultiRowEditing } from '@marvinackerman/tablecraft' + +const { table } = useTable({ data, columns }) + +const { + editingRowIds, + startEditing, + setField, + getDraft, + getErrors, + saveRow, + cancelRow, + saveAll, + cancelAll, + isEditing, + isDirty, + hasUnsavedChanges, + isSavingAll, +} = useMultiRowEditing(table, { + onSave: async (rowId, draft) => { + const errors = await api.updateUser(draft) + if (errors) return errors // { name: 'Too long' } keeps row in edit mode + // return void / undefined → row exits edit mode + }, + onSaveAll: async (rows) => { + const result = await api.bulkUpdate(rows) + // Return Record — rows with errors stay in edit mode + return result.errors + }, +}) + +{hasUnsavedChanges && ( + +)} +``` + +## Notes + +- For a schema-driven validator that plugs straight into either hook's `onSave`, see [`zodValidator`](/docs/api/zod). diff --git a/www/content/docs/api/state-hooks.mdx b/www/content/docs/api/state-hooks.mdx new file mode 100644 index 0000000..8ec4974 --- /dev/null +++ b/www/content/docs/api/state-hooks.mdx @@ -0,0 +1,179 @@ +--- +title: State hooks +description: Granular, standalone state hooks for composing your own useReactTable call instead of using useTable. +--- + +For advanced setups where you compose your own `useReactTable` call directly, +each piece of [`useTable`](/docs/api/use-table)'s state is available as a +standalone hook. Each returns state plus setters compatible with TanStack +Table's `state` and `on*Change` props. + +```tsx +import { + usePaginationState, + useSortState, + useFilterState, + useColumnFilterState, + useRowSelectionState, + useColumnVisibilityState, + useColumnPinningState, + useRowExpansionState, + useGroupingState, +} from '@marvinackerman/tablecraft' + +const pagination = usePaginationState({ pageSize: 25 }) +const sorting = useSortState({ defaultSort: [{ id: 'createdAt', desc: true }] }) +const globalFilter = useFilterState() +const columnFilters = useColumnFilterState() +const rowSelection = useRowSelectionState() +const columnVisibility = useColumnVisibilityState({ defaultVisibility: { id: false } }) +const columnPinning = useColumnPinningState() +const rowExpansion = useRowExpansionState({ allowMultiple: false }) +const grouping = useGroupingState({ defaultGrouping: ['department'] }) +``` + +## `usePaginationState` + +```ts +function usePaginationState(options?: PaginationOptions): { + state: PaginationState + onPaginationChange: Dispatch> + setPageIndex: (index: number) => void + setPageSize: (size: number) => void + nextPage: () => void + previousPage: () => void +} +``` + +`PaginationOptions`: `{ pageSize?: number, pageIndex?: number }` + +## `useSortState` + +```ts +function useSortState(options?: SortingOptions): { + state: SortingState + onSortingChange: Dispatch> + clearSorting: () => void +} +``` + +`SortingOptions`: `{ defaultSort?: SortingState }` + +## `useFilterState` + +```ts +function useFilterState(defaultValue?: string): { + state: string + onGlobalFilterChange: Dispatch> + clear: () => void +} +``` + +Takes a plain string default — not an options object. + +## `useColumnFilterState` + +```ts +function useColumnFilterState(defaultState?: ColumnFiltersState): { + state: ColumnFiltersState + onColumnFiltersChange: Dispatch> + setFilter: (columnId: string, value: unknown) => void + clearFilter: (columnId: string) => void + clearAll: () => void +} +``` + +Takes a `ColumnFiltersState` default directly — not an options object. + +## `useRowSelectionState` + +```ts +function useRowSelectionState(options?: UseRowSelectionOptions): { + state: RowSelectionState + onRowSelectionChange: Dispatch> + toggleRow: (rowId: string) => void + toggleAll: (rowIds: string[]) => void + clearSelection: () => void + selectedRowIds: string[] + selectedCount: number + isSelected: (rowId: string) => boolean + enableMultiRowSelection: boolean +} +``` + +`UseRowSelectionOptions`: `{ defaultSelection?: RowSelectionState, enableMultiRowSelection?: boolean }` + +Note: `toggleAll` here takes the full array of row IDs (`(rowIds: string[]) => void`) — unlike `useTable`'s `rowSelection.toggleAll()`, which takes no arguments because it already has the table's rows in scope. + +## `useColumnVisibilityState` + +```ts +function useColumnVisibilityState(options?: UseColumnVisibilityOptions): { + state: VisibilityState + onColumnVisibilityChange: Dispatch> + toggleColumn: (columnId: string) => void + showColumn: (columnId: string) => void + hideColumn: (columnId: string) => void + showAll: () => void + hiddenColumns: string[] +} +``` + +`UseColumnVisibilityOptions`: `{ defaultVisibility?: VisibilityState }` + +## `useColumnPinningState` + +```ts +function useColumnPinningState(options?: ColumnPinningOptions): { + state: ColumnPinningState + setState: Dispatch> + pinLeft: (id: string) => void + pinRight: (id: string) => void + unpin: (id: string) => void + clearPinning: () => void + isPinned: (id: string) => 'left' | 'right' | false + leftColumns: string[] + rightColumns: string[] +} +``` + +`ColumnPinningOptions`: `{ defaultPinning?: ColumnPinningState }` + +## `useRowExpansionState` + +```ts +function useRowExpansionState(options?: UseRowExpansionOptions): { + state: ExpandedState + onExpandedChange: OnChangeFn + toggleRow: (rowId: string) => void + expandRow: (rowId: string) => void + collapseRow: (rowId: string) => void + clearExpansion: () => void + expandedRowIds: string[] + isExpanded: (rowId: string) => boolean +} +``` + +`UseRowExpansionOptions` (granular-hook form): `{ defaultExpanded?: ExpandedState, allowMultiple?: boolean }`. +`allowMultiple` defaults to `true`; set `false` so expanding a new row collapses all others. + +Note: `useTable`'s `rowExpansion` option accepts a wider `RowExpansionOptions` +that also includes `paginateExpandedRows` and `getSubRows` (for nested +sub-rows) — those two extra fields are not part of this standalone hook's +options. + +## `useGroupingState` + +```ts +function useGroupingState(options?: UseGroupingOptions): { + state: GroupingState + onGroupingChange: OnChangeFn + toggleGrouping: (columnId: string) => void + setGrouping: (cols: GroupingState) => void + clearGrouping: () => void + isGrouped: (columnId: string) => boolean + groupedColumns: GroupingState +} +``` + +`UseGroupingOptions`: `{ defaultGrouping?: GroupingState, manualGrouping?: boolean, groupedColumnMode?: false | 'reorder' | 'remove' }` From 22e94445b77ff1e89e9776c8f0b110901eddb3c4 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:19:00 +0000 Subject: [PATCH 17/29] docs(www): add API reference pages for virtualization and a11y Cover useVirtualRows and useTableA11y, plus the standalone ARIA helper functions (getAriaSortValue, getAriaRowCount, getAriaColCount, getAriaRowIndex) not called out in the original coverage mapping. --- www/content/docs/api/use-table-a11y.mdx | 91 +++++++++++++++++++++++ www/content/docs/api/use-virtual-rows.mdx | 86 +++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 www/content/docs/api/use-table-a11y.mdx create mode 100644 www/content/docs/api/use-virtual-rows.mdx diff --git a/www/content/docs/api/use-table-a11y.mdx b/www/content/docs/api/use-table-a11y.mdx new file mode 100644 index 0000000..3cb47fc --- /dev/null +++ b/www/content/docs/api/use-table-a11y.mdx @@ -0,0 +1,91 @@ +--- +title: useTableA11y +description: Standalone opt-in hook returning ARIA prop-getters implementing the WAI-ARIA Grid pattern, plus keyboard navigation. +--- + +Standalone opt-in hook. Returns prop-getter objects to spread onto your table +elements, implementing the +[WAI-ARIA Grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/). + +## Signature + +```ts +function useTableA11y( + table: Table, + options?: UseTableA11yOptions +): TableA11yReturn +``` + +## Options + +| Option | Type | Description | +|---|---|---| +| `selectionEnabled` | `boolean` | Set to `true` when row selection is enabled on the table. Adds `aria-selected` to row props. | + +## Return + +| Property | Type | Description | +|---|---|---| +| `getTableProps` | `() => { role: 'grid', 'aria-rowcount': number, 'aria-colcount': number }` | Spread onto the table element | +| `getHeaderProps` | `(headerId: string) => { role: 'columnheader', 'aria-sort': 'ascending' \| 'descending' \| 'none' }` | Spread onto each `` | +| `getRowProps` | `(rowId: string) => { role: 'row', 'aria-rowindex': number, 'aria-selected'?: boolean, 'aria-expanded'?: boolean, tabIndex: 0 \| -1, onKeyDown }` | Spread onto each `` | +| `getCellProps` | `(columnIndex: number) => { role: 'gridcell', 'aria-colindex': number }` | Spread onto each `` | +| `focusedRowIndex` | `number \| null` | Current focused row index — useful for custom focus ring styling | + +## Usage + +```tsx +import { useTable, useTableA11y } from '@marvinackerman/tablecraft' + +const { table } = useTable({ data, columns }) +const a11y = useTableA11y(table, { + selectionEnabled: true, // adds aria-selected to row props +}) + +// Spread onto your elements: + + // role="grid", aria-rowcount, aria-colcount + + + // role="row", aria-rowindex, tabIndex, onKeyDown (ArrowUp/Down/Home/End) + // aria-selected (when selectionEnabled), aria-expanded (when expandable) + +
+ // role="columnheader", aria-sort="ascending"|"descending"|"none" + +
+ // role="gridcell", aria-colindex + +// Current focused row index (for custom focus ring styling): +a11y.focusedRowIndex // number | null +``` + +**Keyboard navigation** (applied automatically via `onKeyDown` on row props): + +| Key | Action | +|---|---| +| `ArrowDown` | Move focus to next row | +| `ArrowUp` | Move focus to previous row | +| `Home` | Move focus to first row | +| `End` | Move focus to last row | +| `Enter` / `Space` | Toggle row selection (when `selectionEnabled`) | + +## Standalone ARIA helpers + +The following functions back `useTableA11y` internally and are also exported +directly, in case you're computing ARIA attributes outside the hook (e.g. for +a custom prop-getter or a non-hook rendering path): + +```ts +function getAriaSortValue(headerId: string, sorting: SortingState): 'ascending' | 'descending' | 'none' +function getAriaRowCount(table: Table): number +function getAriaColCount(table: Table): number +function getAriaRowIndex(rowId: string, rows: Row[]): number +``` + +| Function | Description | +|---|---| +| `getAriaSortValue(headerId, sorting)` | `aria-sort` value for a header cell. `'none'` when the column is not currently sorted. | +| `getAriaRowCount(table)` | Total number of filtered rows — used for `aria-rowcount`. | +| `getAriaColCount(table)` | Number of visible leaf columns — used for `aria-colcount`. | +| `getAriaRowIndex(rowId, rows)` | 1-based row index of the given `rowId` within the provided `rows` array. Returns `-1` if the row is not found (should not happen in normal usage). | diff --git a/www/content/docs/api/use-virtual-rows.mdx b/www/content/docs/api/use-virtual-rows.mdx new file mode 100644 index 0000000..6d77695 --- /dev/null +++ b/www/content/docs/api/use-virtual-rows.mdx @@ -0,0 +1,86 @@ +--- +title: useVirtualRows +description: Render only the rows visible in the viewport, for large datasets where rendering every row causes lag. +--- + +Render only the rows visible in the viewport — for large datasets where +rendering all rows at once causes lag. Requires `@tanstack/react-virtual`: + +```bash +npm install @tanstack/react-virtual +``` + +## Signature + +```ts +function useVirtualRows( + table: Table, + options: VirtualRowsOptions +): VirtualRowsReturn +``` + +## Options + +| Option | Type | Default | Description | +|---|---|---|---| +| `rowHeight` | `number` | — (required) | Fixed height of every row in pixels | +| `overscan` | `number` | `5` | Extra rows rendered above and below the visible area to prevent scroll flicker on fast scrolling | + +## Return + +| Property | Type | Description | +|---|---|---| +| `virtualRows` | `VirtualRow[]` | Only the rows currently visible in the viewport | +| `totalHeight` | `number` | Total scroll height in px — set as the `height` of the inner wrapper div | +| `containerRef` | `RefObject` | Attach to the outer scroll container div | +| `scrollToIndex` | `(index: number) => void` | Programmatically scroll to any row by its position in the full rows array | + +Each `VirtualRow`: + +| Field | Type | Description | +|---|---|---| +| `row` | `Row` | Full TanStack Row — `row.original`, `row.id`, `row.getVisibleCells()`, etc. | +| `index` | `number` | Position in the full rows array | +| `start` | `number` | Pixel offset from top — use as `top` in absolute positioning | +| `size` | `number` | Row height in px (always equals `rowHeight` in fixed mode) | + +## Usage + +```tsx +import { useTable, useVirtualRows } from '@marvinackerman/tablecraft' +import { flexRender } from '@tanstack/react-table' + +const { table } = useTable({ data, columns }) + +const { virtualRows, totalHeight, containerRef, scrollToIndex } = useVirtualRows(table, { + rowHeight: 48, +}) + +// Virtualized tables use div-based rendering — position: absolute requires it. +// Use role="row" and role="cell" for screen reader compatibility. +
+
+ {virtualRows.map(({ row, start, size }) => ( +
+ {row.getVisibleCells().map(cell => ( +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+ ))} +
+ ))} +
+
+ +// Programmatic scroll: +scrollToIndex(42) +``` + +## Notes + +- Standard `//` markup is incompatible with virtualization because browsers do not support `position: absolute` inside ``. Use `
`, `
`, and `
` — semantically equivalent for screen readers. +- Works with [`useTable`](/docs/api/use-table), [`useQueryTable`](/docs/api/use-query-table), and [`useInfiniteTable`](/docs/api/use-infinite-table) equally. From abda8b2e732a23d5bc5fbd138f7625cfb600cf7d Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:19:46 +0000 Subject: [PATCH 18/29] docs(www): add API reference pages for columns, provider, and persistence Cover createColumns, inferColumns, TableKitProvider, useTableKitDefaults, and the persist/URL-sync utility functions. --- www/content/docs/api/columns.mdx | 72 +++++++++++++++ www/content/docs/api/persistence-url.mdx | 109 +++++++++++++++++++++++ www/content/docs/api/provider.mdx | 70 +++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 www/content/docs/api/columns.mdx create mode 100644 www/content/docs/api/persistence-url.mdx create mode 100644 www/content/docs/api/provider.mdx diff --git a/www/content/docs/api/columns.mdx b/www/content/docs/api/columns.mdx new file mode 100644 index 0000000..92b3d35 --- /dev/null +++ b/www/content/docs/api/columns.mdx @@ -0,0 +1,72 @@ +--- +title: Columns +description: createColumns for type-safe column definitions, and inferColumns for auto-generating columns from your data shape. +--- + +## `createColumns` + +Type-safe column definition helper. Returns a stable `ColumnDef[]` +without needing `useMemo` or manual type annotations. + +```ts +function createColumns( + columns: ColumnDef[] +): ColumnDef[] +``` + +```tsx +import { createColumns } from '@marvinackerman/tablecraft' + +const columns = createColumns([ + { accessorKey: 'name', header: 'Name', enableSorting: true }, + { accessorKey: 'email', header: 'Email' }, + { + id: 'actions', + header: 'Actions', + cell: ({ row }) => , + }, +]) +``` + +## `inferColumns` + +Auto-generates typed column definitions from your data shape. Infers depth-1 +(flat) keys only — nested objects and arrays are skipped. + +```ts +function inferColumns( + data: TData[], + options?: InferColumnsOptions +): ColumnDef[] +``` + +**Parameters** + +| Parameter | Type | Description | +|---|---|---| +| `data` | `TData[]` | Array of data objects — needs at least one row to infer shape | +| `options` | `InferColumnsOptions` | Include/exclude/override options | + +**`InferColumnsOptions`** + +| Option | Type | Description | +|---|---|---| +| `include` | `(keyof TData)[]` | Whitelist — only include these keys as columns | +| `exclude` | `(keyof TData)[]` | Blacklist — exclude these keys from columns | +| `overrides` | `Partial>>>` | Override specific column definitions while keeping the rest inferred | + +```tsx +import { inferColumns } from '@marvinackerman/tablecraft' + +const columns = inferColumns(users, { + exclude: ['id'], + overrides: { + role: { header: 'Role' }, + }, +}) +``` + +## Notes + +- `inferColumns` has no `headers` shorthand — rename a column's header via `overrides: { key: { header: '...' } }`. +- For deriving columns straight from a Zod schema (no sample data needed), see [`columnsFromZod`](/docs/api/zod). diff --git a/www/content/docs/api/persistence-url.mdx b/www/content/docs/api/persistence-url.mdx new file mode 100644 index 0000000..93f2c45 --- /dev/null +++ b/www/content/docs/api/persistence-url.mdx @@ -0,0 +1,109 @@ +--- +title: Persistence & URL sync +description: Utilities backing useTable's persist/syncUrl options — manual control over localStorage/sessionStorage state and URL search params. +--- + +`useTable` (and `useQueryTable` / `useInfiniteTable`) can persist state via +`persist` / `persistKey` / `persistOptions`, and sync state to the URL via +`syncUrl` — see [`useTable`](/docs/api/use-table). The functions below are the +underlying utilities, exported for manual control. + +## State persistence + +```ts +type PersistStorage = 'localStorage' | 'sessionStorage' + +interface PersistableState { + sorting?: SortingState + columnFilters?: ColumnFiltersState + globalFilter?: string + pagination?: PaginationState +} + +interface PersistOptions { + sorting?: boolean + columnFilters?: boolean + globalFilter?: boolean + pagination?: boolean +} + +function loadPersistedState( + storage: PersistStorage, + key: string, + options?: PersistOptions +): Partial + +function savePersistedState( + storage: PersistStorage, + key: string, + state: PersistableState, + options?: PersistOptions +): void + +function clearPersistedState(storage: PersistStorage, key: string): void +``` + +`PersistOptions` controls which state slices are read/written; it defaults to +all slices except `pagination`. + +```tsx +import { savePersistedState, loadPersistedState, clearPersistedState } from '@marvinackerman/tablecraft' + +savePersistedState('localStorage', 'my-key', state, { sorting: true, pagination: true }) +loadPersistedState('localStorage', 'my-key') +clearPersistedState('localStorage', 'my-key') +``` + +## URL state sync + +```ts +interface URLKeyMap { + /** URL param key for page number (default: 'page') */ + page?: string + /** URL param key for page size (default: 'pageSize') */ + pageSize?: string + /** URL param key for sorting (default: 'sort') */ + sort?: string + /** URL param key for global filter (default: 'filter') */ + filter?: string + /** Prefix for column filter params (default: 'filter_') */ + columnFilterPrefix?: string +} + +function resolveURLKeys(keys?: URLKeyMap): Required +function parseURLState(keys: Required): Partial +function writeURLState( + state: PersistableState, + keys: Required, + mode?: 'replace' | 'push' +): void +``` + +| Function | Description | +|---|---| +| `resolveURLKeys(keys?)` | Merge user-provided URL keys with defaults, returning the fully-resolved key map. | +| `parseURLState(keys)` | Read current URL search params and return table state. Returns only the slices present in the URL. | +| `writeURLState(state, keys, mode?)` | Write table state to URL search params via `replaceState` or `pushState`. Omits default values to keep URLs clean. | + +```tsx +const { table } = useTable({ + data, + columns, + syncUrl: true, + // or with custom keys: + syncUrl: { + keys: { page: 'p', pageSize: 'ps', sort: 's', filter: 'q' }, + mode: 'replace', // or 'push' (adds a browser history entry) + }, +}) +``` + +For manual control without `useTable`'s `syncUrl` option: + +```tsx +import { resolveURLKeys, parseURLState, writeURLState } from '@marvinackerman/tablecraft' + +const keys = resolveURLKeys({ page: 'p' }) +const initial = parseURLState(keys) +writeURLState(currentState, keys, 'replace') +``` diff --git a/www/content/docs/api/provider.mdx b/www/content/docs/api/provider.mdx new file mode 100644 index 0000000..92de2ff --- /dev/null +++ b/www/content/docs/api/provider.mdx @@ -0,0 +1,70 @@ +--- +title: TableKitProvider +description: Set app-level defaults for all tablecraft hooks — per-call options always override provider defaults. +--- + +Set defaults for all tables in your app. Per-call options always override +provider defaults. + +## `TableKitProvider` + +```ts +function TableKitProvider(props: TableKitProviderProps): JSX.Element +``` + +**`TableKitProviderProps`** + +| Prop | Type | Description | +|---|---|---| +| `defaults` | `TableKitDefaults` | Default options applied to all `useTable` / `useQueryTable` calls within this provider | +| `children` | `ReactNode` | — | + +**`TableKitDefaults`** + +| Property | Type | Description | +|---|---|---| +| `pageSize` | `number` | Default page size for all tables | +| `fuzzy` | `boolean` | Enable fuzzy search by default | +| `rowSelection` | `RowSelectionOptions \| boolean` | Enable row selection by default | +| `columnVisibility` | `ColumnVisibilityOptions \| boolean` | Enable column visibility by default | +| `globalFilter` | `boolean` | Enable global filter by default | +| `columnFilters` | `boolean` | Enable column filters by default | +| `persist` | `PersistStorage \| false` | Default persistence strategy | +| `persistOptions` | `PersistOptions` | Default persist options | +| `syncUrl` | `boolean \| URLSyncOptions` | Default URL sync | +| `rowExpansion` | `RowExpansionOptions \| boolean` | Enable row expansion by default | +| `grouping` | `GroupingOptions \| boolean` | Enable row grouping by default | +| `columnPinning` | `ColumnPinningOptions \| boolean` | Enable column pinning by default | + +```tsx +import { TableKitProvider } from '@marvinackerman/tablecraft' + +function App() { + return ( + + + + ) +} +``` + +## `useTableKitDefaults` + +Read the current `TableKitProvider` defaults. Returns an empty object if no +provider is present — safe to call without a provider. + +```ts +function useTableKitDefaults(): TableKitDefaults +``` + +```tsx +import { useTableKitDefaults } from '@marvinackerman/tablecraft' + +const defaults = useTableKitDefaults() +``` From 30891bfa1c14d1fbeca14db39914a8ffd91b0482 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:20:31 +0000 Subject: [PATCH 19/29] docs(www): add Zod integration page and API section nav Cover columnsFromZod and zodValidator from the /zod entry, and set the api/meta.json page order for the API Reference nav section. --- www/content/docs/api/meta.json | 18 ++++++++ www/content/docs/api/zod.mdx | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 www/content/docs/api/meta.json create mode 100644 www/content/docs/api/zod.mdx diff --git a/www/content/docs/api/meta.json b/www/content/docs/api/meta.json new file mode 100644 index 0000000..9a4dc6f --- /dev/null +++ b/www/content/docs/api/meta.json @@ -0,0 +1,18 @@ +{ + "title": "API Reference", + "pages": [ + "use-table", + "use-server-table", + "use-query-table", + "use-infinite-table", + "use-infinite-scroll", + "state-hooks", + "editing", + "use-virtual-rows", + "use-table-a11y", + "columns", + "provider", + "persistence-url", + "zod" + ] +} diff --git a/www/content/docs/api/zod.mdx b/www/content/docs/api/zod.mdx new file mode 100644 index 0000000..4288874 --- /dev/null +++ b/www/content/docs/api/zod.mdx @@ -0,0 +1,84 @@ +--- +title: Zod integration +description: columnsFromZod and zodValidator from the @marvinackerman/tablecraft/zod entry — one Zod schema as the source of truth for columns and edit validation. +--- + +Use one Zod schema as the source of truth for a table's columns *and* its +edit validation. Exported from the separate `@marvinackerman/tablecraft/zod` +entry point. Requires `zod` (optional peer, works with Zod 3 and 4): + +```bash +npm i zod +``` + +```tsx +import { useTable, useMultiRowEditing } from '@marvinackerman/tablecraft' +import { columnsFromZod, zodValidator } from '@marvinackerman/tablecraft/zod' +import { z } from 'zod' + +const userSchema = z.object({ + name: z.string().min(1, 'Name is required'), + email: z.string().email('Invalid email'), +}) +type User = z.infer + +const columns = columnsFromZod(userSchema) // ColumnDef[] +const validate = zodValidator(userSchema) + +const { table } = useTable({ data, columns }) +const editing = useMultiRowEditing(table, { + onSave: async (rowId, draft) => validate(draft) ?? api.save(rowId, draft), +}) +``` + +## `columnsFromZod` + +```ts +function columnsFromZod( + schema: TSchema, + options?: ColumnsFromZodOptions> +): ColumnDef, any>[] +``` + +Generates headless `{ accessorKey, header }` columns from the schema's +top-level fields — headers are humanized (`firstName` → "First Name"). Needs +no sample data, unlike [`inferColumns`](/docs/api/columns). + +**`ColumnsFromZodOptions`** + +| Option | Type | Description | +|---|---|---| +| `include` | `(keyof TData)[]` | Whitelist — only include these keys, in the order given | +| `exclude` | `(keyof TData)[]` | Blacklist — exclude these keys | +| `overrides` | `Partial>>>` | Override specific column definitions while keeping the rest generated | + +## `zodValidator` + +```ts +function zodValidator( + schema: TSchema, + options?: ZodValidatorOptions> +): (values: unknown) => Partial, string>> | undefined +``` + +Returns `(row) => errors | undefined`, matching the error-map contract of +[`useEditableRows` / `useMultiRowEditing`](/docs/api/editing). Returns +`undefined` when the row is valid, so it composes directly with `??`. + +**`ZodValidatorOptions`** + +| Option | Type | Description | +|---|---|---| +| `rootErrorField` | `keyof TData` | Field that receives object-level (empty-path) issues from `.refine()` / `.superRefine()`. Resolution order: `rootErrorField`, then the first key of the schema's `.shape` (if present), then the first key of the validated object. | + +```tsx +const validate = zodValidator(dateRangeSchema, { rootErrorField: 'endDate' }) +``` + +## Notes + +- Fields whose schema directly exposes `.shape` (a nested `z.object`) are skipped by `columnsFromZod`. Arrays, records, and optional/nullable-wrapped objects are **not** auto-detected — `.shape` is `undefined` on `z.array(...)`, `z.record(...)`, and `z.object({...}).optional()` / `.nullable()`, so those fields still get a column. Use `exclude` for those. +- `columnsFromZod` requires a plain `z.object({...})`; wrapped schemas (`.refine()`) throw — use `zodValidator` for those, which supports them fully. +- `.refine()` behaves differently across Zod majors: Zod 3 wraps refined schemas so `.shape` is hidden — `columnsFromZod` throws with instructions (pass the base object, or `.innerType()`). Zod 4 keeps `.shape`, so refined schemas work normally with `columnsFromZod` too. `zodValidator` accepts refined schemas on both. +- **Invalid rows are never silently committed.** If the schema rejects a row, the map `zodValidator` returns is always non-empty — an empty map would collapse to `undefined` under the caller's `Object.keys(e).length ? e : undefined` idiom, and the row would be committed despite being invalid. +- If the resolved `rootErrorField` already has a field-level error for this validation round, the object-level message is *not* attached — the row still stays in edit mode (the field-level error keeps it there), and the object-level message surfaces once that field's own error is fixed. From 3cf8ba2cb4ffd0103c958e9db8c0cbc81dde848e Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:30:25 +0000 Subject: [PATCH 20/29] docs(www): correct rowSelection and overscan details --- www/content/docs/api/use-table.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/content/docs/api/use-table.mdx b/www/content/docs/api/use-table.mdx index efe1ef4..766da27 100644 --- a/www/content/docs/api/use-table.mdx +++ b/www/content/docs/api/use-table.mdx @@ -31,7 +31,7 @@ function useTable( | `onGlobalFilterChange` | `(value: string) => void` | Custom global filter handler | | `columnFilters` | `boolean` | Enable per-column filters | | `onColumnFiltersChange` | `OnChangeFn` | Custom column filter handler | -| `rowSelection` | `RowSelectionOptions \| boolean` | `true`, or `{ enableMultiRowSelection? }` | +| `rowSelection` | `RowSelectionOptions \| boolean` | `true`, or `{ defaultSelection?: RowSelectionState, enableMultiRowSelection? }` | | `columnVisibility` | `ColumnVisibilityOptions \| boolean` | `true`, or `{ defaultVisibility? }` | | `rowExpansion` | `RowExpansionOptions \| boolean` | `true`, or `{ defaultExpanded?, allowMultiple?, paginateExpandedRows?, getSubRows? }` | | `grouping` | `GroupingOptions \| boolean` | `true`, or `{ defaultGrouping?, manualGrouping?, groupedColumnMode? }` | From e8d844da7ed2e5669297234e0f50524675ec7c12 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 18:43:06 +0000 Subject: [PATCH 21/29] docs(www): add inline-editing, server-data, and url-state guides --- www/content/docs/guides/inline-editing.mdx | 133 +++++++++++++++++ www/content/docs/guides/meta.json | 4 + www/content/docs/guides/server-side-data.mdx | 136 +++++++++++++++++ .../docs/guides/url-state-persistence.mdx | 141 ++++++++++++++++++ 4 files changed, 414 insertions(+) create mode 100644 www/content/docs/guides/inline-editing.mdx create mode 100644 www/content/docs/guides/meta.json create mode 100644 www/content/docs/guides/server-side-data.mdx create mode 100644 www/content/docs/guides/url-state-persistence.mdx diff --git a/www/content/docs/guides/inline-editing.mdx b/www/content/docs/guides/inline-editing.mdx new file mode 100644 index 0000000..e88e7e0 --- /dev/null +++ b/www/content/docs/guides/inline-editing.mdx @@ -0,0 +1,133 @@ +--- +title: Inline editing & validation +description: Let users edit table cells in place and validate their changes with Zod, without a form library. +--- + +## The problem + +Rendering rows is the easy part. Letting a user click a cell, edit it, and +save it back requires its own little state machine: which row is being +edited, what the in-progress (draft) values are, whether anything actually +changed, what the validation errors are, and whether a save is in flight — +all before you've written a single ``. + +## The solution + +[`useEditableRows`](/docs/api/editing) owns that state machine for a single +row at a time. You give it an `onSave` callback; it gives back the draft +values, dirty tracking, errors, and the `startEditing` / `setField` / +`saveEditing` / `cancelEditing` actions to wire into your markup. + +For validation, [`zodValidator`](/docs/api/zod) (from the separate +`@marvinackerman/tablecraft/zod` entry) turns a Zod schema into the exact +error-map shape `onSave` expects — `Partial> | +undefined`. Compose it with `??` so a real save only runs once validation +passes: + +```ts +onSave: async (rowId, draft) => validate(draft) ?? api.save(rowId, draft) +``` + +## Walkthrough + +Install `zod` if you haven't already (it's an optional peer dependency): + +```bash +npm i zod +``` + +Define one schema and derive both the columns and the validator from it: + +```tsx +import { useTable } from '@marvinackerman/tablecraft' +import { useEditableRows } from '@marvinackerman/tablecraft' +import { columnsFromZod, zodValidator } from '@marvinackerman/tablecraft/zod' +import { flexRender } from '@tanstack/react-table' +import { z } from 'zod' + +const userSchema = z.object({ + name: z.string().min(1, 'Name is required'), + email: z.string().email('Invalid email'), +}) +type User = z.infer + +const columns = columnsFromZod(userSchema) // ColumnDef[] — no cell renderers, headers humanized +const validate = zodValidator(userSchema) + +function UsersTable({ users }: { users: User[] }) { + const { table } = useTable({ data: users, columns }) + + const editable = useEditableRows(table, { + onSave: async (rowId, draft) => { + // Run the schema first — returning an error map keeps the row in edit mode. + const errors = validate(draft) + if (errors) return errors + + // Validation passed — commit to your backend, then exit edit mode. + await api.updateUser(rowId, draft) + }, + }) + + return ( +
+ + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => { + const field = cell.column.id as keyof User + + if (editable.isEditing(row.id)) { + return ( + + ) + } + + return + })} + + + ))} + +
+ editable.setField(field, e.target.value)} + /> + {editable.errors[field] && ( + {editable.errors[field]} + )} + {flexRender(cell.column.columnDef.cell, cell.getContext())} + {editable.isEditing(row.id) ? ( + <> + + + + ) : ( + + )} +
+ ) +} +``` + +That's a complete, editable, validated table: `columnsFromZod` generates the +columns, `useEditableRows` manages edit/draft/error state per row, and +`zodValidator` is the bridge between the schema and `onSave`. + +{/* A live, runnable version of this example renders here. */} + +## Notes + +- `zodValidator`'s guarantee: if the schema rejects a value, the returned + error map is never empty — so an invalid row can't accidentally slip + through a caller's `Object.keys(e).length ? e : undefined` idiom. See + [Zod integration](/docs/api/zod) for the full details, including + `rootErrorField` for cross-field `.refine()` errors. +- Editing multiple rows at once (bulk save, per-row save, `saveAll`) is a + separate hook, [`useMultiRowEditing`](/docs/api/editing#usemultirowediting) + — same error-map contract, same `zodValidator` output plugs straight in. +- Don't have a schema yet? [`inferColumns`](/docs/api/columns) generates + columns from sample data instead, but you'll need your own validation + function matching the same error-map shape. diff --git a/www/content/docs/guides/meta.json b/www/content/docs/guides/meta.json new file mode 100644 index 0000000..6a323aa --- /dev/null +++ b/www/content/docs/guides/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Guides", + "pages": ["inline-editing", "server-side-data", "url-state-persistence"] +} diff --git a/www/content/docs/guides/server-side-data.mdx b/www/content/docs/guides/server-side-data.mdx new file mode 100644 index 0000000..3af0b4f --- /dev/null +++ b/www/content/docs/guides/server-side-data.mdx @@ -0,0 +1,136 @@ +--- +title: Server-side data +description: Drive a table from a paginated, sorted, and filtered API instead of a client-side array. +--- + +## The problem + +`useTable`'s default pagination and sorting run entirely in memory — great +for a few thousand rows, useless once the data lives behind an API and only +one page of it is ever in the browser at a time. You need the table's +pagination and sorting *state* without letting it run the actual row math, +and you need to react when the user changes a page or a sort so you can +refetch. + +## The solution + +[`useServerTable`](/docs/api/use-server-table) is `useTable` with +`manualPagination` and `manualSorting` forced to `true`, and `rowCount` +required instead of optional. You pass it only the current page's data plus +the total row count; `onPaginationChange` / `onSortingChange` tell you when +to refetch. + +If you're already using TanStack Query, [`useQueryTable`](/docs/api/use-query-table) +wraps this same manual-mode model with query-key-driven refetching, so you +don't have to wire the `useState` + `useEffect` refetch loop yourself. + +## Walkthrough: `useServerTable` + +```tsx +import { useState, useEffect, useCallback } from 'react' +import { useServerTable } from '@marvinackerman/tablecraft' +import type { SortingState } from '@tanstack/react-table' + +interface User { + id: string + name: string + email: string +} + +function UsersTable() { + const [rows, setRows] = useState([]) + const [rowCount, setRowCount] = useState(0) + const [pageIndex, setPageIndex] = useState(0) + const [pageSize, setPageSize] = useState(20) + const [sort, setSort] = useState([]) + + const refetch = useCallback(async () => { + const res = await api.getUsers({ page: pageIndex, pageSize, sort }) + setRows(res.data) + setRowCount(res.total) + }, [pageIndex, pageSize, sort]) + + useEffect(() => { + refetch() + }, [refetch]) + + const { table, pagination, sorting } = useServerTable({ + data: rows, + columns, + rowCount, // required — total rows in the full dataset, drives pageCount + pagination: { pageIndex, pageSize }, + onPaginationChange: (updater) => { + const next = typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater + setPageIndex(next.pageIndex) + setPageSize(next.pageSize) + }, + onSortingChange: (updater) => { + const next = typeof updater === 'function' ? updater(sort) : updater + setSort(next) + }, + }) + + return ( + + {/* render table.getHeaderGroups() / table.getRowModel() as usual */} +
+ ) +} +``` + +`pagination` and `sorting` from the return value give you the same +`pageIndex` / `pageCount` / `canNextPage` / `sortingState` helpers you'd get +from client-side `useTable` — only the row model behind them is now driven +by your fetch instead of an in-memory array. + +## Walkthrough: `useQueryTable` (TanStack Query) + +`useQueryTable` collapses the `useState` + `useEffect` refetch loop above +into a single `queryFn` keyed by `queryKey`. It refetches automatically +whenever pagination, sorting, filters, or grouping change: + +```tsx +import { useQueryTable } from '@marvinackerman/tablecraft' + +const { table, pagination, sorting, query } = useQueryTable({ + queryKey: ['users'], + queryFn: async ({ pagination, sorting, globalFilter }) => { + const res = await api.getUsers({ + page: pagination.pageIndex, + pageSize: pagination.pageSize, + sort: sorting, + search: globalFilter, + }) + return { data: res.data, rowCount: res.total } + }, + columns, + pagination: { pageSize: 20 }, + sorting: true, + globalFilter: true, +}) + +// query.isLoading / query.isError / query.error for loading & error UI +``` + +Requires `@tanstack/react-query` (`npm i @tanstack/react-query`). See +[`useQueryTable`](/docs/api/use-query-table) for the full option list — +`persist`, `syncUrl`, `rowSelection`, `columnPinning`, and the TanStack Query +pass-through options (`staleTime`, `refetchOnWindowFocus`, etc.) all work the +same way they do on `useTable`. + +## Which one? + +- **`useServerTable`** — you own the fetching (a REST call, SWR, a server + action, whatever). You write the `onPaginationChange` / `onSortingChange` + handlers and decide when to refetch. +- **`useQueryTable`** — you're already on TanStack Query and want its cache, + retries, and automatic refetch-on-state-change for free. +- Cursor-based infinite lists (as opposed to page-numbered ones) are a third + case — see [`useInfiniteTable`](/docs/api/use-infinite-table). + +## Notes + +- `rowCount` is required on `useServerTable` — without it the table can't + compute `pageCount` or `canNextPage`. +- Want the current page/sort/filter reflected in the URL so a server-driven + view is shareable? See [URL state & persistence](/docs/guides/url-state-persistence). diff --git a/www/content/docs/guides/url-state-persistence.mdx b/www/content/docs/guides/url-state-persistence.mdx new file mode 100644 index 0000000..87423f6 --- /dev/null +++ b/www/content/docs/guides/url-state-persistence.mdx @@ -0,0 +1,141 @@ +--- +title: URL state & persistence +description: Make a table's sort, page, and filters shareable via URL and durable across reloads. +--- + +## The problem + +A table's sort/filter/page state normally lives in React state — refresh the +page, or send the link to a teammate, and it's gone. You want two related but +distinct things: the current view **shareable** (encoded in the URL so a +pasted link reproduces it) and **durable** (remembered on this device even +without a URL, e.g. plain `localhost:3000/users` should reopen to whatever +view you left it in). + +## The quick path + +For the common case, `useTable` (and `useServerTable` / `useQueryTable` / +`useInfiniteTable`) do both automatically via the `persist*` and `syncUrl` +options: + +```tsx +useTable({ + data, + columns, + persist: 'localStorage', + persistKey: 'users-table', // unique per table + syncUrl: true, +}) +``` + +See [`useTable`](/docs/api/use-table) and +[Persistence & URL sync](/docs/api/persistence-url) for the full option +shapes. If that covers your case, stop there — the rest of this guide is for +when you need manual control over *how* state round-trips: custom routers, +combining a URL-first / storage-fallback strategy, or state you're managing +outside `useTable` (e.g. the `useServerTable` pattern from +[Server-side data](/docs/guides/server-side-data)). + +## The solution: manual control + +Four utilities back the options above, exported for direct use: + +- [`parseURLState(keys)`](/docs/api/persistence-url) — reads the current URL + search params, returns only the state slices present in the URL. +- [`writeURLState(state, keys, mode?)`](/docs/api/persistence-url) — writes + state back to the URL via `history.replaceState` (default) or + `pushState`. +- [`loadPersistedState(storage, key, options?)`](/docs/api/persistence-url) — + reads previously saved state from `localStorage` / `sessionStorage`. +- [`savePersistedState(storage, key, state, options?)`](/docs/api/persistence-url) — + writes state to storage. + +Note the argument order: both persistence functions take `storage` and `key` +*first*, then the state/options. + +## Walkthrough: URL first, storage as fallback + +The URL should win when present (that's what makes a link shareable); when +there's no URL state, fall back to whatever was last persisted on this +device. Read both once on mount, merge them, and write to both on every +change: + +```tsx +'use client' + +import { useMemo, useState } from 'react' +import { useTable } from '@marvinackerman/tablecraft' +import { + resolveURLKeys, + parseURLState, + writeURLState, + loadPersistedState, + savePersistedState, +} from '@marvinackerman/tablecraft' +import type { SortingState, PaginationState } from '@tanstack/react-table' + +const STORAGE_KEY = 'users-table' + +function UsersTable({ data, columns }) { + const keys = useMemo(() => resolveURLKeys(), []) + + // URL wins over persisted storage; persisted storage wins over defaults. + const [initial] = useState(() => ({ + ...loadPersistedState('localStorage', STORAGE_KEY), + ...parseURLState(keys), + })) + + const [sort, setSort] = useState(initial.sorting ?? []) + const [pagination, setPagination] = useState( + initial.pagination ?? { pageIndex: 0, pageSize: 20 }, + ) + + const persistAndSync = (next: { sorting?: SortingState; pagination?: PaginationState }) => { + const state = { sorting: sort, pagination, ...next } + writeURLState(state, keys, 'replace') + savePersistedState('localStorage', STORAGE_KEY, state, { pagination: true }) + } + + const { table } = useTable({ + data, + columns, + sorting: { defaultSort: sort }, + pagination: { pageIndex: pagination.pageIndex, pageSize: pagination.pageSize }, + onSortingChange: (updater) => { + const next = typeof updater === 'function' ? updater(sort) : updater + setSort(next) + persistAndSync({ sorting: next }) + }, + onPaginationChange: (updater) => { + const next = typeof updater === 'function' ? updater(pagination) : updater + setPagination(next) + persistAndSync({ pagination: next }) + }, + }) + + return {/* render as usual */}
+} +``` + +Reloading the page (no URL params) restores the last persisted sort and +page. Sharing the URL sends the exact view — the recipient's `parseURLState` +call picks up the same sort and page from the query string, taking priority +over anything already in their own storage. + +## Notes + +- `parseURLState` and `writeURLState` read/write `window.location` directly + — they only run client-side (`'use client'` in Next.js App Router, and + guard against SSR if you call them outside an effect/event handler). +- `resolveURLKeys({ page: 'p', sort: 's' })` lets you shorten or rename the + query params; pass the same resolved `keys` object to both + `parseURLState` and `writeURLState`. +- `PersistOptions` (the last argument to both persistence functions) controls + which state slices are read/written — it defaults to everything **except** + `pagination`, which is why the example above passes `{ pagination: true }` + explicitly to `savePersistedState`. +- `writeURLState` omits values that match their defaults, so the URL stays + clean instead of accumulating every possible param. +- These same utilities work identically alongside `useServerTable` and + `useQueryTable` — persist/sync whatever state you're already tracking for + the refetch, as shown in [Server-side data](/docs/guides/server-side-data). From 58072003ca274f94b5b9c6050ce937ecce34cce3 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:04:04 +0000 Subject: [PATCH 22/29] feat(docs): add live inline-editing example component --- .../examples/InlineEditingExample.tsx | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 www/components/examples/InlineEditingExample.tsx diff --git a/www/components/examples/InlineEditingExample.tsx b/www/components/examples/InlineEditingExample.tsx new file mode 100644 index 0000000..e9ac7be --- /dev/null +++ b/www/components/examples/InlineEditingExample.tsx @@ -0,0 +1,114 @@ +'use client' +import { useState } from 'react' +import { useTable, useEditableRows, createColumns } from '@marvinackerman/tablecraft' +import { flexRender } from '@tanstack/react-table' +import { sampleUsers, type User } from './sample-data' + +const columns = createColumns([ + { accessorKey: 'name', header: 'Name' }, + { accessorKey: 'email', header: 'Email' }, + { accessorKey: 'role', header: 'Role' }, + { accessorKey: 'age', header: 'Age' }, +]) + +export default function InlineEditingExample() { + // A local copy of the shared sample data — edits here never touch the + // original `sampleUsers` array used by other examples on this page. + const [users, setUsers] = useState(() => sampleUsers.map((u) => ({ ...u }))) + const { table } = useTable({ data: users, columns }) + const editable = useEditableRows(table, { + onSave: (rowId, draft) => { + setUsers((prev) => prev.map((u, i) => (String(i) === rowId ? { ...u, ...draft } : u))) + }, + }) + + return ( +
+ + + {table.getHeaderGroups().map((hg) => ( + + {hg.headers.map((h) => ( + + ))} + + + ))} + + + {table.getRowModel().rows.map((row) => { + const editing = editable.isEditing(row.id) + return ( + + {row.getVisibleCells().map((cell) => { + const field = cell.column.id as keyof User + + if (editing) { + return ( + + ) + } + + return ( + + ) + })} + + + ) + })} + +
+ {flexRender(h.column.columnDef.header, h.getContext())} + Actions
+ + editable.setField( + field, + (field === 'age' + ? Number(e.target.value) + : e.target.value) as User[typeof field], + ) + } + /> + {editable.errors[field] && ( + + {editable.errors[field]} + + )} + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + {editing ? ( +
+ + +
+ ) : ( + + )} +
+
+ ) +} From cac82b50f4cb80b9c893b09d26d88686899a007c Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:04:05 +0000 Subject: [PATCH 23/29] feat(docs): add live virtualization example component --- .../examples/VirtualizationExample.tsx | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 www/components/examples/VirtualizationExample.tsx diff --git a/www/components/examples/VirtualizationExample.tsx b/www/components/examples/VirtualizationExample.tsx new file mode 100644 index 0000000..ca2754e --- /dev/null +++ b/www/components/examples/VirtualizationExample.tsx @@ -0,0 +1,68 @@ +'use client' +import { useMemo } from 'react' +import { useTable, useVirtualRows, createColumns } from '@marvinackerman/tablecraft' +import { flexRender } from '@tanstack/react-table' + +type BigRow = { id: number; name: string; value: number } + +function generateRows(count: number): BigRow[] { + return Array.from({ length: count }, (_, i) => ({ + id: i, + name: `Row ${i}`, + value: Math.round(Math.random() * 1000), + })) +} + +const columns = createColumns([ + { accessorKey: 'id', header: 'ID' }, + { accessorKey: 'name', header: 'Name' }, + { accessorKey: 'value', header: 'Value' }, +]) + +const ROW_HEIGHT = 36 + +export default function VirtualizationExample() { + // Generated once — 10,000 in-memory rows, no network. + const data = useMemo(() => generateRows(10000), []) + // Virtualization needs the full row model — useTable defaults to + // client-side pagination (page size 10), so it must be disabled here. + const { table } = useTable({ data, columns, pagination: false }) + const { virtualRows, totalHeight, containerRef } = useVirtualRows(table, { + rowHeight: ROW_HEIGHT, + }) + + return ( +
+
+ {table.getHeaderGroups()[0]?.headers.map((h) => ( +
+ {flexRender(h.column.columnDef.header, h.getContext())} +
+ ))} +
+
+
+ {virtualRows.map(({ row, start, size }) => ( +
+ {row.getVisibleCells().map((cell) => ( +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+ ))} +
+ ))} +
+
+

+ 10,000 rows generated in memory — only the rows visible in the 400px + viewport (plus overscan) are mounted at any time. Scroll to see rows + mount and unmount. +

+
+ ) +} From 2c6896fb03310c32286fe3b1b5920a7a2065f9aa Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:04:05 +0000 Subject: [PATCH 24/29] feat(docs): embed live inline-editing example in guide --- www/content/docs/guides/inline-editing.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/content/docs/guides/inline-editing.mdx b/www/content/docs/guides/inline-editing.mdx index e88e7e0..55e2c57 100644 --- a/www/content/docs/guides/inline-editing.mdx +++ b/www/content/docs/guides/inline-editing.mdx @@ -3,6 +3,8 @@ title: Inline editing & validation description: Let users edit table cells in place and validate their changes with Zod, without a form library. --- +import InlineEditingExample from '@/components/examples/InlineEditingExample' + ## The problem Rendering rows is the easy part. Letting a user click a cell, edit it, and @@ -116,7 +118,7 @@ That's a complete, editable, validated table: `columnsFromZod` generates the columns, `useEditableRows` manages edit/draft/error state per row, and `zodValidator` is the bridge between the schema and `onSave`. -{/* A live, runnable version of this example renders here. */} + ## Notes From 87ffe1ef5e60abe7d69e0508c90e2171af8ddc2c Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:04:05 +0000 Subject: [PATCH 25/29] feat(docs): embed live virtualization example in api reference --- www/content/docs/api/use-virtual-rows.mdx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/www/content/docs/api/use-virtual-rows.mdx b/www/content/docs/api/use-virtual-rows.mdx index 6d77695..e2b0258 100644 --- a/www/content/docs/api/use-virtual-rows.mdx +++ b/www/content/docs/api/use-virtual-rows.mdx @@ -3,6 +3,8 @@ title: useVirtualRows description: Render only the rows visible in the viewport, for large datasets where rendering every row causes lag. --- +import VirtualizationExample from '@/components/examples/VirtualizationExample' + Render only the rows visible in the viewport — for large datasets where rendering all rows at once causes lag. Requires `@tanstack/react-virtual`: @@ -80,6 +82,13 @@ const { virtualRows, totalHeight, containerRef, scrollToIndex } = useVirtualRows scrollToIndex(42) ``` +## Live example + +10,000 in-memory rows, rendered with `useVirtualRows` inside a fixed-height +scroll container — only the rows in view (plus overscan) are ever mounted. + + + ## Notes - Standard `//` markup is incompatible with virtualization because browsers do not support `position: absolute` inside ``. Use `
`, `
`, and `
` — semantically equivalent for screen readers. From faf1369e1785f5e9cf48d5d416f8abb89828209a Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:08:39 +0000 Subject: [PATCH 26/29] docs(www): note pagination:false requirement for virtualization --- www/content/docs/api/use-virtual-rows.mdx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/content/docs/api/use-virtual-rows.mdx b/www/content/docs/api/use-virtual-rows.mdx index e2b0258..cbda02a 100644 --- a/www/content/docs/api/use-virtual-rows.mdx +++ b/www/content/docs/api/use-virtual-rows.mdx @@ -48,11 +48,16 @@ Each `VirtualRow`: ## Usage +> **Note:** Pass `pagination: false` to `useTable` when combining it with +> `useVirtualRows`. `useTable` paginates to a default page size of 10, so +> without disabling it the virtualizer only ever sees ~10 rows instead of +> your full dataset. + ```tsx import { useTable, useVirtualRows } from '@marvinackerman/tablecraft' import { flexRender } from '@tanstack/react-table' -const { table } = useTable({ data, columns }) +const { table } = useTable({ data, columns, pagination: false }) const { virtualRows, totalHeight, containerRef, scrollToIndex } = useVirtualRows(table, { rowHeight: 48, From 1c9681a8a3815f8f786114d849d0f678985854c5 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:10:44 +0000 Subject: [PATCH 27/29] docs: slim README to overview + install + link to docs site --- README.md | 1072 +---------------------------------------------------- 1 file changed, 18 insertions(+), 1054 deletions(-) diff --git a/README.md b/README.md index c86a5e9..6303be1 100644 --- a/README.md +++ b/README.md @@ -5,1083 +5,47 @@ > Batteries-included [TanStack Table](https://tanstack.com/table) wrapper for React. TypeScript-first, headless, zero UI lock-in. -**Go from ~100 lines of TanStack Table boilerplate to ~10 lines.** No CSS. No component library. Full escape hatch to the raw table instance. +tablecraft collapses the 80–150 lines of `useState`/`useMemo` boilerplate that every TanStack Table project rewrites into a single hook call — without taking away control. You get sensible defaults for sorting, pagination, and filtering, and the full TanStack Table instance is always available as an escape hatch. There's no bundled CSS and no component library, so tablecraft never fights your design system. -> **Using shadcn/ui?** Its data table is built on TanStack Table. Swap the boilerplate for `useTable` and keep every one of your components — tablecraft ships zero markup and zero styles. +**Full docs, guides, and live examples: [https://\](https://)** + +## Install ``` -npm i @marvinackerman/tablecraft @tanstack/react-table +npm i @marvinackerman/tablecraft @tanstack/react-table@^8 react@^18 ``` -## Quick Start +`@tanstack/react-virtual` (`^3`) is an optional peer, needed only for `useVirtualRows`. `zod` (`>=3.23`) is an optional peer for the `tablecraft/zod` entry point. See the [Installation guide](https:///docs/getting-started/installation) for the full optional-peer matrix. + +## Quick start ```tsx import { useTable, createColumns } from '@marvinackerman/tablecraft' import { flexRender } from '@tanstack/react-table' -type User = { id: number; name: string; email: string; role: string } - const columns = createColumns([ { accessorKey: 'name', header: 'Name' }, { accessorKey: 'email', header: 'Email' }, { accessorKey: 'role', header: 'Role' }, + { accessorKey: 'age', header: 'Age' }, ]) function UsersTable({ users }: { users: User[] }) { - const { table, pagination, sorting, globalFilter } = useTable({ - data: users, - columns, - pagination: { pageSize: 20 }, - sorting: true, - globalFilter: true, - }) - - return ( -
- globalFilter.setValue(e.target.value)} - /> -
- - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
- {flexRender(header.column.columnDef.header, header.getContext())} - {{ asc: ' ↑', desc: ' ↓' }[header.column.getIsSorted() as string] ?? ''} -
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
- - Page {pagination.pageIndex + 1} of {pagination.pageCount} - -
- - ) + const { table } = useTable({ data: users, columns }) + // render table.getHeaderGroups() / table.getRowModel() with flexRender } ``` -Sorting, pagination, global search, full TypeScript generics — wired up in one call. - ---- - -## Why tablecraft? - -`@tanstack/react-table` is intentionally 100% headless. That's its strength, but every project starts with 80–150 lines of identical boilerplate: `useState` for sorting, `useState` for pagination, `useState` for filters, `useMemo` for columns, manual row model wiring… - -**tablecraft eliminates the boilerplate without taking away control.** You get sensible defaults, and the full TanStack Table instance is always available as an escape hatch. - -| Feature | TanStack Table | AG Grid | Material React Table | **tablecraft** | -|---|---|---|---|---| -| Headless (no CSS) | Yes | No | No | **Yes** | -| Zero boilerplate | No | Yes | Yes | **Yes** | -| TypeScript-first | Yes | Yes | Yes | **Yes** | -| Inline editing | No | Yes | Yes | **Yes** | -| State persistence | No | Yes | No | **Yes** | -| Row grouping | Yes | Enterprise $$ | Yes | **Yes** | -| Bundle size | ~14 KB | ≈300 KB† | ≈50 KB† | **~4 KB** + TanStack peer | -| License | MIT | MIT* | MIT | **MIT** | - -† tablecraft (~4 KB core) and TanStack Table figures are measured min+gzip; AG Grid and Material React Table are approximate published sizes that vary with configuration. * AG Grid Community is MIT; its Enterprise tier (row grouping, pivoting, server-side row model, Excel export, master/detail) requires a paid licence. - -**The combination is the point:** tablecraft is the only one that is *both* fully headless and zero-boilerplate. - ---- - -## API Reference - -### `useTable` — Primary Hook - -The single hook that covers 90% of use cases. Every option is optional. - -```tsx -const { - table, // Full TanStack Table instance - pagination, - sorting, - globalFilter, - columnFilters, - rowSelection, - columnVisibility, - rowExpansion, - grouping, - emptyState, -} = useTable({ - data, - columns, - - // Pagination - pagination: { pageSize: 20 }, // or true (defaults) or false (disabled) - - // Sorting - sorting: { defaultSort: [{ id: 'name', desc: false }] }, // or true or false - - // Filtering - globalFilter: true, - columnFilters: true, - - // Row selection - rowSelection: true, // or { enableMultiRowSelection: false } - - // Column visibility - columnVisibility: { defaultVisibility: { email: false } }, // or true - - // Row expansion (nested sub-rows) - rowExpansion: { getSubRows: (row) => row.children }, // or true - - // Row grouping - grouping: { defaultGrouping: ['role'] }, // or true - - // Fuzzy search — `true` loads match-sorter via require() (CJS/Node only). - // In ESM-only bundlers (Vite, browsers), pass your own filter function instead. - fuzzy: true, // or (row, columnId, value) => boolean - - // State persistence - persist: 'localStorage', // or 'sessionStorage' - persistKey: 'my-table', - persistOptions: { sorting: true, pagination: true }, - - // URL state sync - syncUrl: true, // or { keys: { page: 'p', sort: 's' }, mode: 'replace' } -}) -``` - -**`pagination` return:** - -| Property | Type | Description | -|---|---|---| -| `pageIndex` | `number` | Current page (0-indexed) | -| `pageSize` | `number` | Rows per page | -| `pageCount` | `number` | Total pages | -| `canPreviousPage` | `boolean` | Can go back | -| `canNextPage` | `boolean` | Can go forward | -| `previousPage` | `() => void` | Go to previous page | -| `nextPage` | `() => void` | Go to next page | -| `setPageIndex` | `(index: number) => void` | Jump to page | -| `setPageSize` | `(size: number) => void` | Change page size | - -**`sorting` return:** - -| Property | Type | Description | -|---|---|---| -| `sortingState` | `SortingState` | Current sort state | -| `setSorting` | `OnChangeFn` | Set sort state directly | -| `clearSorting` | `() => void` | Clear all sorting | - -**`rowSelection` return:** - -| Property | Type | Description | -|---|---|---| -| `state` | `RowSelectionState` | Current selection map | -| `toggleRow` | `(rowId: string) => void` | Toggle a row | -| `toggleAll` | `() => void` | Select / deselect all | -| `clearSelection` | `() => void` | Clear all | -| `selectedRowIds` | `string[]` | IDs of selected rows | -| `selectedCount` | `number` | Number selected | -| `isSelected` | `(rowId: string) => boolean` | Check if selected | - -**`rowExpansion` return:** - -| Property | Type | Description | -|---|---|---| -| `state` | `ExpandedState` | Current expanded rows | -| `toggleRow` | `(rowId: string) => void` | Toggle expand | -| `expandRow` | `(rowId: string) => void` | Expand a row | -| `collapseRow` | `(rowId: string) => void` | Collapse a row | -| `clearExpansion` | `() => void` | Collapse all | -| `expandedRowIds` | `string[]` | IDs of expanded rows | -| `isExpanded` | `(rowId: string) => boolean` | Check if expanded | - -**`grouping` return:** - -| Property | Type | Description | -|---|---|---| -| `state` | `GroupingState` | Current grouped columns | -| `toggleGrouping` | `(columnId: string) => void` | Toggle group by column | -| `setGrouping` | `(cols: GroupingState) => void` | Set grouping directly | -| `clearGrouping` | `() => void` | Remove all grouping | -| `isGrouped` | `(columnId: string) => boolean` | Check if grouped | -| `groupedColumns` | `string[]` | Currently grouped column IDs | - -**`emptyState` return:** - -| Property | Type | Description | -|---|---|---| -| `isEmpty` | `boolean` | True when data has 0 rows total | -| `isFilteredEmpty` | `boolean` | True when filters return 0 rows | - ---- - -### `createColumns` — Column Definition Helper - -Type-safe column definitions without `useMemo` or manual type annotations. - -```tsx -import { createColumns } from '@marvinackerman/tablecraft' - -const columns = createColumns([ - { accessorKey: 'name', header: 'Name', enableSorting: true }, - { accessorKey: 'email', header: 'Email' }, - { - id: 'actions', - header: 'Actions', - cell: ({ row }) => , - }, -]) -``` - ---- - -### `inferColumns` — Auto Column Inference - -Automatically infers column definitions from your data shape. - -```tsx -import { inferColumns } from '@marvinackerman/tablecraft' - -const columns = inferColumns(users, { - exclude: ['id'], - headers: { name: 'Full Name', role: 'Role' }, -}) -``` - ---- - -### `useServerTable` — Server-side Tables - -Forces `manualPagination` and `manualSorting` to `true`. Use when your backend owns sorting, filtering, and pagination. - -```tsx -import { useServerTable } from '@marvinackerman/tablecraft' - -const { table, pagination, sorting } = useServerTable({ - data: serverData, // current page from your API - columns, - rowCount: totalRows, // required — total rows in the dataset - pagination: { pageSize: 20 }, - onPaginationChange: (updater) => { - const next = typeof updater === 'function' ? updater(currentState) : updater - refetch({ page: next.pageIndex, pageSize: next.pageSize }) - }, - onSortingChange: (updater) => { - const next = typeof updater === 'function' ? updater(currentSort) : updater - refetch({ sort: next }) - }, -}) -``` - ---- - -### `useQueryTable` — TanStack Query Integration - -Combines `useServerTable` with TanStack Query. Automatically re-fetches when sort, page, or filter state changes. - -```tsx -import { useQueryTable } from '@marvinackerman/tablecraft' - -const { table, pagination, sorting, query } = useQueryTable({ - queryKey: ['users'], - queryFn: async ({ pagination, sorting, globalFilter, columnFilters }) => { - const res = await api.getUsers({ - page: pagination.pageIndex, - pageSize: pagination.pageSize, - sort: sorting, - search: globalFilter, - }) - return { data: res.data, rowCount: res.total } - }, - columns, - pagination: { pageSize: 20 }, - sorting: true, - globalFilter: true, -}) -``` - -`query` is the raw TanStack Query result (`isLoading`, `isError`, `isFetching`, `error`, `refetch`, etc.). - -Requires `@tanstack/react-query` to be installed: -``` -npm i @tanstack/react-query -``` - ---- - -### `useInfiniteTable` — Infinite Scroll / Load More - -Cursor-based infinite scroll powered by TanStack Query's `useInfiniteQuery`. Pages are accumulated in a flat list — no pagination controls needed. When sort or filter state changes, accumulated pages automatically reset to page 1 via query key composition. - -```tsx -import { useInfiniteTable } from '@marvinackerman/tablecraft' - -const { table, loadMore, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteTable({ - queryKey: ['users'], - initialPageParam: null as string | null, // TCursor inferred as string | null - queryFn: async ({ pageParam, sorting, globalFilter }) => { - const res = await api.getUsers({ - cursor: pageParam, // pageParam: string | null — fully typed ✓ - sort: sorting, - search: globalFilter, - }) - return { - data: res.data, - nextCursor: res.nextCursor, // string | null | undefined — typed ✓ - } - }, - columns, - sorting: true, - globalFilter: true, -}) - -// In your JSX: - -``` - -All rows across every loaded page are available in `table.getRowModel().rows` as a single flat list — no page tracking on your end. - -**`queryFn` context:** - -| Property | Type | Description | -|---|---|---| -| `pageParam` | `unknown` | Cursor/offset passed to your API. Type is controlled by your `nextCursor` return value | -| `sorting` | `SortingState` | Current sort | -| `columnFilters` | `ColumnFiltersState` | Current column filter values | -| `globalFilter` | `string` | Current global search string | -| `grouping` | `GroupingState` | Current grouping columns | - -**Return:** - -| Property | Type | Description | -|---|---|---| -| `table` | `Table` | Full TanStack Table instance with all accumulated rows | -| `loadMore` | `() => void` | Fetch the next page | -| `hasNextPage` | `boolean` | `true` when `nextCursor` was returned from the last page | -| `isFetchingNextPage` | `boolean` | `true` while a `loadMore` call is in-flight | -| `isLoading` | `boolean` | `true` on the very first fetch | -| `isError` | `boolean` | `true` if the query threw | -| `error` | `Error \| null` | The thrown error, if any | -| `refetch` | `() => void` | Re-run the query from the beginning | -| `sorting` | `SortingReturn` | Same shape as `useTable` | -| `globalFilter` | `GlobalFilterReturn` | Same shape as `useTable` | -| `columnFilters` | `ColumnFiltersReturn` | Same shape as `useTable` | -| `rowSelection` | `RowSelectionReturn` | Opt-in — pass `rowSelection: true` | -| `columnVisibility` | `ColumnVisibilityReturn` | Opt-in — pass `columnVisibility: true` | -| `grouping` | `GroupingReturn` | Opt-in — pass `grouping: true` | -| `emptyState` | `EmptyStateReturn` | Same shape as `useTable` | - -**Options:** - -| Option | Type | Default | Description | -|---|---|---|---| -| `queryKey` | `unknown[]` | required | TanStack Query cache key | -| `queryFn` | `(ctx) => Promise<{ data, nextCursor? }>` | required | Fetcher — return `nextCursor: undefined` to signal last page | -| `columns` | `ColumnDef[]` | required | Column definitions | -| `initialPageParam` | `unknown` | `0` | First value passed as `pageParam` | -| `sorting` | `boolean \| SortingOptions` | `true` | Enable sorting | -| `globalFilter` | `boolean` | `true` | Enable global search | -| `columnFilters` | `boolean` | `true` | Enable column filters | -| `rowSelection` | `boolean \| RowSelectionOptions` | `false` | Enable row selection | -| `columnVisibility` | `boolean \| ColumnVisibilityOptions` | `false` | Enable column visibility | -| `grouping` | `boolean \| GroupingOptions` | `false` | Enable row grouping | -| `staleTime` | `number` | — | TanStack Query `staleTime` | -| `gcTime` | `number` | — | TanStack Query `gcTime` | -| `enabled` | `boolean` | — | TanStack Query `enabled` | - -Requires `@tanstack/react-query`: -``` -npm i @tanstack/react-query -``` - ---- - -### `useInfiniteScroll` — Automatic Scroll Wiring - -Pairs with `useInfiniteTable` to trigger `loadMore` automatically when a sentinel element enters the viewport. Handles observer cleanup, reconnect, and stale-ref prevention internally. - -```tsx -import { useInfiniteScroll } from '@marvinackerman/tablecraft' - -const { table, loadMore, hasNextPage, isFetchingNextPage } = useInfiniteTable({ ... }) - -const sentinelRef = useInfiniteScroll(loadMore, { - enabled: hasNextPage && !isFetchingNextPage, // never double-fires -}) - -return ( - <> - - - {table.getRowModel().rows.map((row) => ( - ... - ))} - -
- - {/* Place sentinel below the last row — fires loadMore as it scrolls into view */} -
- - {isFetchingNextPage &&

Loading more…

} - -) -``` - -**Options:** - -| Option | Type | Default | Description | -|---|---|---|---| -| `enabled` | `boolean` | `true` | Pass `hasNextPage && !isFetchingNextPage` to prevent double-firing | -| `rootMargin` | `string` | `'0px'` | Load ahead of scroll position — e.g. `'200px'` triggers before the sentinel is fully visible | - ---- - -### `useTableA11y` — ARIA + Keyboard Navigation - -Standalone opt-in hook. Returns prop-getter objects to spread onto your table elements, implementing the [WAI-ARIA Grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/). - -```tsx -import { useTableA11y } from '@marvinackerman/tablecraft' - -const { table } = useTable({ data, columns }) -const a11y = useTableA11y(table, { - selectionEnabled: true, // adds aria-selected to row props -}) - -// Spread onto your elements: - - // role="grid", aria-rowcount, aria-colcount - - - // role="row", aria-rowindex, tabIndex, onKeyDown (ArrowUp/Down/Home/End) - // aria-selected (when selectionEnabled), aria-expanded (when expandable) - - - {editable.isEditing(row.id) ? ( - <> - - - - ) : ( - <> - - - - )} - -))} -``` - ---- - -### `useMultiRowEditing` - -Edit, validate, and save multiple rows simultaneously. Per-row save and bulk save both supported. - -```tsx -import { useTable, useMultiRowEditing } from '@marvinackerman/tablecraft' - -const { table } = useTable({ data, columns }) +Sorting, pagination, global search, and full TypeScript generics are all wired up in one call — see the [Getting Started](https:///docs) guide for the complete rendered example. -const { - editingRowIds, - startEditing, - setField, - getDraft, - getErrors, - saveRow, - cancelRow, - saveAll, - cancelAll, - isEditing, - isDirty, - hasUnsavedChanges, - isSavingAll, -} = useMultiRowEditing(table, { - // Called by saveRow() and saveAll() (when onSaveAll is not provided) - onSave: async (rowId, draft) => { - const errors = await api.updateUser(draft) - if (errors) return errors // { name: 'Too long' } keeps row in edit mode - // return void / undefined → row exits edit mode - }, +## What's inside - // Optional: called by saveAll() for a real batch API call - onSaveAll: async (rows) => { - const result = await api.bulkUpdate(rows) - // Return Record — rows with errors stay in edit mode - return result.errors - }, -}) +- **[Getting Started](https:///docs)** — installation, mental model, first table +- **[API Reference](https:///docs/api)** — `useTable`, `useServerTable`, `useQueryTable`, `useInfiniteTable`, `useVirtualRows`, `useEditableRows`, `useMultiRowEditing`, `useTableA11y`, column pinning, devtools, testing utilities, and more +- **[Guides](https:///docs/guides)** — server-side tables, inline editing, Zod-driven columns +- **[Live examples](https:///docs)** — interactive tables rendered directly in the docs -// In your row render: -{rows.map(row => ( - - {isEditing(row.id) ? ( - <> - - - - ) : ( - <> - - - - )} - -))} - -{hasUnsavedChanges && ( - -)} -``` - -#### Options - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `onSave` | `(rowId, draft) => void \| errors \| Promise<...>` | — | Per-row save callback. Return a non-empty errors object to stay in edit mode. | -| `onSaveAll` | `(rows) => void \| Record \| Promise<...>` | — | Batch save callback. If omitted, `saveAll()` calls `onSave` for each dirty row in parallel. | - -#### Return - -| Property | Type | Description | -|----------|------|-------------| -| `editingRowIds` | `string[]` | Rows currently in edit mode | -| `savingRows` | `string[]` | Rows mid per-row save | -| `isSavingAll` | `boolean` | `true` during `saveAll()` | -| `hasUnsavedChanges` | `boolean` | `true` if any row has unsaved changes | -| `startEditing(id)` | `fn` | Enter edit mode for a row (no-op if already editing) | -| `setField(id, field, value)` | `fn` | Update a draft field | -| `saveRow(id)` | `async fn` | Save one row via `onSave` | -| `cancelRow(id)` | `fn` | Discard draft and exit edit mode for one row | -| `saveAll()` | `async fn` | Save all dirty rows | -| `cancelAll()` | `fn` | Discard all drafts and exit edit mode | -| `isEditing(id)` | `fn → boolean` | Is this row in edit mode? | -| `isDirty(id)` | `fn → boolean` | Does this row have unsaved changes? | -| `dirtyFields(id)` | `fn → (keyof TData)[]` | Which fields have changed? | -| `getDraft(id)` | `fn → Partial` | Current draft for a row | -| `getErrors(id)` | `fn → Partial>` | Current field errors for a row | -| `isSavingRow(id)` | `fn → boolean` | Is this row currently being saved? | - ---- - -### `useVirtualRows` - -Render only the rows visible in the viewport — for large datasets where rendering all rows at once causes lag. Requires `@tanstack/react-virtual`: - -```bash -npm install @tanstack/react-virtual -``` - -```tsx -import { useTable, useVirtualRows } from '@marvinackerman/tablecraft' -import { flexRender } from '@tanstack/react-table' - -const { table } = useTable({ data, columns }) - -const { virtualRows, totalHeight, containerRef, scrollToIndex } = useVirtualRows(table, { - rowHeight: 48, -}) - -// Virtualized tables use div-based rendering — position: absolute requires it. -// Use role="row" and role="cell" for screen reader compatibility. -
-
- {virtualRows.map(({ row, start, size }) => ( -
- {row.getVisibleCells().map(cell => ( -
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
- ))} -
- ))} -
-
- -// Works with useTable, useQueryTable, and useInfiniteTable equally. -// To scroll programmatically: -scrollToIndex(42) -``` - -> **Note:** Standard `
- // role="columnheader", aria-sort="ascending"|"descending"|"none" - -
- // role="gridcell", aria-colindex - -// Current focused row index (for custom focus ring styling): -a11y.focusedRowIndex // number | null -``` - -**Keyboard navigation** (applied automatically via `onKeyDown` on row props): - -| Key | Action | -|-----|--------| -| `ArrowDown` | Move focus to next row | -| `ArrowUp` | Move focus to previous row | -| `Home` | Move focus to first row | -| `End` | Move focus to last row | -| `Enter` / `Space` | Toggle row selection (when `selectionEnabled`) | - ---- - -### `useEditableRows` — Inline Editing - -Standalone opt-in hook for single-row inline editing. No form library required — works with Zod, Yup, or plain validation. - -```tsx -import { useEditableRows } from '@marvinackerman/tablecraft' - -const { table } = useTable({ data, columns }) -const editable = useEditableRows(table, { - onSave: async (rowId, draft) => { - // Return an error map to show validation errors and stay in edit mode - if (!draft.name) return { name: 'Name is required' } - - // Or use any schema library - const result = schema.safeParse(draft) - if (!result.success) return formatErrors(result.error) - - // Return nothing (or undefined) to commit and exit edit mode - await api.updateUser(rowId, draft) - }, -}) -``` - -**Return:** - -| Property | Type | Description | -|---|---|---| -| `editingRowId` | `string \| null` | Which row is being edited | -| `draftData` | `Partial` | Current draft field values | -| `isDirty` | `boolean` | Whether any field has changed | -| `dirtyFields` | `(keyof TData)[]` | Which fields changed | -| `errors` | `Partial>` | Field-level validation errors | -| `isSaving` | `boolean` | True while `onSave` promise is in flight | -| `isEditing` | `(rowId: string) => boolean` | Check if a row is in edit mode | -| `startEditing` | `(rowId: string) => void` | Enter edit mode (snapshots original) | -| `setField` | `(field, value) => void` | Update a draft field | -| `saveEditing` | `() => Promise` | Run `onSave`, commit or show errors | -| `cancelEditing` | `() => void` | Discard changes, exit edit mode | - -**Usage in rows:** - -```tsx -{table.getRowModel().rows.map((row) => ( -
- editable.setField('name', e.target.value)} - /> - {editable.errors.name && {editable.errors.name}} - - - - {row.original.name} - -
- setField(row.id, 'name', e.target.value)} - /> - {getErrors(row.id).name && {getErrors(row.id).name}} - - - - {row.original.name}
//` markup is incompatible with virtualization because browsers do not support `position: absolute` inside ``. Use `
`, `
`, and `
` — semantically equivalent for screen readers. - -#### Options - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `rowHeight` | `number` | — (required) | Fixed height of every row in pixels | -| `overscan` | `number` | `5` | Extra rows rendered above and below the visible area to prevent scroll flicker on fast scrolling | - -#### Return - -| Property | Type | Description | -|----------|------|-------------| -| `virtualRows` | `VirtualRow[]` | Only the rows currently visible in the viewport | -| `totalHeight` | `number` | Total scroll height in px — set as the `height` of the inner wrapper div | -| `containerRef` | `RefObject` | Attach to the outer scroll container div | -| `scrollToIndex` | `(index: number) => void` | Programmatically scroll to any row by its position in the full rows array | - -Each `VirtualRow`: - -| Field | Type | Description | -|-------|------|-------------| -| `row` | `Row` | Full TanStack Row — `row.original`, `row.id`, `row.getVisibleCells()`, etc. | -| `index` | `number` | Position in the full rows array | -| `start` | `number` | Pixel offset from top — use as `top` in absolute positioning | -| `size` | `number` | Row height in px (always equals `rowHeight` in fixed mode) | - ---- - -### `TableKitProvider` — Global Defaults - -Set defaults for all tables in your app. Per-call options always override provider defaults. - -```tsx -import { TableKitProvider } from '@marvinackerman/tablecraft' - -function App() { - return ( - - - - ) -} -``` - ---- - -### State Persistence - -Persist table state across page reloads via `localStorage` or `sessionStorage`. - -```tsx -const { table } = useTable({ - data, - columns, - persist: 'localStorage', - persistKey: 'users-table', // unique key per table - persistOptions: { - sorting: true, - pagination: true, - globalFilter: false, - columnFilters: false, - }, -}) -``` - -Utilities for manual control: - -```tsx -import { savePersistedState, loadPersistedState, clearPersistedState } from '@marvinackerman/tablecraft' - -savePersistedState('my-key', state, 'localStorage') -loadPersistedState('my-key', 'localStorage') -clearPersistedState('my-key', 'localStorage') -``` - ---- - -### URL State Sync - -Sync table state (page, sort, filters) to the URL. Works with any router. - -```tsx -const { table } = useTable({ - data, - columns, - syncUrl: true, - // or with custom keys: - syncUrl: { - keys: { page: 'p', pageSize: 'ps', sort: 's', filter: 'q' }, - mode: 'replace', // or 'push' (adds browser history entry) - }, -}) -``` - ---- - -### Granular Hooks - -For advanced setups where you compose your own `useReactTable` call: - -```tsx -import { - useSortState, - usePaginationState, - useFilterState, - useColumnFilterState, - useRowSelectionState, - useColumnVisibilityState, - useRowExpansionState, - useGroupingState, - useColumnPinningState, -} from '@marvinackerman/tablecraft' - -const sorting = useSortState({ defaultSort: [{ id: 'createdAt', desc: true }] }) -const pagination = usePaginationState({ pageSize: 25 }) -const globalFilter = useFilterState() -const columnFilters = useColumnFilterState() -const rowSelection = useRowSelectionState() -const columnVisibility = useColumnVisibilityState({ defaultVisibility: { id: false } }) -const rowExpansion = useRowExpansionState({ allowMultiple: false }) -const grouping = useGroupingState({ defaultGrouping: ['department'] }) -``` - -Each hook returns state + setters compatible with TanStack Table's `state` and `on*Change` props. - ---- - -### Column Pinning - -Pin columns to the left or right edge. TanStack Table provides the pixel offsets — your CSS does the sticking. - -```tsx -const { table, columnPinning } = useTable({ - data, - columns, - columnPinning: true, - // or: columnPinning: { defaultPinning: { left: ['id'] } } -}) - -// Actions -columnPinning.pinLeft('name') -columnPinning.pinRight('email') -columnPinning.unpin('name') -columnPinning.clearPinning() -columnPinning.isPinned('name') // → 'left' | 'right' | false -columnPinning.leftColumns // → ['id'] -columnPinning.rightColumns // → ['email'] - -// Render with sticky CSS -{table.getHeaderGroups().map(headerGroup => ( -
- {(['left', 'center', 'right'] as const).flatMap(position => - (position === 'left' - ? table.getLeftLeafHeaders() - : position === 'right' - ? table.getRightLeafHeaders() - : table.getCenterLeafHeaders() - ).map(header => ( - - )) - )} - -))} -``` - -> `position: sticky` is all CSS. Tablecraft provides the state and pixel offsets (`getStart`, `getAfter`). Your styles do the rest — no UI lock-in. - -Also works in `useQueryTable` and `useInfiniteTable` with the same `columnPinning` option. - -**Options** - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `columnPinning` | `boolean \| ColumnPinningOptions` | `false` | Opt-in column pinning. Pass `true` to enable with defaults, or an object to configure. | - -**`ColumnPinningOptions` properties:** - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `defaultPinning` | `{ left?: string[], right?: string[] }` | `{}` | Columns pinned on mount | - -**`columnPinning` return** - -| Property | Type | Description | -|----------|------|-------------| -| `state` | `ColumnPinningState` | Raw TanStack state | -| `pinLeft(id)` | `fn` | Pin column to left edge | -| `pinRight(id)` | `fn` | Pin column to right edge | -| `unpin(id)` | `fn` | Remove pin from column | -| `clearPinning()` | `fn` | Unpin all columns | -| `isPinned(id)` | `fn → 'left' \| 'right' \| false` | Query pin status | -| `leftColumns` | `string[]` | Currently left-pinned column IDs | -| `rightColumns` | `string[]` | Currently right-pinned column IDs | - ---- - -### Zod Schemas — `@marvinackerman/tablecraft/zod` - -Use one Zod schema as the source of truth for a table's columns *and* its edit validation. Requires `zod` (optional peer, works with Zod 3 and 4): - -``` -npm i zod -``` - -```tsx -import { useTable, useMultiRowEditing } from '@marvinackerman/tablecraft' -import { columnsFromZod, zodValidator } from '@marvinackerman/tablecraft/zod' -import { z } from 'zod' - -const userSchema = z.object({ - name: z.string().min(1, 'Name is required'), - email: z.string().email('Invalid email'), -}) -type User = z.infer - -const columns = columnsFromZod(userSchema) // ColumnDef[] -const validate = zodValidator(userSchema) - -const { table } = useTable({ data, columns }) -const editing = useMultiRowEditing(table, { - onSave: async (rowId, draft) => validate(draft) ?? api.save(rowId, draft), -}) -``` - -**`columnsFromZod(schema, options?)`** — generates headless `{ accessorKey, header }` columns from the schema's top-level fields (headers are humanized: `firstName` → "First Name"). Needs no sample data. Options: `include`, `exclude`, `overrides` — identical to `inferColumns`. - -Fields whose schema directly exposes `.shape` (a nested `z.object`) are skipped. Arrays, records, and optional/nullable-wrapped objects are **not** auto-detected — since `.shape` is `undefined` on `z.array(...)`, `z.record(...)`, and `z.object({...}).optional()` / `.nullable()`, those fields still produce a column. Use `exclude` to remove them. Requires a schema that exposes `.shape`. - -> **`.refine()` behaves differently across Zod majors.** Zod 3 wraps refined schemas so `.shape` is hidden — `columnsFromZod` throws with instructions (pass the base object, or `.innerType()`). Zod 4 keeps `.shape`, so refined schemas work normally. `zodValidator` accepts refined schemas on both. - -**`zodValidator(schema, options?)`** — returns `(row) => errors | undefined`, matching the error-map contract of `useEditableRows` / `useMultiRowEditing`. Returns `undefined` when the row is valid, so it composes directly with `??`. - -Wrapped schemas *are* supported here, so cross-field `.refine()` rules run. Because an object-level issue has no field path, its message is attached to a field so the row stays in edit mode — the first schema field by default, or `rootErrorField`: - -```tsx -const validate = zodValidator(dateRangeSchema, { rootErrorField: 'endDate' }) -``` - -> **Invalid rows are never silently committed.** If the schema rejects a row, the returned map is always non-empty — an empty map would collapse to `undefined` and the row would save despite failing validation. - ---- - -### Devtools - -A floating debug panel showing current table state — sorting, pagination, filters, selection, expansion, grouping. Zero-config, dev-only. - -```tsx -import { TablecraftDevtools } from '@marvinackerman/tablecraft/devtools' - -function MyTable() { - // Devtools takes the whole useTable(...) return value, not just `table` - const tableReturn = useTable({ data, columns }) - const { table } = tableReturn - - return ( - <> - {/* your table */} - {process.env.NODE_ENV === 'development' && ( - - )} - - ) -} -``` - ---- - -### Testing Utilities - -Helpers for testing tables in Vitest / Jest without boilerplate. - -```tsx -import { renderTable } from '@marvinackerman/tablecraft/testing' - -const { table, pagination, sorting } = renderTable({ - data: users, - columns, - pagination: true, - sorting: true, -}) -``` - -Requires `@testing-library/react`: -``` -npm i -D @testing-library/react -``` - ---- - -## TypeScript - -tablecraft is written in strict TypeScript with full generics. Your data type flows through the entire API: - -```tsx -type Product = { id: number; name: string; price: number } - -const columns = createColumns([ - { accessorKey: 'name', header: 'Name' }, - { accessorKey: 'price', header: 'Price' }, -]) - -// table is Table, row.original is Product -const { table } = useTable({ data: products, columns }) -``` - ---- - -## FAQ - -**Does this impose any styles?** -No. tablecraft is 100% headless. Bring your own CSS, Tailwind, shadcn/ui, or anything else. - -**Can I use the raw TanStack Table instance?** -Yes. `useTable` returns the full `Table` instance as `table`. Use it for anything tablecraft doesn't cover. - -**Does it work with shadcn/ui?** -Yes. shadcn's data table is built on TanStack Table. Replace the boilerplate with `useTable` and keep your shadcn components. - -**Does it work with Next.js App Router?** -Yes. All hooks include `"use client"` directives. `createColumns` and `inferColumns` are pure functions that work anywhere. - -**What's the bundle size?** -tablecraft's own code is **~4 KB min+gzip** for the core (`useTable` + `createColumns`), or **~16 KB min+gzip** if you import the entire library. It's fully tree-shakeable, so you only pay for the hooks you actually import. That sits on top of `@tanstack/react-table` (~14 KB min+gzip), which you'd need anyway — so a typical setup ships **~18 KB gzipped total**. Compare that to AG Grid (~300 KB) or Material React Table (~50 KB). - -**Does it support React 19?** -Yes. Tested against React 18 and 19. - ---- - -## Optional Peer Dependencies - -| Package | Feature | -|---------|---------| -| `match-sorter` | Fuzzy search (`fuzzy: true` on `useTable`) — loaded via `require()`, so CJS/Node environments only. In ESM-only bundlers (e.g. Vite), pass a custom `FilterFn` as `fuzzy` instead; no dependency needed. | -| `@tanstack/react-query` | `useQueryTable` | -| `@testing-library/react` | `tablecraft/testing` utilities | -| `@tanstack/react-virtual` | `useVirtualRows` | -| `zod` | `tablecraft/zod` — `columnsFromZod`, `zodValidator` (Zod 3 and 4) | - ---- - -## Roadmap - -- **v2** — Row expansion, grouping + aggregation, ARIA + keyboard navigation, inline editing, TanStack Query integration (`useQueryTable`), URL state sync, state persistence, devtools, testing utilities -- **v2.1** — Infinite scroll (`useInfiniteTable`) -- **v3** — Column pinning, multi-row editing, Zod column schemas, CLI scaffold - ---- +> **Using shadcn/ui?** Its data table is built on TanStack Table. Swap the boilerplate for `useTable` and keep every one of your components — tablecraft ships zero markup and zero styles. ## License From c8c0211fbdeae0daa612c7c86e40e2033d727da2 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:14:58 +0000 Subject: [PATCH 28/29] docs: fix README peer deps to match installation docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6303be1..a9a62bb 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,10 @@ tablecraft collapses the 80–150 lines of `useState`/`useMemo` boilerplate that ## Install ``` -npm i @marvinackerman/tablecraft @tanstack/react-table@^8 react@^18 +npm i @marvinackerman/tablecraft @tanstack/react-table@">=8" @tanstack/react-virtual@">=3" react@">=18" react-dom@">=18" ``` -`@tanstack/react-virtual` (`^3`) is an optional peer, needed only for `useVirtualRows`. `zod` (`>=3.23`) is an optional peer for the `tablecraft/zod` entry point. See the [Installation guide](https:///docs/getting-started/installation) for the full optional-peer matrix. +`@tanstack/react-table`, `react`/`react-dom`, and `@tanstack/react-virtual` are all required peers — the core entry statically imports react-virtual. Optional peers, installed only as you reach for the feature they back: `zod` (`>=3.23.0`, for the `tablecraft/zod` entry), `@tanstack/react-query` (for `useQueryTable`/`useInfiniteTable`), and `match-sorter` (fuzzy search). See the [Installation guide](https:///docs/getting-started/installation) for details. ## Quick start From 07fc8adb91c917187e52ab0183afee1739999399 Mon Sep 17 00:00:00 2001 From: Marvinkwame Date: Sun, 26 Jul 2026 19:29:31 +0000 Subject: [PATCH 29/29] docs: correct README doc-link paths and add installation description --- README.md | 8 +++++--- www/content/docs/installation.mdx | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a9a62bb..b75312a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ tablecraft collapses the 80–150 lines of `useState`/`useMemo` boilerplate that npm i @marvinackerman/tablecraft @tanstack/react-table@">=8" @tanstack/react-virtual@">=3" react@">=18" react-dom@">=18" ``` -`@tanstack/react-table`, `react`/`react-dom`, and `@tanstack/react-virtual` are all required peers — the core entry statically imports react-virtual. Optional peers, installed only as you reach for the feature they back: `zod` (`>=3.23.0`, for the `tablecraft/zod` entry), `@tanstack/react-query` (for `useQueryTable`/`useInfiniteTable`), and `match-sorter` (fuzzy search). See the [Installation guide](https:///docs/getting-started/installation) for details. +`@tanstack/react-table`, `react`/`react-dom`, and `@tanstack/react-virtual` are all required peers — the core entry statically imports react-virtual. Optional peers, installed only as you reach for the feature they back: `zod` (`>=3.23.0`, for the `tablecraft/zod` entry), `@tanstack/react-query` (for `useQueryTable`/`useInfiniteTable`), and `match-sorter` (fuzzy search). See the [Installation guide](https:///docs/installation) for details. ## Quick start @@ -41,8 +41,10 @@ Sorting, pagination, global search, and full TypeScript generics are all wired u ## What's inside - **[Getting Started](https:///docs)** — installation, mental model, first table -- **[API Reference](https:///docs/api)** — `useTable`, `useServerTable`, `useQueryTable`, `useInfiniteTable`, `useVirtualRows`, `useEditableRows`, `useMultiRowEditing`, `useTableA11y`, column pinning, devtools, testing utilities, and more -- **[Guides](https:///docs/guides)** — server-side tables, inline editing, Zod-driven columns +- **[Installation](https:///docs/installation)** — required and optional peer dependencies +- **[API Reference](https:///docs/api/use-table)** — `useTable`, `useServerTable`, `useQueryTable`, `useInfiniteTable`, `useVirtualRows`, `useEditableRows`, `useMultiRowEditing`, `useTableA11y`, column pinning, devtools, testing utilities, and more +- **[Guides](https:///docs/guides/inline-editing)** — server-side tables, inline editing +- **[Zod-driven columns](https:///docs/api/zod)** — derive columns and edit validation from a single schema - **[Live examples](https:///docs)** — interactive tables rendered directly in the docs > **Using shadcn/ui?** Its data table is built on TanStack Table. Swap the boilerplate for `useTable` and keep every one of your components — tablecraft ships zero markup and zero styles. diff --git a/www/content/docs/installation.mdx b/www/content/docs/installation.mdx index c100513..04a1954 100644 --- a/www/content/docs/installation.mdx +++ b/www/content/docs/installation.mdx @@ -1,5 +1,6 @@ --- title: Installation +description: Required and optional peer dependencies for tablecraft, and which feature each optional peer unlocks. --- ## Install
- {flexRender(header.column.columnDef.header, header.getContext())} -