@vexcms/next 0.1.0-alpha.2 → 0.1.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +59 -48
  2. package/dist/NextAdminLayout.d.ts +14 -23
  3. package/dist/NextAdminLayout.d.ts.map +1 -1
  4. package/dist/NextAdminLayout.js +3 -20
  5. package/dist/NextAdminLayout.js.map +1 -1
  6. package/dist/NextAdminLayoutClient.d.ts +10 -11
  7. package/dist/NextAdminLayoutClient.d.ts.map +1 -1
  8. package/dist/NextAdminLayoutClient.js +6 -7
  9. package/dist/NextAdminLayoutClient.js.map +1 -1
  10. package/dist/NextAdminPage.d.ts +7 -5
  11. package/dist/NextAdminPage.d.ts.map +1 -1
  12. package/dist/NextAdminPage.js +2 -137
  13. package/dist/NextAdminPage.js.map +1 -1
  14. package/dist/cache/createVexRevalidateRoute.d.ts +88 -0
  15. package/dist/cache/createVexRevalidateRoute.d.ts.map +1 -0
  16. package/dist/cache/createVexServerClient.d.ts +31 -0
  17. package/dist/cache/createVexServerClient.d.ts.map +1 -0
  18. package/dist/cache/index.d.ts +5 -0
  19. package/dist/cache/index.d.ts.map +1 -0
  20. package/dist/cache/index.js +9 -0
  21. package/dist/cache/index.js.map +1 -0
  22. package/dist/cache/types.d.ts +36 -0
  23. package/dist/cache/types.d.ts.map +1 -0
  24. package/dist/chunk-3J7LCKFC.js +129 -0
  25. package/dist/chunk-3J7LCKFC.js.map +1 -0
  26. package/dist/chunk-K4AAS5B5.js +22 -0
  27. package/dist/chunk-K4AAS5B5.js.map +1 -0
  28. package/dist/chunk-KIRSFMPI.js +78 -0
  29. package/dist/chunk-KIRSFMPI.js.map +1 -0
  30. package/dist/chunk-L6N3D6L5.js +155 -0
  31. package/dist/chunk-L6N3D6L5.js.map +1 -0
  32. package/dist/index.d.ts +10 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +48 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/seo/createVexRobots.d.ts +22 -0
  37. package/dist/seo/createVexRobots.d.ts.map +1 -0
  38. package/dist/seo/createVexSitemap.d.ts +41 -0
  39. package/dist/seo/createVexSitemap.d.ts.map +1 -0
  40. package/dist/seo/index.d.ts +5 -0
  41. package/dist/seo/index.d.ts.map +1 -0
  42. package/dist/seo/index.js +13 -0
  43. package/dist/seo/index.js.map +1 -0
  44. package/dist/seo/vexMetadata.d.ts +30 -0
  45. package/dist/seo/vexMetadata.d.ts.map +1 -0
  46. package/dist/seo/vexStaticParams.d.ts +25 -0
  47. package/dist/seo/vexStaticParams.d.ts.map +1 -0
  48. package/dist/testing/index.d.ts +2 -0
  49. package/dist/testing/index.d.ts.map +1 -0
  50. package/dist/testing/index.js +3 -0
  51. package/dist/testing/index.js.map +1 -0
  52. package/package.json +25 -5
package/README.md CHANGED
@@ -1,87 +1,98 @@
1
- # @vexcms/admin-next
1
+ # @vexcms/next
2
2
 
