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/ diff --git a/README.md b/README.md index c86a5e9..b75312a 100644 --- a/README.md +++ b/README.md @@ -5,1083 +5,49 @@ > 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" @tanstack/react-virtual@">=3" react@">=18" react-dom@">=18" ``` -## Quick Start +`@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 ```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 +- **[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 -// 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 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/**'], }, }) 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..96bf1c8 --- /dev/null +++ b/www/app/global.css @@ -0,0 +1,58 @@ +@import 'tailwindcss'; +@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: #1a1a20; + --color-fd-accent-foreground: #ededf2; + --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; +} + +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..23e9e9a --- /dev/null +++ b/www/app/layout.tsx @@ -0,0 +1,32 @@ +import { RootProvider } from 'fumadocs-ui/provider/next'; +import './global.css'; +import { Manrope, JetBrains_Mono, Bricolage_Grotesque } from 'next/font/google'; + +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} + + + ); +} 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/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 ( +
+
- {flexRender(header.column.columnDef.header, header.getContext())} -
+ + {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/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 ? ( +
+ + +
+ ) : ( + + )} +
+
+ ) +} 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. +

+
+ ) +} 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 }, +] 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/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/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/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/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() +``` 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' }` 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-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-table.mdx b/www/content/docs/api/use-table.mdx new file mode 100644 index 0000000..766da27 --- /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 `{ 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? }` | +| `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`. 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..cbda02a --- /dev/null +++ b/www/content/docs/api/use-virtual-rows.mdx @@ -0,0 +1,100 @@ +--- +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`: + +```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 + +> **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, pagination: false }) + +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) +``` + +## 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. +- Works with [`useTable`](/docs/api/use-table), [`useQueryTable`](/docs/api/use-query-table), and [`useInfiniteTable`](/docs/api/use-infinite-table) equally. 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. diff --git a/www/content/docs/guides/inline-editing.mdx b/www/content/docs/guides/inline-editing.mdx new file mode 100644 index 0000000..55e2c57 --- /dev/null +++ b/www/content/docs/guides/inline-editing.mdx @@ -0,0 +1,135 @@ +--- +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 +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`. + + + +## 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). diff --git a/www/content/docs/index.mdx b/www/content/docs/index.mdx new file mode 100644 index 0000000..d1c66dc --- /dev/null +++ b/www/content/docs/index.mdx @@ -0,0 +1,50 @@ +--- +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 + +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: + + diff --git a/www/content/docs/installation.mdx b/www/content/docs/installation.mdx new file mode 100644 index 0000000..04a1954 --- /dev/null +++ b/www/content/docs/installation.mdx @@ -0,0 +1,49 @@ +--- +title: Installation +description: Required and optional peer dependencies for tablecraft, and which feature each optional peer unlocks. +--- + +## 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` `>=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. | + +## 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`. | 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"] +} 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..9a61aee --- /dev/null +++ b/www/next.config.mjs @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url'; +import { createMDX } from 'fumadocs-mdx/next'; + +const withMDX = createMDX(); + +/** @type {import('next').NextConfig} */ +const config = { + reactStrictMode: true, + turbopack: { + root: fileURLToPath(new URL('.', import.meta.url)), + }, +}; + +export default withMDX(config); diff --git a/www/package-lock.json b/www/package-lock.json new file mode 100644 index 0000000..0ff2e60 --- /dev/null +++ b/www/package-lock.json @@ -0,0 +1,6254 @@ +{ + "name": "tablecraft-docs", + "version": "0.0.8", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "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", + "fumadocs-ui": "^16.12.1", + "lucide-react": "^1.25.0", + "next": "16.2.11", + "react": "^19.2.8", + "react-dom": "^19.2.8", + "zod": "^3.25.76" + }, + "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/@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", + "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/@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", + "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==", + "dev": 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==", + "dev": 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==", + "dev": 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-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", + "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==", + "dev": 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": "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" + } + }, + "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..dabf9a7 --- /dev/null +++ b/www/package.json @@ -0,0 +1,36 @@ +{ + "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": { + "@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", + "fumadocs-ui": "^16.12.1", + "lucide-react": "^1.25.0", + "next": "16.2.11", + "react": "^19.2.8", + "react-dom": "^19.2.8", + "zod": "^3.25.76" + }, + "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"] +}