@panneau/app 4.1.1 → 5.0.0-alpha.1

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.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @panneau/app
2
+
3
+ The Panneau admin panel: the app entry (`createPanneauApp`), and the shell, routes and pages to come.
4
+
5
+ The shell is a placeholder until Phase 2 of the [roadmap](../../docs/roadmap.md): it loads the definition, lists the resources and follows the client routes. The entry contract below is stable: see [decisions/0019](../../docs/decisions/0019-app-entry.md).
6
+
7
+ ```ts
8
+ // resources/js/panneau.tsx
9
+ import { createPanneauApp } from '@panneau/app';
10
+
11
+ createPanneauApp({ element: document.getElementById('panneau')!, plugins: [] });
12
+ ```
13
+
14
+ The page writes the boot config next to the root element ([protocol.md](../../docs/protocol.md#boot-config)):
15
+
16
+ ```html
17
+ <div id="panneau"></div>
18
+ <script type="application/json" id="panneau-boot">
19
+ { "protocol": 1, "apiBaseUrl": "/panneau/api", "basePath": "/panneau", "locale": "fr" }
20
+ </script>
21
+ ```
22
+
23
+ | Export | Content |
24
+ | -------------- | -------------------------------------------------------------------------------------------------- |
25
+ | `@panneau/app` | `createPanneauApp()`, the `<Panneau>` component, `readBootConfig()` and the types of their options |
26
+
27
+ ## Setup
28
+
29
+ ```bash
30
+ npm install @panneau/app@^5.0.0-alpha.0 react react-dom @tanstack/react-query
31
+ npm install --save-dev vite @vitejs/plugin-react
32
+ ```
33
+
34
+ - Add `@vitejs/plugin-react` to the Vite config, and the entry to its inputs.
35
+ - The entry imports no CSS and no theme: packages import their own styles, and themes come from plugins.
36
+ - Without `adapter`, the app uses the Laravel preset of the REST adapter (`@panneau/data/laravel`) on `apiBaseUrl`.
37
+ - When the API answers `401` (or `419` from Laravel), the app sends the browser to the login URL. Pass `onUnauthorized` to do something else.
38
+
39
+ The package layout, scripts and API reports are explained in [`docs/packages.md`](../../docs/packages.md).
@@ -0,0 +1,39 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import { type PanneauPlugin } from '@panneau/core';
3
+ import { type DataAdapter } from '@panneau/data';
4
+ import type { BootConfig } from '@panneau/protocol';
5
+ /** What `onUnauthorized` receives. */
6
+ export interface UnauthorizedContext {
7
+ /**
8
+ * Where to send the user: `auth.loginUrl` of the definition in `external` auth mode, or the
9
+ * `loginUrl` of the boot config before the definition is loaded. `null` when there is none, or
10
+ * in `panneau` auth mode, where the login page is part of the app.
11
+ */
12
+ loginUrl: string | null;
13
+ }
14
+ /** Props of `<Panneau>`. */
15
+ export interface PanneauProps {
16
+ /** The boot config, validated (`readBootConfig()`, or `validateBootConfig()` of the protocol). */
17
+ config: BootConfig;
18
+ /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */
19
+ adapter?: DataAdapter;
20
+ /** Plugins: field types, pages, locales, themes… */
21
+ plugins?: readonly PanneauPlugin[];
22
+ /** The TanStack Query client. Defaults to a new one. */
23
+ queryClient?: QueryClient;
24
+ /**
25
+ * Called once when the API answers that the user isn't authenticated (`401`, or `419` with the
26
+ * Laravel adapter). The app then shows that the session ended. Defaults to sending the browser
27
+ * to `loginUrl` when there is one.
28
+ */
29
+ onUnauthorized?: (context: UnauthorizedContext) => void;
30
+ }
31
+ /**
32
+ * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it
33
+ * in an element of the page. The adapter and the query client are read on the first render.
34
+ *
35
+ * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
36
+ * the API answers that the user isn't authenticated, it calls `onUnauthorized`.
37
+ */
38
+ export declare function Panneau({ config, adapter, plugins, queryClient, onUnauthorized, }: PanneauProps): import("react").JSX.Element;
39
+ //# sourceMappingURL=Panneau.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panneau.d.ts","sourceRoot":"","sources":["../src/Panneau.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAGnF,OAAO,EAAE,KAAK,aAAa,EAAwC,MAAM,eAAe,CAAC;AACzF,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,eAAe,CAAC;AAG7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAChC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IACzB,kGAAkG;IAClG,MAAM,EAAE,UAAU,CAAC;IACnB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC3D;AA0ED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,OAAO,EACP,OAAY,EACZ,WAAW,EACX,cAAgC,GACnC,EAAE,YAAY,+BAyBd"}
@@ -0,0 +1,92 @@
1
+ import { Shell } from "./Shell.js";
2
+ import { createSessionState, getLoginUrl, watchUnauthorized } from "./unauthorized.js";
3
+ import { useEffect, useState, useSyncExternalStore } from "react";
4
+ import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
5
+ import { PanneauProvider, createHistoryRouter } from "@panneau/core";
6
+ import { isApiError } from "@panneau/data";
7
+ import { createLaravelAdapter } from "@panneau/data/laravel";
8
+ import { DataAdapterProvider, definitionQueryOptions } from "@panneau/data/query";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ //#region src/Panneau.tsx
11
+ function redirectToLogin({ loginUrl }) {
12
+ if (loginUrl !== null) window.location.assign(loginUrl);
13
+ }
14
+ function createQueryClient() {
15
+ return new QueryClient({ defaultOptions: { queries: { retry: (failureCount, error) => !(isApiError(error) && error.status < 500) && failureCount < 3 } } });
16
+ }
17
+ function Content({ config, adapter, plugins, session, onUnauthorized }) {
18
+ const [router] = useState(createHistoryRouter);
19
+ const definitionQuery = useQuery({
20
+ ...definitionQueryOptions(adapter),
21
+ initialData: config.definition
22
+ });
23
+ const signedOut = useSyncExternalStore(session.subscribe, session.isSignedOut);
24
+ const loginUrl = getLoginUrl(definitionQuery.data, config);
25
+ useEffect(() => {
26
+ if (signedOut) onUnauthorized({ loginUrl });
27
+ }, [signedOut]);
28
+ if (signedOut) return /* @__PURE__ */ jsxs("div", {
29
+ role: "alert",
30
+ children: [/* @__PURE__ */ jsx("p", { children: "Your session has ended." }), loginUrl !== null ? /* @__PURE__ */ jsx("a", {
31
+ href: loginUrl,
32
+ children: "Log in"
33
+ }) : null]
34
+ });
35
+ if (definitionQuery.data === void 0) {
36
+ if (definitionQuery.isError) return /* @__PURE__ */ jsxs("div", {
37
+ role: "alert",
38
+ children: [/* @__PURE__ */ jsx("p", { children: "The admin panel could not be loaded." }), /* @__PURE__ */ jsx("button", {
39
+ type: "button",
40
+ onClick: () => void definitionQuery.refetch(),
41
+ children: "Try again"
42
+ })]
43
+ });
44
+ return /* @__PURE__ */ jsx("p", {
45
+ role: "status",
46
+ children: "Loading…"
47
+ });
48
+ }
49
+ return /* @__PURE__ */ jsx(PanneauProvider, {
50
+ plugins,
51
+ definition: definitionQuery.data,
52
+ router,
53
+ children: /* @__PURE__ */ jsx(Shell, {
54
+ definition: definitionQuery.data,
55
+ basePath: config.basePath
56
+ })
57
+ });
58
+ }
59
+ /**
60
+ * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it
61
+ * in an element of the page. The adapter and the query client are read on the first render.
62
+ *
63
+ * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
64
+ * the API answers that the user isn't authenticated, it calls `onUnauthorized`.
65
+ */
66
+ function Panneau({ config, adapter, plugins = [], queryClient, onUnauthorized = redirectToLogin }) {
67
+ const [state] = useState(() => {
68
+ const session = createSessionState();
69
+ return {
70
+ session,
71
+ adapter: watchUnauthorized(adapter ?? createLaravelAdapter({ baseUrl: config.apiBaseUrl }), session),
72
+ queryClient: queryClient ?? createQueryClient()
73
+ };
74
+ });
75
+ return /* @__PURE__ */ jsx(QueryClientProvider, {
76
+ client: state.queryClient,
77
+ children: /* @__PURE__ */ jsx(DataAdapterProvider, {
78
+ adapter: state.adapter,
79
+ children: /* @__PURE__ */ jsx(Content, {
80
+ config,
81
+ adapter: state.adapter,
82
+ plugins,
83
+ session: state.session,
84
+ onUnauthorized
85
+ })
86
+ })
87
+ });
88
+ }
89
+ //#endregion
90
+ export { Panneau };
91
+
92
+ //# sourceMappingURL=Panneau.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panneau.js","names":[],"sources":["../src/Panneau.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport { type PanneauPlugin, PanneauProvider, createHistoryRouter } from '@panneau/core';\nimport { type DataAdapter, isApiError } from '@panneau/data';\nimport { createLaravelAdapter } from '@panneau/data/laravel';\nimport { DataAdapterProvider, definitionQueryOptions } from '@panneau/data/query';\nimport type { BootConfig } from '@panneau/protocol';\n\nimport { Shell } from './Shell';\nimport { createSessionState, getLoginUrl, watchUnauthorized } from './unauthorized';\n\n/** What `onUnauthorized` receives. */\nexport interface UnauthorizedContext {\n /**\n * Where to send the user: `auth.loginUrl` of the definition in `external` auth mode, or the\n * `loginUrl` of the boot config before the definition is loaded. `null` when there is none, or\n * in `panneau` auth mode, where the login page is part of the app.\n */\n loginUrl: string | null;\n}\n\n/** Props of `<Panneau>`. */\nexport interface PanneauProps {\n /** The boot config, validated (`readBootConfig()`, or `validateBootConfig()` of the protocol). */\n config: BootConfig;\n /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */\n adapter?: DataAdapter;\n /** Plugins: field types, pages, locales, themes… */\n plugins?: readonly PanneauPlugin[];\n /** The TanStack Query client. Defaults to a new one. */\n queryClient?: QueryClient;\n /**\n * Called once when the API answers that the user isn't authenticated (`401`, or `419` with the\n * Laravel adapter). The app then shows that the session ended. Defaults to sending the browser\n * to `loginUrl` when there is one.\n */\n onUnauthorized?: (context: UnauthorizedContext) => void;\n}\n\nfunction redirectToLogin({ loginUrl }: UnauthorizedContext) {\n if (loginUrl !== null) {\n window.location.assign(loginUrl);\n }\n}\n\nfunction createQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n // Client errors (401, 403, 404, 422…) don't change on retry.\n retry: (failureCount, error) =>\n !(isApiError(error) && error.status < 500) && failureCount < 3,\n },\n },\n });\n}\n\nfunction Content({\n config,\n adapter,\n plugins,\n session,\n onUnauthorized,\n}: Required<Pick<PanneauProps, 'config' | 'adapter' | 'onUnauthorized'>> & {\n plugins: readonly PanneauPlugin[];\n session: ReturnType<typeof createSessionState>;\n}) {\n const [router] = useState(createHistoryRouter);\n const definitionQuery = useQuery({\n ...definitionQueryOptions(adapter),\n initialData: config.definition,\n });\n const signedOut = useSyncExternalStore(session.subscribe, session.isSignedOut);\n const loginUrl = getLoginUrl(definitionQuery.data, config);\n\n useEffect(() => {\n if (signedOut) {\n onUnauthorized({ loginUrl });\n }\n // Only when the session ends: `loginUrl` and the callback are read at that time.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signedOut]);\n\n if (signedOut) {\n return (\n <div role=\"alert\">\n <p>Your session has ended.</p>\n {loginUrl !== null ? <a href={loginUrl}>Log in</a> : null}\n </div>\n );\n }\n if (definitionQuery.data === undefined) {\n if (definitionQuery.isError) {\n return (\n <div role=\"alert\">\n <p>The admin panel could not be loaded.</p>\n <button type=\"button\" onClick={() => void definitionQuery.refetch()}>\n Try again\n </button>\n </div>\n );\n }\n return <p role=\"status\">Loading…</p>;\n }\n return (\n <PanneauProvider plugins={plugins} definition={definitionQuery.data} router={router}>\n <Shell definition={definitionQuery.data} basePath={config.basePath} />\n </PanneauProvider>\n );\n}\n\n/**\n * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it\n * in an element of the page. The adapter and the query client are read on the first render.\n *\n * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When\n * the API answers that the user isn't authenticated, it calls `onUnauthorized`.\n */\nexport function Panneau({\n config,\n adapter,\n plugins = [],\n queryClient,\n onUnauthorized = redirectToLogin,\n}: PanneauProps) {\n const [state] = useState(() => {\n const session = createSessionState();\n return {\n session,\n adapter: watchUnauthorized(\n adapter ?? createLaravelAdapter({ baseUrl: config.apiBaseUrl }),\n session,\n ),\n queryClient: queryClient ?? createQueryClient(),\n };\n });\n return (\n <QueryClientProvider client={state.queryClient}>\n <DataAdapterProvider adapter={state.adapter}>\n <Content\n config={config}\n adapter={state.adapter}\n plugins={plugins}\n session={state.session}\n onUnauthorized={onUnauthorized}\n />\n </DataAdapterProvider>\n </QueryClientProvider>\n );\n}\n"],"mappings":";;;;;;;;;;AAwCA,SAAS,gBAAgB,EAAE,YAAiC;CACxD,IAAI,aAAa,MACb,OAAO,SAAS,OAAO,QAAQ;AAEvC;AAEA,SAAS,oBAAiC;CACtC,OAAO,IAAI,YAAY,EACnB,gBAAgB,EACZ,SAAS,EAEL,QAAQ,cAAc,UAClB,EAAE,WAAW,KAAK,KAAK,MAAM,SAAS,QAAQ,eAAe,EACrE,EACJ,EACJ,CAAC;AACL;AAEA,SAAS,QAAQ,EACb,QACA,SACA,SACA,SACA,kBAID;CACC,MAAM,CAAC,UAAU,SAAS,mBAAmB;CAC7C,MAAM,kBAAkB,SAAS;EAC7B,GAAG,uBAAuB,OAAO;EACjC,aAAa,OAAO;CACxB,CAAC;CACD,MAAM,YAAY,qBAAqB,QAAQ,WAAW,QAAQ,WAAW;CAC7E,MAAM,WAAW,YAAY,gBAAgB,MAAM,MAAM;CAEzD,gBAAgB;EACZ,IAAI,WACA,eAAe,EAAE,SAAS,CAAC;CAInC,GAAG,CAAC,SAAS,CAAC;CAEd,IAAI,WACA,OACI,qBAAC,OAAD;EAAK,MAAK;EAAV,UAAA,CACI,oBAAC,KAAD,EAAA,UAAG,0BAA0B,CAAA,GAC5B,aAAa,OAAO,oBAAC,KAAD;GAAG,MAAM;GAAU,UAAA;EAAS,CAAA,IAAI,IACpD;;CAGb,IAAI,gBAAgB,SAAS,KAAA,GAAW;EACpC,IAAI,gBAAgB,SAChB,OACI,qBAAC,OAAD;GAAK,MAAK;GAAV,UAAA,CACI,oBAAC,KAAD,EAAA,UAAG,uCAAuC,CAAA,GAC1C,oBAAC,UAAD;IAAQ,MAAK;IAAS,eAAe,KAAK,gBAAgB,QAAQ;IAAE,UAAA;GAE5D,CAAA,CACP;;EAGb,OAAO,oBAAC,KAAD;GAAG,MAAK;GAAS,UAAA;EAAW,CAAA;CACvC;CACA,OACI,oBAAC,iBAAD;EAA0B;EAAS,YAAY,gBAAgB;EAAc;EACzE,UAAA,oBAAC,OAAD;GAAO,YAAY,gBAAgB;GAAM,UAAU,OAAO;EAAS,CAAA;CACtD,CAAA;AAEzB;;;;;;;;AASA,SAAgB,QAAQ,EACpB,QACA,SACA,UAAU,CAAA,GACV,aACA,iBAAiB,mBACJ;CACb,MAAM,CAAC,SAAS,eAAe;EAC3B,MAAM,UAAU,mBAAmB;EACnC,OAAO;GACH;GACA,SAAS,kBACL,WAAW,qBAAqB,EAAE,SAAS,OAAO,WAAW,CAAC,GAC9D,OACJ;GACA,aAAa,eAAe,kBAAkB;EAClD;CACJ,CAAC;CACD,OACI,oBAAC,qBAAD;EAAqB,QAAQ,MAAM;EAC/B,UAAA,oBAAC,qBAAD;GAAqB,SAAS,MAAM;GAChC,UAAA,oBAAC,SAAD;IACY;IACR,SAAS,MAAM;IACN;IACT,SAAS,MAAM;IACC;GAAe,CAAA;EAElB,CAAA;CACJ,CAAA;AAE7B"}
@@ -0,0 +1,11 @@
1
+ import type { Definition } from '@panneau/protocol';
2
+ export interface ShellProps {
3
+ definition: Definition;
4
+ basePath: string;
5
+ }
6
+ /**
7
+ * Placeholder of the app shell: the site name, the resources, and the title of the current route.
8
+ * The real shell (layout, menus, pages) comes in Phase 2.
9
+ */
10
+ export declare function Shell({ definition, basePath }: ShellProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=Shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Shell.d.ts","sourceRoot":"","sources":["../src/Shell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACpB;AA6BD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,UAAU,+BAiCzD"}
package/dist/Shell.js ADDED
@@ -0,0 +1,144 @@
1
+ import { Link, usePathname } from "./location.js";
2
+ import { matchRoute, routePath } from "./routes.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/Shell.tsx
6
+ function getTitle(route, definition) {
7
+ if (route.name === "home") return definition.name;
8
+ if (route.name === "page") {
9
+ const page = definition.pages?.[route.page];
10
+ return page === void 0 ? "Page not found" : page.label ?? route.page;
11
+ }
12
+ if (route.name === "not-found") return "Page not found";
13
+ const resource = definition.resources.find(({ id }) => id === route.resource);
14
+ if (resource === void 0) return "Page not found";
15
+ switch (route.name) {
16
+ case "resource.index": return resource.label.plural;
17
+ case "resource.create": return `New ${resource.label.singular}`;
18
+ case "resource.show": return `${resource.label.singular} ${route.id}`;
19
+ case "resource.edit": return `Edit ${resource.label.singular} ${route.id}`;
20
+ }
21
+ }
22
+ /**
23
+ * Placeholder of the app shell: the site name, the resources, and the title of the current route.
24
+ * The real shell (layout, menus, pages) comes in Phase 2.
25
+ */
26
+ function Shell(t0) {
27
+ const $ = c(34);
28
+ const { definition, basePath } = t0;
29
+ const pathname = usePathname();
30
+ let t1;
31
+ let t2;
32
+ let t3;
33
+ let t4;
34
+ if ($[0] !== basePath || $[1] !== definition || $[2] !== pathname) {
35
+ const route = matchRoute(pathname, basePath) ?? { name: "not-found" };
36
+ t2 = "";
37
+ let t5;
38
+ if ($[7] !== basePath) {
39
+ t5 = routePath({ name: "home" }, basePath);
40
+ $[7] = basePath;
41
+ $[8] = t5;
42
+ } else t5 = $[8];
43
+ let t6;
44
+ if ($[9] !== definition.name || $[10] !== t5) {
45
+ t6 = /* @__PURE__ */ jsx(Link, {
46
+ href: t5,
47
+ children: definition.name
48
+ });
49
+ $[9] = definition.name;
50
+ $[10] = t5;
51
+ $[11] = t6;
52
+ } else t6 = $[11];
53
+ let t7;
54
+ if ($[12] !== definition.user) {
55
+ t7 = definition.user !== void 0 && definition.user !== null ? /* @__PURE__ */ jsx("span", { children: definition.user.name }) : null;
56
+ $[12] = definition.user;
57
+ $[13] = t7;
58
+ } else t7 = $[13];
59
+ if ($[14] !== t6 || $[15] !== t7) {
60
+ t3 = /* @__PURE__ */ jsxs("header", { children: [t6, t7] });
61
+ $[14] = t6;
62
+ $[15] = t7;
63
+ $[16] = t3;
64
+ } else t3 = $[16];
65
+ let t8;
66
+ if ($[17] !== basePath || $[18] !== definition.resources) {
67
+ let t9;
68
+ if ($[20] !== basePath) {
69
+ t9 = (resource) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Link, {
70
+ href: routePath({
71
+ name: "resource.index",
72
+ resource: resource.id
73
+ }, basePath),
74
+ children: resource.label.plural
75
+ }) }, resource.id);
76
+ $[20] = basePath;
77
+ $[21] = t9;
78
+ } else t9 = $[21];
79
+ t8 = definition.resources.map(t9);
80
+ $[17] = basePath;
81
+ $[18] = definition.resources;
82
+ $[19] = t8;
83
+ } else t8 = $[19];
84
+ if ($[22] !== t8) {
85
+ t4 = /* @__PURE__ */ jsx("nav", {
86
+ "aria-label": "Resources",
87
+ children: /* @__PURE__ */ jsx("ul", { children: t8 })
88
+ });
89
+ $[22] = t8;
90
+ $[23] = t4;
91
+ } else t4 = $[23];
92
+ t1 = getTitle(route, definition);
93
+ $[0] = basePath;
94
+ $[1] = definition;
95
+ $[2] = pathname;
96
+ $[3] = t1;
97
+ $[4] = t2;
98
+ $[5] = t3;
99
+ $[6] = t4;
100
+ } else {
101
+ t1 = $[3];
102
+ t2 = $[4];
103
+ t3 = $[5];
104
+ t4 = $[6];
105
+ }
106
+ let t5;
107
+ if ($[24] !== t1) {
108
+ t5 = /* @__PURE__ */ jsx("h1", { children: t1 });
109
+ $[24] = t1;
110
+ $[25] = t5;
111
+ } else t5 = $[25];
112
+ let t6;
113
+ if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
114
+ t6 = /* @__PURE__ */ jsx("p", { children: "The Panneau 5 app shell is not built yet." });
115
+ $[26] = t6;
116
+ } else t6 = $[26];
117
+ let t7;
118
+ if ($[27] !== t5) {
119
+ t7 = /* @__PURE__ */ jsxs("main", { children: [t5, t6] });
120
+ $[27] = t5;
121
+ $[28] = t7;
122
+ } else t7 = $[28];
123
+ let t8;
124
+ if ($[29] !== t2 || $[30] !== t3 || $[31] !== t4 || $[32] !== t7) {
125
+ t8 = /* @__PURE__ */ jsxs("div", {
126
+ "data-panneau-shell": t2,
127
+ children: [
128
+ t3,
129
+ t4,
130
+ t7
131
+ ]
132
+ });
133
+ $[29] = t2;
134
+ $[30] = t3;
135
+ $[31] = t4;
136
+ $[32] = t7;
137
+ $[33] = t8;
138
+ } else t8 = $[33];
139
+ return t8;
140
+ }
141
+ //#endregion
142
+ export { Shell };
143
+
144
+ //# sourceMappingURL=Shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Shell.js","names":["_c"],"sources":["../src/Shell.tsx"],"sourcesContent":["import type { Definition } from '@panneau/protocol';\n\nimport { Link, usePathname } from './location';\nimport { type AppRoute, matchRoute, routePath } from './routes';\n\nexport interface ShellProps {\n definition: Definition;\n basePath: string;\n}\n\nfunction getTitle(route: AppRoute, definition: Definition): string {\n if (route.name === 'home') {\n return definition.name;\n }\n if (route.name === 'page') {\n const page = definition.pages?.[route.page];\n return page === undefined ? 'Page not found' : (page.label ?? route.page);\n }\n if (route.name === 'not-found') {\n return 'Page not found';\n }\n const resource = definition.resources.find(({ id }) => id === route.resource);\n if (resource === undefined) {\n return 'Page not found';\n }\n switch (route.name) {\n case 'resource.index':\n return resource.label.plural;\n case 'resource.create':\n return `New ${resource.label.singular}`;\n case 'resource.show':\n return `${resource.label.singular} ${route.id}`;\n case 'resource.edit':\n return `Edit ${resource.label.singular} ${route.id}`;\n }\n}\n\n/**\n * Placeholder of the app shell: the site name, the resources, and the title of the current route.\n * The real shell (layout, menus, pages) comes in Phase 2.\n */\nexport function Shell({ definition, basePath }: ShellProps) {\n const pathname = usePathname();\n const route = matchRoute(pathname, basePath) ?? { name: 'not-found' };\n return (\n <div data-panneau-shell=\"\">\n <header>\n <Link href={routePath({ name: 'home' }, basePath)}>{definition.name}</Link>\n {definition.user !== undefined && definition.user !== null ? (\n <span>{definition.user.name}</span>\n ) : null}\n </header>\n <nav aria-label=\"Resources\">\n <ul>\n {definition.resources.map((resource) => (\n <li key={resource.id}>\n <Link\n href={routePath(\n { name: 'resource.index', resource: resource.id },\n basePath,\n )}\n >\n {resource.label.plural}\n </Link>\n </li>\n ))}\n </ul>\n </nav>\n <main>\n <h1>{getTitle(route, definition)}</h1>\n <p>The Panneau 5 app shell is not built yet.</p>\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
package/dist/boot.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { type BootConfig } from '@panneau/protocol';
2
+ /** Validates a boot config, and throws an error that lists what is invalid. */
3
+ export declare function parseBootConfig(input: unknown): BootConfig;
4
+ /**
5
+ * Reads the boot config that the server wrote in the page, in
6
+ * `<script type="application/json" id="panneau-boot">`, and validates it. Throws when the element
7
+ * is missing, or when its content isn't a valid boot config.
8
+ */
9
+ export declare function readBootConfig(target?: Document): BootConfig;
10
+ //# sourceMappingURL=boot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../src/boot.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,UAAU,EAAsB,MAAM,mBAAmB,CAAC;AAEhG,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAS1D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,QAAmB,GAAG,UAAU,CAmBtE"}
package/dist/boot.js ADDED
@@ -0,0 +1,31 @@
1
+ import { BOOT_CONFIG_ELEMENT_ID, validateBootConfig } from "@panneau/protocol";
2
+ //#region src/boot.ts
3
+ /** Validates a boot config, and throws an error that lists what is invalid. */
4
+ function parseBootConfig(input) {
5
+ const result = validateBootConfig(input);
6
+ if (!result.success) {
7
+ const issues = result.issues.map(({ path, message }) => `- ${path === "" ? "(root)" : path}: ${message}`);
8
+ throw new Error(`The Panneau boot config is invalid:\n${issues.join("\n")}`);
9
+ }
10
+ return result.data;
11
+ }
12
+ /**
13
+ * Reads the boot config that the server wrote in the page, in
14
+ * `<script type="application/json" id="panneau-boot">`, and validates it. Throws when the element
15
+ * is missing, or when its content isn't a valid boot config.
16
+ */
17
+ function readBootConfig(target = document) {
18
+ const element = target.getElementById(BOOT_CONFIG_ELEMENT_ID);
19
+ if (element === null) throw new Error(`The page has no Panneau boot config: add <script type="application/json" id="${BOOT_CONFIG_ELEMENT_ID}">, or pass \`config\` to createPanneauApp().`);
20
+ let input;
21
+ try {
22
+ input = JSON.parse(element.textContent);
23
+ } catch (error) {
24
+ throw new Error(`The Panneau boot config in #${BOOT_CONFIG_ELEMENT_ID} is not valid JSON.`, { cause: error });
25
+ }
26
+ return parseBootConfig(input);
27
+ }
28
+ //#endregion
29
+ export { parseBootConfig, readBootConfig };
30
+
31
+ //# sourceMappingURL=boot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.js","names":[],"sources":["../src/boot.ts"],"sourcesContent":["import { BOOT_CONFIG_ELEMENT_ID, type BootConfig, validateBootConfig } from '@panneau/protocol';\n\n/** Validates a boot config, and throws an error that lists what is invalid. */\nexport function parseBootConfig(input: unknown): BootConfig {\n const result = validateBootConfig(input);\n if (!result.success) {\n const issues = result.issues.map(\n ({ path, message }) => `- ${path === '' ? '(root)' : path}: ${message}`,\n );\n throw new Error(`The Panneau boot config is invalid:\\n${issues.join('\\n')}`);\n }\n return result.data;\n}\n\n/**\n * Reads the boot config that the server wrote in the page, in\n * `<script type=\"application/json\" id=\"panneau-boot\">`, and validates it. Throws when the element\n * is missing, or when its content isn't a valid boot config.\n */\nexport function readBootConfig(target: Document = document): BootConfig {\n const element = target.getElementById(BOOT_CONFIG_ELEMENT_ID);\n if (element === null) {\n throw new Error(\n `The page has no Panneau boot config: add <script type=\"application/json\" id=\"${BOOT_CONFIG_ELEMENT_ID}\">, or pass \\`config\\` to createPanneauApp().`,\n );\n }\n let input: unknown;\n try {\n input = JSON.parse(element.textContent);\n } catch (error) {\n throw new Error(\n `The Panneau boot config in #${BOOT_CONFIG_ELEMENT_ID} is not valid JSON.`,\n {\n cause: error,\n },\n );\n }\n return parseBootConfig(input);\n}\n"],"mappings":";;;AAGA,SAAgB,gBAAgB,OAA4B;CACxD,MAAM,SAAS,mBAAmB,KAAK;CACvC,IAAI,CAAC,OAAO,SAAS;EACjB,MAAM,SAAS,OAAO,OAAO,KACxB,EAAE,MAAM,cAAc,KAAK,SAAS,KAAK,WAAW,KAAI,IAAK,SAClE;EACA,MAAM,IAAI,MAAM,wCAAwC,OAAO,KAAK,IAAI,GAAG;CAC/E;CACA,OAAO,OAAO;AAClB;;;;;;AAOA,SAAgB,eAAe,SAAmB,UAAsB;CACpE,MAAM,UAAU,OAAO,eAAe,sBAAsB;CAC5D,IAAI,YAAY,MACZ,MAAM,IAAI,MACN,gFAAgF,uBAAsB,8CAC1G;CAEJ,IAAI;CACJ,IAAI;EACA,QAAQ,KAAK,MAAM,QAAQ,WAAW;CAC1C,SAAS,OAAO;EACZ,MAAM,IAAI,MACN,+BAA+B,uBAAsB,sBACrD,EACI,OAAO,MACX,CACJ;CACJ;CACA,OAAO,gBAAgB,KAAK;AAChC"}
@@ -0,0 +1,45 @@
1
+ import type { QueryClient } from '@tanstack/react-query';
2
+ import type { PanneauPlugin } from '@panneau/core';
3
+ import type { DataAdapter } from '@panneau/data';
4
+ import type { BootConfig, BootConfigInput } from '@panneau/protocol';
5
+ import { type UnauthorizedContext } from './Panneau';
6
+ /** Options of `createPanneauApp()`. */
7
+ export interface PanneauAppOptions {
8
+ /** The element the app renders in. */
9
+ element: Element;
10
+ /** Plugins: field types, pages, locales, themes… */
11
+ plugins?: readonly PanneauPlugin[];
12
+ /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */
13
+ adapter?: DataAdapter;
14
+ /**
15
+ * The boot config. Defaults to the one the server wrote in the page, in
16
+ * `<script type="application/json" id="panneau-boot">`.
17
+ */
18
+ config?: BootConfigInput;
19
+ /** The TanStack Query client. Defaults to a new one. */
20
+ queryClient?: QueryClient;
21
+ /**
22
+ * Called once when the API answers that the user isn't authenticated. Defaults to sending the
23
+ * browser to the login URL, when there is one.
24
+ */
25
+ onUnauthorized?: (context: UnauthorizedContext) => void;
26
+ }
27
+ /** A mounted app. */
28
+ export interface PanneauApp {
29
+ /** The boot config, validated, with defaults applied. */
30
+ config: BootConfig;
31
+ /** Unmounts the app from its element. */
32
+ unmount(): void;
33
+ }
34
+ /**
35
+ * Mounts the Panneau admin panel in an element of the page. Throws when the boot config is
36
+ * missing or invalid.
37
+ *
38
+ * ```ts
39
+ * import { createPanneauApp } from '@panneau/app';
40
+ *
41
+ * createPanneauApp({ element: document.getElementById('panneau')!, plugins: [] });
42
+ * ```
43
+ */
44
+ export declare function createPanneauApp({ element, config: input, ...props }: PanneauAppOptions): PanneauApp;
45
+ //# sourceMappingURL=createPanneauApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPanneauApp.d.ts","sourceRoot":"","sources":["../src/createPanneauApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAW,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAG9D,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAC9B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,4FAA4F;IAC5F,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC3D;AAED,qBAAqB;AACrB,MAAM,WAAW,UAAU;IACvB,yDAAyD;IACzD,MAAM,EAAE,UAAU,CAAC;IACnB,yCAAyC;IACzC,OAAO,IAAI,IAAI,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,OAAO,EACP,MAAM,EAAE,KAAK,EACb,GAAG,KAAK,EACX,EAAE,iBAAiB,GAAG,UAAU,CAUhC"}
@@ -0,0 +1,32 @@
1
+ import { Panneau } from "./Panneau.js";
2
+ import { parseBootConfig, readBootConfig } from "./boot.js";
3
+ import { StrictMode } from "react";
4
+ import { createRoot } from "react-dom/client";
5
+ import { jsx } from "react/jsx-runtime";
6
+ //#region src/createPanneauApp.tsx
7
+ /**
8
+ * Mounts the Panneau admin panel in an element of the page. Throws when the boot config is
9
+ * missing or invalid.
10
+ *
11
+ * ```ts
12
+ * import { createPanneauApp } from '@panneau/app';
13
+ *
14
+ * createPanneauApp({ element: document.getElementById('panneau')!, plugins: [] });
15
+ * ```
16
+ */
17
+ function createPanneauApp({ element, config: input, ...props }) {
18
+ const config = input !== void 0 ? parseBootConfig(input) : readBootConfig(element.ownerDocument);
19
+ const root = createRoot(element);
20
+ root.render(/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(Panneau, {
21
+ ...props,
22
+ config
23
+ }) }));
24
+ return {
25
+ config,
26
+ unmount: () => root.unmount()
27
+ };
28
+ }
29
+ //#endregion
30
+ export { createPanneauApp };
31
+
32
+ //# sourceMappingURL=createPanneauApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPanneauApp.js","names":[],"sources":["../src/createPanneauApp.tsx"],"sourcesContent":["import type { QueryClient } from '@tanstack/react-query';\nimport { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport type { PanneauPlugin } from '@panneau/core';\nimport type { DataAdapter } from '@panneau/data';\nimport type { BootConfig, BootConfigInput } from '@panneau/protocol';\n\nimport { Panneau, type UnauthorizedContext } from './Panneau';\nimport { parseBootConfig, readBootConfig } from './boot';\n\n/** Options of `createPanneauApp()`. */\nexport interface PanneauAppOptions {\n /** The element the app renders in. */\n element: Element;\n /** Plugins: field types, pages, locales, themes… */\n plugins?: readonly PanneauPlugin[];\n /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */\n adapter?: DataAdapter;\n /**\n * The boot config. Defaults to the one the server wrote in the page, in\n * `<script type=\"application/json\" id=\"panneau-boot\">`.\n */\n config?: BootConfigInput;\n /** The TanStack Query client. Defaults to a new one. */\n queryClient?: QueryClient;\n /**\n * Called once when the API answers that the user isn't authenticated. Defaults to sending the\n * browser to the login URL, when there is one.\n */\n onUnauthorized?: (context: UnauthorizedContext) => void;\n}\n\n/** A mounted app. */\nexport interface PanneauApp {\n /** The boot config, validated, with defaults applied. */\n config: BootConfig;\n /** Unmounts the app from its element. */\n unmount(): void;\n}\n\n/**\n * Mounts the Panneau admin panel in an element of the page. Throws when the boot config is\n * missing or invalid.\n *\n * ```ts\n * import { createPanneauApp } from '@panneau/app';\n *\n * createPanneauApp({ element: document.getElementById('panneau')!, plugins: [] });\n * ```\n */\nexport function createPanneauApp({\n element,\n config: input,\n ...props\n}: PanneauAppOptions): PanneauApp {\n const config =\n input !== undefined ? parseBootConfig(input) : readBootConfig(element.ownerDocument);\n const root = createRoot(element);\n root.render(\n <StrictMode>\n <Panneau {...props} config={config} />\n </StrictMode>,\n );\n return { config, unmount: () => root.unmount() };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmDA,SAAgB,iBAAiB,EAC7B,SACA,QAAQ,OACR,GAAG,SAC2B;CAC9B,MAAM,SACF,UAAU,KAAA,IAAY,gBAAgB,KAAK,IAAI,eAAe,QAAQ,aAAa;CACvF,MAAM,OAAO,WAAW,OAAO;CAC/B,KAAK,OACD,oBAAC,YAAD,EAAA,UACI,oBAAC,SAAD;EAAS,GAAI;EAAe;CAAO,CAAA,EAC3B,CAAA,CAChB;CACA,OAAO;EAAE;EAAQ,eAAe,KAAK,QAAQ;CAAE;AACnD"}
package/dist/index.d.ts CHANGED
@@ -1,53 +1,4 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
3
- import { PanneauDefinition, FormDefinition, FieldDefinition, ComponentsMap, User, StatusCode, Label } from '@panneau/core';
4
- import { UppyProviderConfig } from '@panneau/uppy';
5
-
6
- interface ContainerProps {
7
- definition: PanneauDefinition;
8
- forms?: FormDefinition[] | null;
9
- fields?: FieldDefinition[] | null;
10
- components?: ComponentsMap | null;
11
- user?: User | null;
12
- memoryRouter?: boolean;
13
- baseUrl?: string | null;
14
- uppy?: UppyProviderConfig | null;
15
- statusCode?: StatusCode | null;
16
- }
17
- declare function Container({ definition, forms: providedForms, fields: providedFields, components, user, memoryRouter, baseUrl, uppy, statusCode, }: ContainerProps): react.JSX.Element;
18
-
19
- interface MainLayoutProps {
20
- children?: ReactNode;
21
- loading?: boolean;
22
- fullscreen?: boolean;
23
- }
24
- declare function MainLayout({ fullscreen, loading, children }: MainLayoutProps): react.JSX.Element;
25
-
26
- interface GuestLayoutProps {
27
- children: ReactNode;
28
- fullscreen?: boolean;
29
- }
30
- declare function GuestLayout({ fullscreen, children }: GuestLayoutProps): react.JSX.Element;
31
-
32
- interface PageHeaderProps {
33
- title?: Label | null;
34
- actions?: ReactNode;
35
- small?: boolean;
36
- className?: string | null;
37
- children?: ReactNode;
38
- }
39
- declare function PageHeader({ title, actions, small, className, children, }: PageHeaderProps): react.JSX.Element;
40
-
41
- declare function ResourceFilters(props: any): react.JSX.Element;
42
-
43
- interface ResourceItemsListProps {
44
- resource: string | {
45
- id: string;
46
- };
47
- [key: string]: any;
48
- }
49
- declare function ResourceItemsList({ resource, ...props }: ResourceItemsListProps): react.JSX.Element;
50
-
51
- declare function ResourceFormWrapper(props: any): react.JSX.Element;
52
-
53
- export { GuestLayout, MainLayout, PageHeader, ResourceFilters, ResourceFormWrapper as ResourceForm, ResourceItemsList, Container as default };
1
+ export { createPanneauApp, type PanneauApp, type PanneauAppOptions } from './createPanneauApp';
2
+ export { Panneau, type PanneauProps, type UnauthorizedContext } from './Panneau';
3
+ export { readBootConfig } from './boot';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/F,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC"}