3
- The admin panel for [VEX CMS](https://github.com/ianyimi/vex), built for Next.js. Provides a complete content management interface with collection CRUD, media management, versioning, live preview, access control, and user impersonation.
3
+ The Next.js adapter for [VEX CMS](https://github.com/ianyimi/vex). Provides the server and client components that render the admin panel — collection CRUD, media management, and role-based access control — plus config functions re-exported from `@vexcms/react`.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- pnpm add @vexcms/admin-next
8
+ pnpm add @vexcms/next@alpha
9
9
  ```
10
10
 
11
11
  ## Quick Setup
12
12
 
13
13
  ```tsx
14
- // app/admin/[[...path]]/page.tsx
15
- import { AdminLayout, AdminPage } from "@vexcms/admin-next"
14
+ // app/admin/clientProviders.tsx
15
+ "use client"
16
+ import { VexConfigProvider } from "@vexcms/react"
16
17
  import config from "@/vex.config"
17
18
 
18
- export default function Admin({ params }) {
19
+ export function ClientProviders({ children }: { children: React.ReactNode }) {
20
+ return <VexConfigProvider config={config}>{children}</VexConfigProvider>
21
+ }
22
+ ```
23
+
24
+ ```tsx
25
+ // app/admin/layout.tsx
26
+ import { NextAdminLayout } from "@vexcms/next/client"
27
+ import { getCurrentUser } from "@/auth/serverUtils"
28
+
29
+ import { ClientProviders } from "./clientProviders"
30
+
31
+ export default async function AdminRootLayout({ children }: { children: React.ReactNode }) {
32
+ const user = await getCurrentUser()
19
33
  return (
20
- <AdminLayout config={config} user={user}>
21
- <AdminPage config={config} path={params.path} />
22
- </AdminLayout>
34
+ <ClientProviders>
35
+ <NextAdminLayout user={user ?? undefined}>{children}</NextAdminLayout>
36
+ </ClientProviders>
23
37
  )
24
38
  }
25
39
  ```
26
40
 
41
+ ```tsx
42
+ // app/admin/[[...path]]/page.tsx
43
+ import { NextAdminPage } from "@vexcms/next/server"
44
+ import config from "@/vex.config.server"
45
+
46
+ export default function AdminPage({
47
+ params,
48
+ }: {
49
+ params: Promise<{ path?: string[] }>
50
+ }) {
51
+ return <NextAdminPage config={config} params={params} />
52
+ }
53
+ ```
54
+
55
+ `NextAdminPage` and `NextAdminLayout` are exported from separate subpaths (`/server` and `/client`) rather than the package root, because an async server component and a `"use client"` component cannot share one bundle.
56
+
27
57
  ## Features
28
58
 
29
59
  ### Collection Management
30
60
 
31
- - **List view** — Paginated data table with search, sorting, bulk delete, and configurable columns
32
- - **Edit view** — Auto-generated forms from collection schema with field validation via TanStack React Form
33
- - **Create/delete** — Dialogs for document creation and deletion with permission checks
34
- - **Bidirectional pagination** — Instant access to first and last pages
61
+ - **List view** — Data table with Load More pagination, row selection, and bulk delete
62
+ - **Edit view** — Auto-generated forms from the collection schema, submitted via TanStack React Form
63
+ - **Create dialog** — Modal for document creation, gated by a `create` permission check
35
64
 
36
65
  ### Media Management
37
66
 
38
67
  - **Grid/list views** — Browse media files with thumbnails
39
- - **Upload** — Drag-and-drop upload with file type detection
40
- - **Media picker** — Inline picker for upload and relationship fields with search and pagination
41
- - **Image dimensions** — Auto-detected on upload
42
-
43
- ### Versioning & Drafts
68
+ - **Upload** — Drag-and-drop or click-to-upload through the collection's configured storage adapter
69
+ - **Media picker** — Inline picker for upload fields, with a client-side search filter and Load More pagination
44
70
 
45
- - **Draft/publish workflow** — Status badges, publish/unpublish actions
46
- - **Version history** — Dropdown to view, restore, or delete previous versions
47
- - **Autosave** — Configurable auto-save interval for draft documents
71
+ ### Roadmap note
48
72
 
49
- ### Live Preview
50
-
51
- - **Side-by-side panel** — Preview content changes in an iframe alongside the editor
52
- - **Responsive breakpoints** — Test at different screen sizes
53
- - **Snapshot system** — Transient preview data without saving to database
73
+ Versioning, drafts, and live preview are not implemented yet — both are in progress on the [roadmap](https://docs.vexcms.dev). A global's `versions.drafts` option parses and is stored on the resolved config, but it is not enforced: every read still returns the live document. See [docs.vexcms.dev](https://docs.vexcms.dev) for current status.
54
74
 
55
75
  ### Access Control
56
76
 
57
- - **Permission provider** — React context for role-based access control
58
- - **Field-level permissions** — Read-only fields based on user roles
59
- - **Collection-level permissions** — Control create, read, update, delete per collection
60
- - **UI enforcement** — Buttons and actions hidden/disabled based on permissions
61
-
62
- ### User Impersonation
63
-
64
- - **Impersonation banner** — Shows when an admin is viewing as another user
65
- - **User switching** — Select from impersonatable users list
77
+ - **Config provider** — `VexConfigProvider` (`@vexcms/react`) supplies the resolved client config — including `access` and `storage.clientUploads` — to the admin panel via React context, mounted once by your app around the admin route
78
+ - **Collection-level permissions** — `usePermission` gates create, read, update, and delete per collection and per global
79
+ - **Field-level permissions** — a per-field access rule hides a read-denied input entirely and renders an update-denied one read-only; edit forms submit only the fields the user actually changed
80
+ - **UI enforcement** — Buttons and actions are disabled or hidden when the current user lacks permission
66
81
 
67
82
  ### Admin Layout
68
83
 
69
- - **Sidebar navigation** — Collections grouped by `admin.group`, with auth and media sections
70
- - **Theme support** — Light/dark mode
71
- - **User menu** — Profile, sign out, impersonation controls
84
+ - **Sidebar navigation** — Links grouped into Collections, Globals, and Media sections
85
+ - **Theme support** — Light, dark, and system modes via `ThemeToggle`
72
86
 
73
87
  ## Exports
74
88
 
75
- | Export | Description |
76
- |--------|-------------|
77
- | `AdminPage` | Main routing component — renders the correct view based on URL path |
78
- | `AdminLayout` | Server-side layout wrapper with sidebar and theme |
79
- | `PermissionProvider` | React context provider for RBAC |
80
- | `usePermission` | Hook to check a single action permission |
81
- | `usePermissions` | Hook to check all CRUD permissions for a resource |
82
- | `usePermissionContext` | Hook to access the full permission context |
83
- | `ImpersonationBanner` | Banner component for admin impersonation |
84
- | `useMediaPickerState` | Hook for media picker state management |
89
+ | Export | From | Description |
90
+ |--------|------|-------------|
91
+ | `NextAdminPage` | `@vexcms/next/server` | Async server component that routes the admin panel by URL path (dashboard, list, edit) |
92
+ | `NextAdminLayout` | `@vexcms/next/client` | Client component rendering the admin shell (sidebar, theme, breadcrumbs) around page content |
93
+ | `defineConfig`, `defineCollection`, `relationship`, `text`, `number`, `select`, `date`, `url`, `checkbox` | `@vexcms/next` | Config functions re-exported from `@vexcms/react` |
94
+
95
+ The compiled stylesheet is available at `@vexcms/next/styles`.
85
96
 
86
97
  ## Peer Dependencies
87
98
 
@@ -1,43 +1,35 @@
1
1
  import type { ReactNode } from "react";
2
- import type { VexConfig } from "@vexcms/core";
3
2
  import type { AdminUser } from "@vexcms/react";
4
3
  /**
5
4
  * Next.js admin layout shell for VexCMS.
6
5
  *
7
- * A **server component** that sits on the server→client boundary for the admin
8
- * panel. It sanitizes the resolved `vex.config` with `sanitizeConfigForClient`
9
- * — stripping storage adapter class instances, functions, and React components
10
- * — *before* the config is handed to the client leaf `NextAdminLayoutClient`.
11
- *
12
- * This placement is the whole point: React serializes props when a server
13
- * component renders a client component, so the sanitize **must** happen on the
14
- * server side of that edge. Sanitizing inside the client component would run
15
- * too late — the raw config would already have failed to serialize.
16
- *
17
- * The client leaf handles everything that needs the browser (`usePathname`,
18
- * `NuqsAdapter`, `NextLink`/`NextImage`); this wrapper does no client work.
6
+ * A **server component** that reads the `sidebar_state` cookie server-side
7
+ * (so the sidebar's open/closed state is correct on first paint, with no
8
+ * client flash) and passes it, plus `user`/`organization`/`children`, to the
9
+ * client leaf `NextAdminLayoutClient`. Config no longer crosses this
10
+ * boundary at all — the admin panel's client tree gets its config from the
11
+ * app's own `VexConfigProvider` mount (`clientProviders.tsx`), not from a
12
+ * prop threaded through this layout.
19
13
  *
20
14
  * Render it from your admin `layout.tsx`. Because this is a server component,
21
15
  * your `layout.tsx` may itself be an `async` server component (e.g. to run auth
22
- * checks) and pass the **raw** `vex.config` straight through — no sanitize
23
- * needed on the application side.
24
- *
25
- * @param props - Layout props
26
- * @param props.config - The resolved VexCMS config from `vex.config.ts` (raw)
27
- * @param props.children - The page content from `[[...slug]]/page.tsx`
28
- * @param props.user - Current user for the admin shell
16
+ * checks).
29
17
  *
18
+ * @param props - Layout props.
19
+ * @param props.children - The page content from `[[...slug]]/page.tsx`.
20
+ * @param props.user - Current user for the admin shell.
21
+ * @returns The rendered admin shell, wrapping `children` in the client boundary
22
+ * ({@link NextAdminLayoutClient}) with the server-read sidebar cookie state.
30
23
  * @example
31
24
  * ```tsx
32
25
  * // app/admin/layout.tsx
33
26
  * import { NextAdminLayout } from "@vexcms/next/client";
34
- * import config from "~/vex.config";
35
27
  * import { getCurrentUser } from "~/auth/serverUtils";
36
28
  *
37
29
  * export default async function AdminLayout({ children }: { children: ReactNode }) {
38
30
  * const user = await getCurrentUser();
39
31
  * return (
40
- * <NextAdminLayout config={config} user={user ?? undefined}>
32
+ * <NextAdminLayout user={user ?? undefined}>
41
33
  * {children}
42
34
  * </NextAdminLayout>
43
35
  * );
@@ -45,7 +37,6 @@ import type { AdminUser } from "@vexcms/react";
45
37
  * ```
46
38
  */
47
39
  export declare function NextAdminLayout(props: {
48
- config: VexConfig;
49
40
  children: ReactNode;
50
41
  user?: AdminUser;
51
42
  organization?: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"NextAdminLayout.d.ts","sourceRoot":"","sources":["../src/NextAdminLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC,wCAmBA"}
1
+ {"version":3,"file":"NextAdminLayout.d.ts","sourceRoot":"","sources":["../src/NextAdminLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC,wCAaA"}
@@ -1,23 +1,6 @@
1
- // src/NextAdminLayout.tsx
2
- import { sanitizeConfigForClient } from "@vexcms/core";
3
- import { NextAdminLayoutClient } from "./NextAdminLayoutClient";
4
- import { cookies } from "next/headers";
5
- import { jsx } from "react/jsx-runtime";
6
- async function NextAdminLayout(props) {
7
- const clientConfig = sanitizeConfigForClient(props.config);
8
- const cookieStore = await cookies();
9
- const sidebarOpen = String(cookieStore.get("sidebar_state")?.value) === "true";
10
- return /* @__PURE__ */ jsx(
11
- NextAdminLayoutClient,
12
- {
13
- config: clientConfig,
14
- user: props.user,
15
- organization: props.organization,
16
- sidebarOpen,
17
- children: props.children
18
- }
19
- );
20
- }
1
+ import {
2
+ NextAdminLayout
3
+ } from "./chunk-K4AAS5B5.js";
21
4
  export {
22
5
  NextAdminLayout
23
6
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/NextAdminLayout.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { VexConfig } from \"@vexcms/core\";\nimport { sanitizeConfigForClient } from \"@vexcms/core\";\nimport type { AdminUser } from \"@vexcms/react\";\nimport { NextAdminLayoutClient } from \"./NextAdminLayoutClient\";\nimport { cookies } from \"next/headers\";\n\n/**\n * Next.js admin layout shell for VexCMS.\n *\n * A **server component** that sits on the server→client boundary for the admin\n * panel. It sanitizes the resolved `vex.config` with `sanitizeConfigForClient`\n * — stripping storage adapter class instances, functions, and React components\n * — *before* the config is handed to the client leaf `NextAdminLayoutClient`.\n *\n * This placement is the whole point: React serializes props when a server\n * component renders a client component, so the sanitize **must** happen on the\n * server side of that edge. Sanitizing inside the client component would run\n * too late — the raw config would already have failed to serialize.\n *\n * The client leaf handles everything that needs the browser (`usePathname`,\n * `NuqsAdapter`, `NextLink`/`NextImage`); this wrapper does no client work.\n *\n * Render it from your admin `layout.tsx`. Because this is a server component,\n * your `layout.tsx` may itself be an `async` server component (e.g. to run auth\n * checks) and pass the **raw** `vex.config` straight through — no sanitize\n * needed on the application side.\n *\n * @param props - Layout props\n * @param props.config - The resolved VexCMS config from `vex.config.ts` (raw)\n * @param props.children - The page content from `[[...slug]]/page.tsx`\n * @param props.user - Current user for the admin shell\n *\n * @example\n * ```tsx\n * // app/admin/layout.tsx\n * import { NextAdminLayout } from \"@vexcms/next/client\";\n * import config from \"~/vex.config\";\n * import { getCurrentUser } from \"~/auth/serverUtils\";\n *\n * export default async function AdminLayout({ children }: { children: ReactNode }) {\n * const user = await getCurrentUser();\n * return (\n * <NextAdminLayout config={config} user={user ?? undefined}>\n * {children}\n * </NextAdminLayout>\n * );\n * }\n * ```\n */\nexport async function NextAdminLayout(props: {\n config: VexConfig;\n children: ReactNode;\n user?: AdminUser;\n organization?: Record<string, unknown>;\n}) {\n // Sanitize on the SERVER side of the server→client boundary, before the\n // config is serialized as a prop into the client leaf. This removes the\n // storage adapter class instances that would otherwise crash RSC\n // serialization (\"Classes or null prototypes are not supported\").\n const clientConfig = sanitizeConfigForClient(props.config);\n const cookieStore = await cookies();\n const sidebarOpen = String(cookieStore.get(\"sidebar_state\")?.value) === \"true\";\n\n return (\n <NextAdminLayoutClient\n config={clientConfig}\n user={props.user}\n organization={props.organization}\n sidebarOpen={sidebarOpen}\n >\n {props.children}\n </NextAdminLayoutClient>\n );\n}\n"],"mappings":";AAEA,SAAS,+BAA+B;AAExC,SAAS,6BAA6B;AACtC,SAAS,eAAe;AA4DpB;AAfJ,eAAsB,gBAAgB,OAKnC;AAKD,QAAM,eAAe,wBAAwB,MAAM,MAAM;AACzD,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,cAAc,OAAO,YAAY,IAAI,eAAe,GAAG,KAAK,MAAM;AAExE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ;AAAA,MACR,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB;AAAA,MAEC,gBAAM;AAAA;AAAA,EACT;AAEJ;","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,5 +1,4 @@
1
1
  import type { ReactNode } from "react";
2
- import type { ClientVexConfig } from "@vexcms/core";
3
2
  import { type AdminUser } from "@vexcms/react";
4
3
  /**
5
4
  * Client leaf for the Next.js admin layout.
@@ -12,24 +11,24 @@ import { type AdminUser } from "@vexcms/react";
12
11
  * - `NextLink` / `NextImage` passed as framework components so every
13
12
  * `VexLink`/`VexImage` uses Next.js routing and image optimisation.
14
13
  *
15
- * **Receives an already-sanitized `ClientVexConfig`.** The server wrapper
16
- * ({@link NextAdminLayout}) calls `sanitizeConfigForClient` before this
17
- * component is reached, so no non-serializable values (storage adapter class
18
- * instances, functions, React components) cross the server→client boundary.
14
+ * Config reaches `AdminLayout`'s children through the app's own
15
+ * `VexConfigProvider` mount, not through a prop on this component — this
16
+ * leaf never touches config at all.
19
17
  *
20
18
  * This component is internal to `@vexcms/next` — applications render
21
19
  * {@link NextAdminLayout} instead.
22
20
  *
23
- * @param props - Layout props
24
- * @param props.config - Sanitized config, safe to serialize across the boundary
25
- * @param props.children - The page content from `[[...slug]]/page.tsx`
26
- * @param props.user - Current user for the admin shell
21
+ * @param props - Layout props.
22
+ * @param props.children - The page content from `[[...slug]]/page.tsx`.
23
+ * @param props.user - Current user for the admin shell.
24
+ * @returns The admin shell rendered from `children`, wrapped in `NuqsAdapter`
25
+ * and the shared `AdminLayout`, wired with the active slug/document id derived
26
+ * from `usePathname()` and Next.js `Link`/`Image` components.
27
27
  */
28
28
  export declare function NextAdminLayoutClient(props: {
29
- config: ClientVexConfig;
30
29
  children: ReactNode;
31
- user?: AdminUser;
32
30
  organization?: Record<string, unknown>;
33
31
  sidebarOpen?: boolean;
32
+ user?: AdminUser;
34
33
  }): import("react").JSX.Element;
35
34
  //# sourceMappingURL=NextAdminLayoutClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NextAdminLayoutClient.d.ts","sourceRoot":"","sources":["../src/NextAdminLayoutClient.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKpD,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAwBA"}
1
+ {"version":3,"file":"NextAdminLayoutClient.d.ts","sourceRoot":"","sources":["../src/NextAdminLayoutClient.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAM5D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,+BAuBA"}
@@ -2,11 +2,11 @@
2
2
  "use client";
3
3
 
4
4
  // src/NextAdminLayoutClient.tsx
5
- import { usePathname } from "next/navigation";
6
- import NextLink from "next/link";
5
+ import { AdminLayout } from "@vexcms/react";
7
6
  import NextImage from "next/image";
7
+ import NextLink from "next/link";
8
+ import { usePathname } from "next/navigation";
8
9
  import { NuqsAdapter } from "nuqs/adapters/next/app";
9
- import { AdminLayout } from "@vexcms/react";
10
10
  import { jsx } from "react/jsx-runtime";
11
11
  function NextAdminLayoutClient(props) {
12
12
  const pathname = usePathname();
@@ -16,14 +16,13 @@ function NextAdminLayoutClient(props) {
16
16
  return /* @__PURE__ */ jsx(NuqsAdapter, { children: /* @__PURE__ */ jsx(
17
17
  AdminLayout,
18
18
  {
19
- config: props.config,
19
+ activeDocID,
20
20
  activeSlug,
21
21
  components: { Link: NextLink, Image: NextImage },
22
- pathname,
23
- activeDocID,
24
- user: props.user,
25
22
  organization: props.organization,
23
+ pathname,
26
24
  sidebarOpen: props.sidebarOpen,
25
+ user: props.user,
27
26
  children: props.children
28
27
  }
29
28
  ) });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/NextAdminLayoutClient.tsx"],"sourcesContent":["\"use client\";\n// \"use client\" is injected by the tsup build banner for this entry (see\n// tsup.config.ts) so the emitted module carries the client boundary.\nimport type { ReactNode } from \"react\";\nimport type { ClientVexConfig } from \"@vexcms/core\";\nimport { usePathname } from \"next/navigation\";\nimport NextLink from \"next/link\";\nimport NextImage from \"next/image\";\nimport { NuqsAdapter } from \"nuqs/adapters/next/app\";\nimport { AdminLayout, type AdminUser } from \"@vexcms/react\";\n\n/**\n * Client leaf for the Next.js admin layout.\n *\n * Owns all client-only wiring that cannot run on the server:\n * - `usePathname()` to derive the active collection slug / document id for\n * sidebar highlighting (Next.js layouts do not receive route params).\n * - `NuqsAdapter` (`nuqs/adapters/next/app`) so URL state works inside the\n * admin routes.\n * - `NextLink` / `NextImage` passed as framework components so every\n * `VexLink`/`VexImage` uses Next.js routing and image optimisation.\n *\n * **Receives an already-sanitized `ClientVexConfig`.** The server wrapper\n * ({@link NextAdminLayout}) calls `sanitizeConfigForClient` before this\n * component is reached, so no non-serializable values (storage adapter class\n * instances, functions, React components) cross the server→client boundary.\n *\n * This component is internal to `@vexcms/next` — applications render\n * {@link NextAdminLayout} instead.\n *\n * @param props - Layout props\n * @param props.config - Sanitized config, safe to serialize across the boundary\n * @param props.children - The page content from `[[...slug]]/page.tsx`\n * @param props.user - Current user for the admin shell\n */\nexport function NextAdminLayoutClient(props: {\n config: ClientVexConfig;\n children: ReactNode;\n user?: AdminUser;\n organization?: Record<string, unknown>;\n sidebarOpen?: boolean;\n}) {\n const pathname = usePathname();\n // pathname: \"/admin\", \"/admin/posts\", \"/admin/posts/123\"\n // Split on \"/\" and take the segment after \"admin\"\n const segments = pathname.split(\"/\").filter(Boolean);\n const activeSlug = segments[1]; // undefined on /admin, \"posts\" on /admin/posts\n const activeDocID = segments[2];\n\n return (\n <NuqsAdapter>\n <AdminLayout\n config={props.config}\n activeSlug={activeSlug}\n components={{ Link: NextLink, Image: NextImage }}\n pathname={pathname}\n activeDocID={activeDocID}\n user={props.user}\n organization={props.organization}\n sidebarOpen={props.sidebarOpen}\n >\n {props.children}\n </AdminLayout>\n </NuqsAdapter>\n );\n}\n"],"mappings":";;;;AAKA,SAAS,mBAAmB;AAC5B,OAAO,cAAc;AACrB,OAAO,eAAe;AACtB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmC;AA0CtC;AAhBC,SAAS,sBAAsB,OAMnC;AACD,QAAM,WAAW,YAAY;AAG7B,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnD,QAAM,aAAa,SAAS,CAAC;AAC7B,QAAM,cAAc,SAAS,CAAC;AAE9B,SACE,oBAAC,eACC;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ,MAAM;AAAA,MACd;AAAA,MACA,YAAY,EAAE,MAAM,UAAU,OAAO,UAAU;AAAA,MAC/C;AAAA,MACA;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB,aAAa,MAAM;AAAA,MAElB,gBAAM;AAAA;AAAA,EACT,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/NextAdminLayoutClient.tsx"],"sourcesContent":["\"use client\";\n// \"use client\" is injected by the tsup build banner for this entry (see\n// tsup.config.ts) so the emitted module carries the client boundary.\nimport type { ReactNode } from \"react\";\n\nimport { AdminLayout, type AdminUser } from \"@vexcms/react\";\nimport NextImage from \"next/image\";\nimport NextLink from \"next/link\";\nimport { usePathname } from \"next/navigation\";\nimport { NuqsAdapter } from \"nuqs/adapters/next/app\";\n\n/**\n * Client leaf for the Next.js admin layout.\n *\n * Owns all client-only wiring that cannot run on the server:\n * - `usePathname()` to derive the active collection slug / document id for\n * sidebar highlighting (Next.js layouts do not receive route params).\n * - `NuqsAdapter` (`nuqs/adapters/next/app`) so URL state works inside the\n * admin routes.\n * - `NextLink` / `NextImage` passed as framework components so every\n * `VexLink`/`VexImage` uses Next.js routing and image optimisation.\n *\n * Config reaches `AdminLayout`'s children through the app's own\n * `VexConfigProvider` mount, not through a prop on this component — this\n * leaf never touches config at all.\n *\n * This component is internal to `@vexcms/next` — applications render\n * {@link NextAdminLayout} instead.\n *\n * @param props - Layout props.\n * @param props.children - The page content from `[[...slug]]/page.tsx`.\n * @param props.user - Current user for the admin shell.\n * @returns The admin shell rendered from `children`, wrapped in `NuqsAdapter`\n * and the shared `AdminLayout`, wired with the active slug/document id derived\n * from `usePathname()` and Next.js `Link`/`Image` components.\n */\nexport function NextAdminLayoutClient(props: {\n children: ReactNode;\n organization?: Record<string, unknown>;\n sidebarOpen?: boolean;\n user?: AdminUser;\n}) {\n const pathname = usePathname();\n // pathname: \"/admin\", \"/admin/posts\", \"/admin/posts/123\"\n // Split on \"/\" and take the segment after \"admin\"\n const segments = pathname.split(\"/\").filter(Boolean);\n const activeSlug = segments[1]; // undefined on /admin, \"posts\" on /admin/posts\n const activeDocID = segments[2];\n\n return (\n <NuqsAdapter>\n <AdminLayout\n activeDocID={activeDocID}\n activeSlug={activeSlug}\n components={{ Link: NextLink, Image: NextImage }}\n organization={props.organization}\n pathname={pathname}\n sidebarOpen={props.sidebarOpen}\n user={props.user}\n >\n {props.children}\n </AdminLayout>\n </NuqsAdapter>\n );\n}\n"],"mappings":";;;;AAKA,SAAS,mBAAmC;AAC5C,OAAO,eAAe;AACtB,OAAO,cAAc;AACrB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AA0CtB;AAfC,SAAS,sBAAsB,OAKnC;AACD,QAAM,WAAW,YAAY;AAG7B,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACnD,QAAM,aAAa,SAAS,CAAC;AAC7B,QAAM,cAAc,SAAS,CAAC;AAE9B,SACE,oBAAC,eACC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY,EAAE,MAAM,UAAU,OAAO,UAAU;AAAA,MAC/C,cAAc,MAAM;AAAA,MACpB;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,MAAM,MAAM;AAAA,MAEX,gBAAM;AAAA;AAAA,EACT,GACF;AAEJ;","names":[]}
@@ -4,7 +4,7 @@ import type { VexConfig } from "@vexcms/core";
4
4
  *
5
5
  * An `async` server component that routes by the `[[...slug]]` catch-all
6
6
  * params, prefetches Convex data via `fetchQuery`, and renders the correct
7
- * view component. Does **not** include a layout wrapper — `VexAdminLayout`
7
+ * view component. Does **not** include a layout wrapper — `NextAdminLayout`
8
8
  * in `app/admin/layout.tsx` owns the persistent shell.
9
9
  *
10
10
  * **Route mapping:**
@@ -16,22 +16,24 @@ import type { VexConfig } from "@vexcms/core";
16
16
  * | `[collectionSlug, documentId]` | `CollectionEditView` with preloaded doc |
17
17
  *
18
18
  * @param props - Component props
19
- * @param props.config - The resolved VexCMS configuration from `vex.config.ts`
19
+ * @param props.config - The resolved server `VexConfig`, typically the default export of
20
+ * `vex.config.server.ts` — not the client-safe `vex.config.ts`.
20
21
  * @param props.params - Next.js 15 async params `{ path?: string[] }`
22
+ * @param props.token - Optional session token forwarded to `fetchQuery` for authenticated reads.
21
23
  * @returns The appropriate admin view for the current URL path.
22
24
  *
23
25
  * @example
24
26
  * ```tsx
25
27
  * // app/admin/[[...slug]]/page.tsx
26
- * import { VexAdminPage } from "@vexcms/next";
27
- * import config from "../../../../vex.config";
28
+ * import { NextAdminPage } from "@vexcms/next/server";
29
+ * import config from "../../../../vex.config.server";
28
30
  *
29
31
  * export default function AdminPage({
30
32
  * params,
31
33
  * }: {
32
34
  * params: Promise<{ path?: string[] }>;
33
35
  * }) {
34
- * return <VexAdminPage config={config} params={params} />;
36
+ * return <NextAdminPage config={config} params={params} />;
35
37
  * }
36
38
  * ```
37
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"NextAdminPage.d.ts","sourceRoot":"","sources":["../src/NextAdminPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoC,SAAS,EAAoB,MAAM,cAAc,CAAC;AAYlG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,wCAoIA"}
1
+ {"version":3,"file":"NextAdminPage.d.ts","sourceRoot":"","sources":["../src/NextAdminPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoC,SAAS,EAAoB,MAAM,cAAc,CAAC;AAqBlG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,wCAwIA"}
@@ -1,141 +1,6 @@
1
- // src/NextAdminPage.tsx
2
- import { fetchQuery } from "convex/nextjs";
3
- import { vexConvexApi } from "@vexcms/core";
4
1
  import {
5
- DashboardView,
6
- CollectionListView,
7
- CollectionEditView,
8
- MediaCollectionEditView,
9
- MediaCollectionListView,
10
- GlobalsListView,
11
- GlobalEditView
12
- } from "@vexcms/react";
13
- import { sanitizeConfigForClient } from "@vexcms/core";
14
- import { jsx, jsxs } from "react/jsx-runtime";
15
- async function NextAdminPage(props) {
16
- const { path = [] } = await props.params;
17
- const [collectionSlug, documentId] = path;
18
- const clientConfig = sanitizeConfigForClient(props.config);
19
- if (!collectionSlug) {
20
- return /* @__PURE__ */ jsx(DashboardView, { config: clientConfig });
21
- }
22
- if (collectionSlug === "globals") {
23
- if (!documentId) {
24
- return /* @__PURE__ */ jsx(GlobalsListView, { config: clientConfig });
25
- }
26
- const globalConfig = clientConfig.globals.find((g) => g.slug === documentId);
27
- if (!globalConfig) {
28
- return /* @__PURE__ */ jsxs("div", { children: [
29
- /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground p-6", children: [
30
- 'Global "',
31
- documentId,
32
- '" not found.'
33
- ] }),
34
- /* @__PURE__ */ jsx("p", { children: "TODO: add not found view" })
35
- ] });
36
- }
37
- const global = await fetchQuery(
38
- vexConvexApi.globals.get,
39
- { slug: globalConfig.slug },
40
- props.token ? { token: props.token } : void 0
41
- );
42
- return /* @__PURE__ */ jsx(GlobalEditView, { global: globalConfig, initialData: global });
43
- }
44
- const collection = clientConfig.collections.find((c) => c.slug === collectionSlug);
45
- const mediaCollection = clientConfig.mediaCollections.find((mc) => mc.slug === collectionSlug);
46
- if (!collection && !mediaCollection) {
47
- return /* @__PURE__ */ jsxs("div", { children: [
48
- /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground p-6", children: [
49
- 'Collection "',
50
- collectionSlug,
51
- '" not found.'
52
- ] }),
53
- /* @__PURE__ */ jsx("p", { children: "TODO: add not found view" })
54
- ] });
55
- }
56
- if (mediaCollection && documentId) {
57
- const initialData2 = await fetchQuery(
58
- vexConvexApi.get,
59
- {
60
- id: documentId,
61
- collection: mediaCollection.slug
62
- },
63
- props.token ? { token: props.token } : void 0
64
- );
65
- return /* @__PURE__ */ jsx(
66
- MediaCollectionEditView,
67
- {
68
- collection: mediaCollection,
69
- documentId,
70
- initialData: initialData2
71
- }
72
- );
73
- }
74
- if (mediaCollection) {
75
- const numItems2 = Math.max(
76
- mediaCollection.admin.table.serverPageSize,
77
- mediaCollection.admin.table.defaultPageSize
78
- );
79
- const initialData2 = await fetchQuery(
80
- vexConvexApi.find,
81
- {
82
- collection: collectionSlug,
83
- paginationOpts: {
84
- numItems: numItems2,
85
- totalDocs: true,
86
- cursor: null
87
- }
88
- },
89
- props.token ? { token: props.token } : void 0
90
- );
91
- return /* @__PURE__ */ jsx(
92
- MediaCollectionListView,
93
- {
94
- collection: mediaCollection,
95
- initialData: initialData2
96
- }
97
- );
98
- }
99
- if (collection && documentId) {
100
- const initialData2 = await fetchQuery(
101
- vexConvexApi.get,
102
- {
103
- id: documentId,
104
- collection: collection.slug
105
- },
106
- props.token ? { token: props.token } : void 0
107
- );
108
- return /* @__PURE__ */ jsx(
109
- CollectionEditView,
110
- {
111
- collection,
112
- documentId,
113
- initialData: initialData2
114
- }
115
- );
116
- }
117
- if (!collection) {
118
- throw new Error("invalid collection slug");
119
- }
120
- const numItems = Math.max(
121
- collection.admin.table.serverPageSize,
122
- collection.admin.table.defaultPageSize
123
- );
124
- const initialData = await fetchQuery(
125
- vexConvexApi.findPaginated,
126
- {
127
- collection: collectionSlug,
128
- depth: 1,
129
- paginationOpts: {
130
- cursor: null,
131
- numItems,
132
- totalDocs: true
133
- }
134
- },
135
- props.token ? { token: props.token } : void 0
136
- );
137
- return /* @__PURE__ */ jsx(CollectionListView, { collection, initialData });
138
- }
2
+ NextAdminPage
3
+ } from "./chunk-L6N3D6L5.js";
139
4
  export {
140
5
  NextAdminPage
141
6
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/NextAdminPage.tsx"],"sourcesContent":["import { fetchQuery } from \"convex/nextjs\";\nimport { vexConvexApi } from \"@vexcms/core\";\nimport type { CollectionSlug, PaginationResult, VexConfig, VexMediaDocument } from \"@vexcms/core\";\nimport {\n DashboardView,\n CollectionListView,\n CollectionEditView,\n MediaCollectionEditView,\n MediaCollectionListView,\n GlobalsListView,\n GlobalEditView,\n} from \"@vexcms/react\";\nimport { sanitizeConfigForClient } from \"@vexcms/core\";\n\n/**\n * VexCMS admin page server component for Next.js.\n *\n * An `async` server component that routes by the `[[...slug]]` catch-all\n * params, prefetches Convex data via `fetchQuery`, and renders the correct\n * view component. Does **not** include a layout wrapper — `VexAdminLayout`\n * in `app/admin/layout.tsx` owns the persistent shell.\n *\n * **Route mapping:**\n * | `path` array | View |\n * |---|---|\n * | `[]` or undefined | `DashboardView` |\n * | `[collectionSlug]` | `CollectionListView` with preloaded docs |\n * | `[collectionSlug, \"new\"]` | `CollectionEditView` (empty form) |\n * | `[collectionSlug, documentId]` | `CollectionEditView` with preloaded doc |\n *\n * @param props - Component props\n * @param props.config - The resolved VexCMS configuration from `vex.config.ts`\n * @param props.params - Next.js 15 async params `{ path?: string[] }`\n * @returns The appropriate admin view for the current URL path.\n *\n * @example\n * ```tsx\n * // app/admin/[[...slug]]/page.tsx\n * import { VexAdminPage } from \"@vexcms/next\";\n * import config from \"../../../../vex.config\";\n *\n * export default function AdminPage({\n * params,\n * }: {\n * params: Promise<{ path?: string[] }>;\n * }) {\n * return <VexAdminPage config={config} params={params} />;\n * }\n * ```\n */\nexport async function NextAdminPage(props: {\n config: VexConfig;\n params: Promise<{ path?: string[] }>;\n token?: string;\n}) {\n const { path = [] } = await props.params;\n const [collectionSlug, documentId] = path;\n\n // Sanitize config for client components (strips storageAdapters, recursively sanitizes mediaCollections)\n const clientConfig = sanitizeConfigForClient(props.config);\n\n if (!collectionSlug) {\n return <DashboardView config={clientConfig} />;\n }\n\n if (collectionSlug === \"globals\") {\n if (!documentId) {\n return <GlobalsListView config={clientConfig} />;\n }\n // Validate the route param against the registered globals first — the\n // found config's `slug` carries the narrowed GlobalSlug type, so no cast\n // of the raw URL segment is needed downstream.\n const globalConfig = clientConfig.globals.find((g) => g.slug === documentId);\n if (!globalConfig) {\n return (\n <div>\n <p className=\"text-muted-foreground p-6\">Global &quot;{documentId}&quot; not found.</p>\n <p>TODO: add not found view</p>\n </div>\n );\n }\n const global = await fetchQuery(\n vexConvexApi.globals.get,\n { slug: globalConfig.slug },\n props.token ? { token: props.token } : undefined,\n );\n return <GlobalEditView global={globalConfig} initialData={global} />;\n }\n\n const collection = clientConfig.collections.find((c) => c.slug === collectionSlug);\n const mediaCollection = clientConfig.mediaCollections.find((mc) => mc.slug === collectionSlug);\n\n if (!collection && !mediaCollection) {\n return (\n <div>\n <p className=\"text-muted-foreground p-6\">\n Collection &quot;{collectionSlug}&quot; not found.\n </p>\n <p>TODO: add not found view</p>\n </div>\n );\n }\n\n if (mediaCollection && documentId) {\n const initialData = await fetchQuery(\n vexConvexApi.get,\n {\n id: documentId,\n collection: mediaCollection.slug,\n },\n props.token ? { token: props.token } : undefined,\n );\n return (\n <MediaCollectionEditView\n collection={mediaCollection}\n documentId={documentId}\n initialData={initialData as VexMediaDocument | null}\n />\n );\n }\n\n if (mediaCollection) {\n const numItems = Math.max(\n mediaCollection.admin.table.serverPageSize,\n mediaCollection.admin.table.defaultPageSize,\n );\n const initialData = await fetchQuery(\n vexConvexApi.find,\n {\n collection: collectionSlug as CollectionSlug,\n paginationOpts: {\n numItems,\n totalDocs: true,\n cursor: null,\n },\n },\n props.token ? { token: props.token } : undefined,\n );\n return (\n <MediaCollectionListView\n collection={mediaCollection}\n initialData={initialData as PaginationResult<VexMediaDocument>}\n />\n );\n }\n\n if (collection && documentId) {\n const initialData = await fetchQuery(\n vexConvexApi.get,\n {\n id: documentId,\n collection: collection.slug,\n },\n props.token ? { token: props.token } : undefined,\n );\n return (\n <CollectionEditView\n collection={collection}\n documentId={documentId}\n initialData={initialData}\n />\n );\n }\n\n if (!collection) {\n throw new Error(\"invalid collection slug\");\n }\n\n const numItems = Math.max(\n collection.admin.table.serverPageSize,\n collection.admin.table.defaultPageSize,\n );\n const initialData = await fetchQuery(\n vexConvexApi.findPaginated,\n {\n collection: collectionSlug as CollectionSlug,\n depth: 1,\n paginationOpts: {\n cursor: null,\n numItems,\n totalDocs: true,\n },\n },\n props.token ? { token: props.token } : undefined,\n );\n return <CollectionListView collection={collection} initialData={initialData} />;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAE7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,+BAA+B;AAkD7B,cAcD,YAdC;AAZX,eAAsB,cAAc,OAIjC;AACD,QAAM,EAAE,OAAO,CAAC,EAAE,IAAI,MAAM,MAAM;AAClC,QAAM,CAAC,gBAAgB,UAAU,IAAI;AAGrC,QAAM,eAAe,wBAAwB,MAAM,MAAM;AAEzD,MAAI,CAAC,gBAAgB;AACnB,WAAO,oBAAC,iBAAc,QAAQ,cAAc;AAAA,EAC9C;AAEA,MAAI,mBAAmB,WAAW;AAChC,QAAI,CAAC,YAAY;AACf,aAAO,oBAAC,mBAAgB,QAAQ,cAAc;AAAA,IAChD;AAIA,UAAM,eAAe,aAAa,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU;AAC3E,QAAI,CAAC,cAAc;AACjB,aACE,qBAAC,SACC;AAAA,6BAAC,OAAE,WAAU,6BAA4B;AAAA;AAAA,UAAc;AAAA,UAAW;AAAA,WAAiB;AAAA,QACnF,oBAAC,OAAE,sCAAwB;AAAA,SAC7B;AAAA,IAEJ;AACA,UAAM,SAAS,MAAM;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,EAAE,MAAM,aAAa,KAAK;AAAA,MAC1B,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,IACzC;AACA,WAAO,oBAAC,kBAAe,QAAQ,cAAc,aAAa,QAAQ;AAAA,EACpE;AAEA,QAAM,aAAa,aAAa,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,cAAc;AACjF,QAAM,kBAAkB,aAAa,iBAAiB,KAAK,CAAC,OAAO,GAAG,SAAS,cAAc;AAE7F,MAAI,CAAC,cAAc,CAAC,iBAAiB;AACnC,WACE,qBAAC,SACC;AAAA,2BAAC,OAAE,WAAU,6BAA4B;AAAA;AAAA,QACrB;AAAA,QAAe;AAAA,SACnC;AAAA,MACA,oBAAC,OAAE,sCAAwB;AAAA,OAC7B;AAAA,EAEJ;AAEA,MAAI,mBAAmB,YAAY;AACjC,UAAMA,eAAc,MAAM;AAAA,MACxB,aAAa;AAAA,MACb;AAAA,QACE,IAAI;AAAA,QACJ,YAAY,gBAAgB;AAAA,MAC9B;AAAA,MACA,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,IACzC;AACA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,YAAY;AAAA,QACZ;AAAA,QACA,aAAaA;AAAA;AAAA,IACf;AAAA,EAEJ;AAEA,MAAI,iBAAiB;AACnB,UAAMC,YAAW,KAAK;AAAA,MACpB,gBAAgB,MAAM,MAAM;AAAA,MAC5B,gBAAgB,MAAM,MAAM;AAAA,IAC9B;AACA,UAAMD,eAAc,MAAM;AAAA,MACxB,aAAa;AAAA,MACb;AAAA,QACE,YAAY;AAAA,QACZ,gBAAgB;AAAA,UACd,UAAAC;AAAA,UACA,WAAW;AAAA,UACX,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,MACA,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,IACzC;AACA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,YAAY;AAAA,QACZ,aAAaD;AAAA;AAAA,IACf;AAAA,EAEJ;AAEA,MAAI,cAAc,YAAY;AAC5B,UAAMA,eAAc,MAAM;AAAA,MACxB,aAAa;AAAA,MACb;AAAA,QACE,IAAI;AAAA,QACJ,YAAY,WAAW;AAAA,MACzB;AAAA,MACA,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,IACzC;AACA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,aAAaA;AAAA;AAAA,IACf;AAAA,EAEJ;AAEA,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAEA,QAAM,WAAW,KAAK;AAAA,IACpB,WAAW,MAAM,MAAM;AAAA,IACvB,WAAW,MAAM,MAAM;AAAA,EACzB;AACA,QAAM,cAAc,MAAM;AAAA,IACxB,aAAa;AAAA,IACb;AAAA,MACE,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,gBAAgB;AAAA,QACd,QAAQ;AAAA,QACR;AAAA,QACA,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,EACzC;AACA,SAAO,oBAAC,sBAAmB,YAAwB,aAA0B;AAC/E;","names":["initialData","numItems"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}