@panneau/app 5.0.0-alpha.5 → 5.0.0-alpha.6

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 CHANGED
@@ -37,6 +37,7 @@ npm install --save-dev vite @vitejs/plugin-react
37
37
  - The entry imports no CSS and no theme: packages import their own styles, and themes come from plugins.
38
38
  - Named icons (`"icon": "users"` in the definition) are Lucide icons, each loaded when shown. Pass `iconLoader` to load fewer, or `null` for none.
39
39
  - Without `adapter`, the app uses the Laravel preset of the REST adapter (`@panneau/data/laravel`) on `apiBaseUrl`.
40
+ - `location` fields place points on OpenStreetMap's tiles, without an address search. Pass `maps` for other tiles or a search: `maps: { geocoding: createNominatimSource() }`, from `@panneau/fields`.
40
41
  - When the API answers `401` (or `419` from Laravel), the app sends the browser to the login URL. Pass `onUnauthorized` to do something else.
41
42
 
42
43
  ## Theming the shell
package/dist/Panneau.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
2
  import { type PanneauPlugin } from '@panneau/core';
3
3
  import { type DataAdapter } from '@panneau/data';
4
+ import { type MapsConfig } from '@panneau/fields';
4
5
  import type { BootConfig } from '@panneau/protocol';
5
6
  import { type NamedIconLoader } from '@panneau/ui';
6
7
  /** What `onUnauthorized` receives. */
@@ -33,6 +34,11 @@ export interface PanneauProps {
33
34
  * to `loginUrl` when there is one.
34
35
  */
35
36
  onUnauthorized?: (context: UnauthorizedContext) => void;
37
+ /**
38
+ * The tiles and the address search of the maps of `location` fields. Defaults to
39
+ * OpenStreetMap's tiles, without an address search (decision 0033).
40
+ */
41
+ maps?: MapsConfig | null;
36
42
  }
37
43
  /**
38
44
  * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it
@@ -41,5 +47,5 @@ export interface PanneauProps {
41
47
  * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
42
48
  * the API answers that the user isn't authenticated, it calls `onUnauthorized`.
43
49
  */
44
- export declare function Panneau({ config, adapter, plugins, queryClient, iconLoader, onUnauthorized, }: PanneauProps): import("react").JSX.Element;
50
+ export declare function Panneau({ config, adapter, plugins, queryClient, iconLoader, onUnauthorized, maps, }: PanneauProps): import("react").JSX.Element;
45
51
  //# sourceMappingURL=Panneau.d.ts.map
@@ -1 +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,EACH,KAAK,aAAa,EAKrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,eAAe,CAAC;AAI7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAU,KAAK,eAAe,EAAwC,MAAM,aAAa,CAAC;AASjG,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;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC3D;AAiHD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,OAAO,EACP,OAAY,EACZ,WAAW,EACX,UAA6B,EAC7B,cAAgC,GACnC,EAAE,YAAY,+BA0Bd"}
1
+ {"version":3,"file":"Panneau.d.ts","sourceRoot":"","sources":["../src/Panneau.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAGnF,OAAO,EACH,KAAK,aAAa,EAKrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAkB,KAAK,UAAU,EAAqB,MAAM,iBAAiB,CAAC;AAErF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAU,KAAK,eAAe,EAAwC,MAAM,aAAa,CAAC;AASjG,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;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5B;AAsHD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,OAAO,EACP,OAAY,EACZ,WAAW,EACX,UAA6B,EAC7B,cAAgC,EAChC,IAAW,GACd,EAAE,YAAY,+BA2Bd"}
package/dist/Panneau.js CHANGED
@@ -10,6 +10,7 @@ import { PanneauProvider, createHistoryRouter, createPluginRegistry, resolveThem
10
10
  import { isApiError } from "@panneau/data";
11
11
  import { createLaravelAdapter } from "@panneau/data/laravel";
12
12
  import { DataAdapterProvider, definitionQueryOptions } from "@panneau/data/query";
13
+ import { FieldsProvider, createEmbedSource } from "@panneau/fields";
13
14
  import { appMessages } from "@panneau/intl";
14
15
  import { Button, PanneauRoot, Spinner, usePanneauIntl } from "@panneau/ui";
15
16
  import { lucideIconLoader } from "@panneau/ui/named-icons";
@@ -21,7 +22,7 @@ function redirectToLogin({ loginUrl }) {
21
22
  function createQueryClient() {
22
23
  return new QueryClient({ defaultOptions: { queries: { retry: (failureCount, error) => !(isApiError(error) && error.status < 500) && failureCount < 3 } } });
23
24
  }
24
- function Content({ config, adapter, plugins, iconLoader, session, onUnauthorized }) {
25
+ function Content({ config, adapter, plugins, iconLoader, session, onUnauthorized, maps }) {
25
26
  const [router] = useState(createHistoryRouter);
26
27
  const definitionQuery = useQuery({
27
28
  ...definitionQueryOptions(adapter),
@@ -48,11 +49,15 @@ function Content({ config, adapter, plugins, iconLoader, session, onUnauthorized
48
49
  plugins,
49
50
  definition,
50
51
  router,
51
- children: /* @__PURE__ */ jsx(Shell, {
52
- definition,
53
- basePath: config.basePath,
54
- colorScheme: scheme,
55
- onColorSchemeChange: setColorScheme
52
+ children: /* @__PURE__ */ jsx(FieldsProvider, {
53
+ embedSource: createEmbedSource(adapter),
54
+ maps,
55
+ children: /* @__PURE__ */ jsx(Shell, {
56
+ definition,
57
+ basePath: config.basePath,
58
+ colorScheme: scheme,
59
+ onColorSchemeChange: setColorScheme
60
+ })
56
61
  })
57
62
  })
58
63
  });
@@ -169,7 +174,7 @@ function Loading(t0) {
169
174
  * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
170
175
  * the API answers that the user isn't authenticated, it calls `onUnauthorized`.
171
176
  */
172
- function Panneau({ config, adapter, plugins = [], queryClient, iconLoader = lucideIconLoader, onUnauthorized = redirectToLogin }) {
177
+ function Panneau({ config, adapter, plugins = [], queryClient, iconLoader = lucideIconLoader, onUnauthorized = redirectToLogin, maps = null }) {
173
178
  const [state] = useState(() => {
174
179
  const session = createSessionState();
175
180
  return {
@@ -188,7 +193,8 @@ function Panneau({ config, adapter, plugins = [], queryClient, iconLoader = luci
188
193
  plugins,
189
194
  iconLoader,
190
195
  session: state.session,
191
- onUnauthorized
196
+ onUnauthorized,
197
+ maps
192
198
  })
193
199
  })
194
200
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Panneau.js","names":["loginUrl","onRetry","styles","_c"],"sources":["../src/Panneau.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport {\n type PanneauPlugin,\n PanneauProvider,\n createHistoryRouter,\n createPluginRegistry,\n resolveTheme,\n} from '@panneau/core';\nimport { type DataAdapter, isApiError } from '@panneau/data';\nimport { createLaravelAdapter } from '@panneau/data/laravel';\nimport { DataAdapterProvider, definitionQueryOptions } from '@panneau/data/query';\nimport { appMessages } from '@panneau/intl';\nimport type { BootConfig } from '@panneau/protocol';\nimport { Button, type NamedIconLoader, PanneauRoot, Spinner, usePanneauIntl } from '@panneau/ui';\nimport { lucideIconLoader } from '@panneau/ui/named-icons';\n\nimport styles from './Panneau.module.css';\nimport { Shell } from './Shell';\nimport { usePreference } from './preferences';\nimport { COLOR_SCHEMES } from './shell/Sidebar';\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 * Loads the Lucide icons that the definition names (`\"icon\": \"users\"`). Defaults to every\n * Lucide icon, each one in its own chunk, loaded when shown. `null` shows no named icons.\n */\n iconLoader?: NamedIconLoader | null;\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 iconLoader,\n session,\n onUnauthorized,\n}: Required<Pick<PanneauProps, 'config' | 'adapter' | 'onUnauthorized'>> & {\n plugins: readonly PanneauPlugin[];\n iconLoader: NamedIconLoader | null;\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 [colorScheme, setColorScheme] = usePreference('color-scheme', COLOR_SCHEMES);\n const definition = definitionQuery.data;\n const loginUrl = getLoginUrl(definition, 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 const scheme = colorScheme ?? definition?.theme?.colorScheme ?? 'light';\n return (\n <PanneauRoot\n theme={\n definition !== undefined\n ? resolveTheme(definition.theme, createPluginRegistry(plugins).themes)\n : null\n }\n colorScheme={scheme}\n locale={definition?.locale ?? config.locale}\n iconLoader={iconLoader}\n className={styles.root}\n >\n {signedOut ? (\n <SessionEnded loginUrl={loginUrl} />\n ) : definition === undefined ? (\n <Loading\n isError={definitionQuery.isError}\n onRetry={() => void definitionQuery.refetch()}\n />\n ) : (\n <PanneauProvider plugins={plugins} definition={definition} router={router}>\n <Shell\n definition={definition}\n basePath={config.basePath}\n colorScheme={scheme}\n onColorSchemeChange={setColorScheme}\n />\n </PanneauProvider>\n )}\n </PanneauRoot>\n );\n}\n\nfunction SessionEnded({ loginUrl }: { loginUrl: string | null }) {\n const intl = usePanneauIntl();\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.sessionEnded)}</p>\n {loginUrl !== null ? (\n <a href={loginUrl}>{intl.formatMessage(appMessages.logIn)}</a>\n ) : null}\n </div>\n );\n}\n\nfunction Loading({ isError, onRetry }: { isError: boolean; onRetry: () => void }) {\n const intl = usePanneauIntl();\n if (isError) {\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.loadError)}</p>\n <Button onPress={onRetry}>{intl.formatMessage(appMessages.retry)}</Button>\n </div>\n );\n }\n return (\n <div className={styles.state}>\n <Spinner showLabel label={intl.formatMessage(appMessages.loading)} />\n </div>\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 iconLoader = lucideIconLoader,\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 iconLoader={iconLoader}\n session={state.session}\n onUnauthorized={onUnauthorized}\n />\n </DataAdapterProvider>\n </QueryClientProvider>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Panneau.js","names":["loginUrl","onRetry","styles","_c"],"sources":["../src/Panneau.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport {\n type PanneauPlugin,\n PanneauProvider,\n createHistoryRouter,\n createPluginRegistry,\n resolveTheme,\n} from '@panneau/core';\nimport { type DataAdapter, isApiError } from '@panneau/data';\nimport { createLaravelAdapter } from '@panneau/data/laravel';\nimport { DataAdapterProvider, definitionQueryOptions } from '@panneau/data/query';\nimport { FieldsProvider, type MapsConfig, createEmbedSource } from '@panneau/fields';\nimport { appMessages } from '@panneau/intl';\nimport type { BootConfig } from '@panneau/protocol';\nimport { Button, type NamedIconLoader, PanneauRoot, Spinner, usePanneauIntl } from '@panneau/ui';\nimport { lucideIconLoader } from '@panneau/ui/named-icons';\n\nimport styles from './Panneau.module.css';\nimport { Shell } from './Shell';\nimport { usePreference } from './preferences';\nimport { COLOR_SCHEMES } from './shell/Sidebar';\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 * Loads the Lucide icons that the definition names (`\"icon\": \"users\"`). Defaults to every\n * Lucide icon, each one in its own chunk, loaded when shown. `null` shows no named icons.\n */\n iconLoader?: NamedIconLoader | null;\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 * The tiles and the address search of the maps of `location` fields. Defaults to\n * OpenStreetMap's tiles, without an address search (decision 0033).\n */\n maps?: MapsConfig | null;\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 iconLoader,\n session,\n onUnauthorized,\n maps,\n}: Required<Pick<PanneauProps, 'config' | 'adapter' | 'onUnauthorized'>> & {\n plugins: readonly PanneauPlugin[];\n iconLoader: NamedIconLoader | null;\n maps: MapsConfig | null;\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 [colorScheme, setColorScheme] = usePreference('color-scheme', COLOR_SCHEMES);\n const definition = definitionQuery.data;\n const loginUrl = getLoginUrl(definition, 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 const scheme = colorScheme ?? definition?.theme?.colorScheme ?? 'light';\n return (\n <PanneauRoot\n theme={\n definition !== undefined\n ? resolveTheme(definition.theme, createPluginRegistry(plugins).themes)\n : null\n }\n colorScheme={scheme}\n locale={definition?.locale ?? config.locale}\n iconLoader={iconLoader}\n className={styles.root}\n >\n {signedOut ? (\n <SessionEnded loginUrl={loginUrl} />\n ) : definition === undefined ? (\n <Loading\n isError={definitionQuery.isError}\n onRetry={() => void definitionQuery.refetch()}\n />\n ) : (\n <PanneauProvider plugins={plugins} definition={definition} router={router}>\n {/* What `embed` and `location` fields need, in every form */}\n <FieldsProvider embedSource={createEmbedSource(adapter)} maps={maps}>\n <Shell\n definition={definition}\n basePath={config.basePath}\n colorScheme={scheme}\n onColorSchemeChange={setColorScheme}\n />\n </FieldsProvider>\n </PanneauProvider>\n )}\n </PanneauRoot>\n );\n}\n\nfunction SessionEnded({ loginUrl }: { loginUrl: string | null }) {\n const intl = usePanneauIntl();\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.sessionEnded)}</p>\n {loginUrl !== null ? (\n <a href={loginUrl}>{intl.formatMessage(appMessages.logIn)}</a>\n ) : null}\n </div>\n );\n}\n\nfunction Loading({ isError, onRetry }: { isError: boolean; onRetry: () => void }) {\n const intl = usePanneauIntl();\n if (isError) {\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.loadError)}</p>\n <Button onPress={onRetry}>{intl.formatMessage(appMessages.retry)}</Button>\n </div>\n );\n }\n return (\n <div className={styles.state}>\n <Spinner showLabel label={intl.formatMessage(appMessages.loading)} />\n </div>\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 iconLoader = lucideIconLoader,\n onUnauthorized = redirectToLogin,\n maps = null,\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 iconLoader={iconLoader}\n session={state.session}\n onUnauthorized={onUnauthorized}\n maps={maps}\n />\n </DataAdapterProvider>\n </QueryClientProvider>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { QueryClient } from '@tanstack/react-query';
2
2
  import type { PanneauPlugin } from '@panneau/core';
3
3
  import type { DataAdapter } from '@panneau/data';
4
+ import type { MapsConfig } from '@panneau/fields';
4
5
  import type { BootConfig, BootConfigInput } from '@panneau/protocol';
5
6
  import type { NamedIconLoader } from '@panneau/ui';
6
7
  import { type UnauthorizedContext } from './Panneau';
@@ -26,6 +27,11 @@ export interface PanneauAppOptions {
26
27
  * browser to the login URL, when there is one.
27
28
  */
28
29
  onUnauthorized?: (context: UnauthorizedContext) => void;
30
+ /**
31
+ * The tiles and the address search of the maps of `location` fields: `{ geocoding:
32
+ * createNominatimSource() }`. Defaults to OpenStreetMap's tiles, without an address search.
33
+ */
34
+ maps?: MapsConfig | null;
29
35
  }
30
36
  /** A mounted app. */
31
37
  export interface PanneauApp {
@@ -1 +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;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,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,uFAAuF;IACvF,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;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"}
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,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,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,uFAAuF;IACvF,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5B;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"}
@@ -1 +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';\nimport type { NamedIconLoader } from '@panneau/ui';\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 /** Loads the Lucide icons that the definition names. Defaults to every Lucide icon. */\n iconLoader?: NamedIconLoader | null;\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":";;;;;;;;;;;;;;;;AAsDA,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"}
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 { MapsConfig } from '@panneau/fields';\nimport type { BootConfig, BootConfigInput } from '@panneau/protocol';\nimport type { NamedIconLoader } from '@panneau/ui';\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 /** Loads the Lucide icons that the definition names. Defaults to every Lucide icon. */\n iconLoader?: NamedIconLoader | null;\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 * The tiles and the address search of the maps of `location` fields: `{ geocoding:\n * createNominatimSource() }`. Defaults to OpenStreetMap's tiles, without an address search.\n */\n maps?: MapsConfig | null;\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":";;;;;;;;;;;;;;;;AA4DA,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"}
@@ -9,10 +9,10 @@ import { getItemTitle } from "./itemTitle.js";
9
9
  import { c } from "react/compiler-runtime";
10
10
  import { getItemValues, resolveForm } from "@panneau/core";
11
11
  import { useCreateItem, useDataAdapter, useResourceItem, useUpdateItem } from "@panneau/data/query";
12
+ import { createRelationSource } from "@panneau/fields";
12
13
  import { appMessages } from "@panneau/intl";
13
14
  import { Alert, Button, Spinner, usePanneauIntl } from "@panneau/ui";
14
15
  import { jsx, jsxs } from "react/jsx-runtime";
15
- import { createRelationSource } from "@panneau/fields";
16
16
  import { Form } from "@panneau/forms";
17
17
  //#region src/pages/ResourceFormPage.tsx
18
18
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panneau/app",
3
- "version": "5.0.0-alpha.5",
3
+ "version": "5.0.0-alpha.6",
4
4
  "description": "The Panneau admin panel: the app entry (createPanneauApp), the shell with its sidebar, and the pages of resources.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -39,15 +39,15 @@
39
39
  "react-intl": "^12.0.0"
40
40
  },
41
41
  "dependencies": {
42
- "@panneau/actions": "5.0.0-alpha.5",
43
- "@panneau/core": "5.0.0-alpha.5",
44
- "@panneau/data": "5.0.0-alpha.5",
45
- "@panneau/fields": "5.0.0-alpha.5",
46
- "@panneau/forms": "5.0.0-alpha.5",
47
- "@panneau/intl": "5.0.0-alpha.5",
48
- "@panneau/lists": "5.0.0-alpha.5",
49
- "@panneau/protocol": "5.0.0-alpha.5",
50
- "@panneau/ui": "5.0.0-alpha.5",
42
+ "@panneau/actions": "5.0.0-alpha.6",
43
+ "@panneau/core": "5.0.0-alpha.6",
44
+ "@panneau/data": "5.0.0-alpha.6",
45
+ "@panneau/fields": "5.0.0-alpha.6",
46
+ "@panneau/forms": "5.0.0-alpha.6",
47
+ "@panneau/intl": "5.0.0-alpha.6",
48
+ "@panneau/lists": "5.0.0-alpha.6",
49
+ "@panneau/protocol": "5.0.0-alpha.6",
50
+ "@panneau/ui": "5.0.0-alpha.6",
51
51
  "lucide-react": "^1.57.0"
52
52
  }
53
53
  }