@panneau/app 5.0.0-alpha.4 → 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.
Files changed (103) hide show
  1. package/README.md +33 -5
  2. package/dist/Panneau.css +19 -0
  3. package/dist/Panneau.d.ts +13 -1
  4. package/dist/Panneau.d.ts.map +1 -1
  5. package/dist/Panneau.js +144 -31
  6. package/dist/Panneau.js.map +1 -1
  7. package/dist/Panneau.module.js +12 -0
  8. package/dist/Panneau.module.js.map +1 -0
  9. package/dist/Shell.d.ts +8 -3
  10. package/dist/Shell.d.ts.map +1 -1
  11. package/dist/Shell.js +272 -114
  12. package/dist/Shell.js.map +1 -1
  13. package/dist/createPanneauApp.d.ts +9 -0
  14. package/dist/createPanneauApp.d.ts.map +1 -1
  15. package/dist/createPanneauApp.js.map +1 -1
  16. package/dist/cx.d.ts +3 -0
  17. package/dist/cx.d.ts.map +1 -0
  18. package/dist/cx.js +9 -0
  19. package/dist/cx.js.map +1 -0
  20. package/dist/documentTitle.d.ts +10 -0
  21. package/dist/documentTitle.d.ts.map +1 -0
  22. package/dist/documentTitle.js +49 -0
  23. package/dist/documentTitle.js.map +1 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -1
  27. package/dist/location.d.ts +13 -1
  28. package/dist/location.d.ts.map +1 -1
  29. package/dist/location.js +55 -48
  30. package/dist/location.js.map +1 -1
  31. package/dist/navigation.d.ts +53 -0
  32. package/dist/navigation.d.ts.map +1 -0
  33. package/dist/navigation.js +117 -0
  34. package/dist/navigation.js.map +1 -0
  35. package/dist/pages/HomePage.d.ts +11 -0
  36. package/dist/pages/HomePage.d.ts.map +1 -0
  37. package/dist/pages/HomePage.js +111 -0
  38. package/dist/pages/HomePage.js.map +1 -0
  39. package/dist/pages/ItemPanel.css +164 -0
  40. package/dist/pages/ItemPanel.d.ts +17 -0
  41. package/dist/pages/ItemPanel.d.ts.map +1 -0
  42. package/dist/pages/ItemPanel.js +370 -0
  43. package/dist/pages/ItemPanel.js.map +1 -0
  44. package/dist/pages/ItemPanel.module.js +34 -0
  45. package/dist/pages/ItemPanel.module.js.map +1 -0
  46. package/dist/pages/ItemPreview.d.ts +15 -0
  47. package/dist/pages/ItemPreview.d.ts.map +1 -0
  48. package/dist/pages/ItemPreview.js +179 -0
  49. package/dist/pages/ItemPreview.js.map +1 -0
  50. package/dist/pages/NotFoundPage.d.ts +6 -0
  51. package/dist/pages/NotFoundPage.d.ts.map +1 -0
  52. package/dist/pages/NotFoundPage.js +93 -0
  53. package/dist/pages/NotFoundPage.js.map +1 -0
  54. package/dist/pages/PageHeader.d.ts +21 -0
  55. package/dist/pages/PageHeader.d.ts.map +1 -0
  56. package/dist/pages/PageHeader.js +86 -0
  57. package/dist/pages/PageHeader.js.map +1 -0
  58. package/dist/pages/ResourceFormPage.d.ts +15 -0
  59. package/dist/pages/ResourceFormPage.d.ts.map +1 -0
  60. package/dist/pages/ResourceFormPage.js +204 -0
  61. package/dist/pages/ResourceFormPage.js.map +1 -0
  62. package/dist/pages/ResourceListPage.d.ts +15 -0
  63. package/dist/pages/ResourceListPage.d.ts.map +1 -0
  64. package/dist/pages/ResourceListPage.js +101 -0
  65. package/dist/pages/ResourceListPage.js.map +1 -0
  66. package/dist/pages/itemTitle.d.ts +7 -0
  67. package/dist/pages/itemTitle.d.ts.map +1 -0
  68. package/dist/pages/itemTitle.js +18 -0
  69. package/dist/pages/itemTitle.js.map +1 -0
  70. package/dist/pages/pages.css +162 -0
  71. package/dist/pages/pages.module.js +40 -0
  72. package/dist/pages/pages.module.js.map +1 -0
  73. package/dist/preferences.d.ts +6 -0
  74. package/dist/preferences.d.ts.map +1 -0
  75. package/dist/preferences.js +53 -0
  76. package/dist/preferences.js.map +1 -0
  77. package/dist/recentItems.d.ts +15 -0
  78. package/dist/recentItems.d.ts.map +1 -0
  79. package/dist/recentItems.js +70 -0
  80. package/dist/recentItems.js.map +1 -0
  81. package/dist/shell/AppLayout.css +189 -0
  82. package/dist/shell/AppLayout.d.ts +22 -0
  83. package/dist/shell/AppLayout.d.ts.map +1 -0
  84. package/dist/shell/AppLayout.js +365 -0
  85. package/dist/shell/AppLayout.js.map +1 -0
  86. package/dist/shell/AppLayout.module.js +36 -0
  87. package/dist/shell/AppLayout.module.js.map +1 -0
  88. package/dist/shell/GoTo.d.ts +20 -0
  89. package/dist/shell/GoTo.d.ts.map +1 -0
  90. package/dist/shell/GoTo.js +370 -0
  91. package/dist/shell/GoTo.js.map +1 -0
  92. package/dist/shell/Sidebar.css +313 -0
  93. package/dist/shell/Sidebar.d.ts +29 -0
  94. package/dist/shell/Sidebar.d.ts.map +1 -0
  95. package/dist/shell/Sidebar.js +225 -0
  96. package/dist/shell/Sidebar.js.map +1 -0
  97. package/dist/shell/Sidebar.module.js +60 -0
  98. package/dist/shell/Sidebar.module.js.map +1 -0
  99. package/dist/shell/tokens.d.ts +23 -0
  100. package/dist/shell/tokens.d.ts.map +1 -0
  101. package/dist/shell/tokens.js +75 -0
  102. package/dist/shell/tokens.js.map +1 -0
  103. package/package.json +15 -6
package/dist/Shell.js CHANGED
@@ -1,142 +1,300 @@
1
- import { Link, usePathname } from "./location.js";
1
+ import { DocumentTitle } from "./documentTitle.js";
2
+ import { navigate, setHistoryGuard, usePathname } from "./location.js";
2
3
  import { matchRoute, routePath } from "./routes.js";
4
+ import { HomePage } from "./pages/HomePage.js";
5
+ import { NotFoundPage } from "./pages/NotFoundPage.js";
6
+ import { ResourceFormPage } from "./pages/ResourceFormPage.js";
7
+ import { ResourceListPage } from "./pages/ResourceListPage.js";
8
+ import { AppLayout } from "./shell/AppLayout.js";
9
+ import { createElement, useEffect, useState } from "react";
3
10
  import { c } from "react/compiler-runtime";
4
- import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { useQueryClient } from "@tanstack/react-query";
12
+ import { LeaveGuardsProvider, createLeaveGuards, findResource, resolveResource, usePlugins } from "@panneau/core";
13
+ import { invalidateActionResult, useDataAdapter } from "@panneau/data/query";
14
+ import { appMessages } from "@panneau/intl";
15
+ import { Alert, usePanneauIntl } from "@panneau/ui";
16
+ import { RouterProvider } from "react-aria-components";
17
+ import { ActionRunnerProvider, ActionRuns } from "@panneau/actions";
18
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
19
  //#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;
20
+ /** The path of a named route of the definition (`routes`), with its parameters filled in. */
21
+ function resolveRoute(definition, { route, params = {} }) {
22
+ const path = definition.routes?.[route];
23
+ if (path === void 0) {
24
+ console.warn(`[panneau] The definition has no route "${route}".`);
25
+ return null;
11
26
  }
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";
27
+ return path.replace(/\{(\w+)\}/g, (match, name) => params[name] !== void 0 ? encodeURIComponent(String(params[name])) : match);
28
+ }
29
+ function Page(t0) {
30
+ const $ = c(36);
31
+ const { definition, basePath, route } = t0;
32
+ const intl = usePanneauIntl();
33
+ const plugins = usePlugins();
34
+ let t1;
35
+ if ($[0] !== basePath) {
36
+ t1 = routePath({ name: "home" }, basePath);
37
+ $[0] = basePath;
38
+ $[1] = t1;
39
+ } else t1 = $[1];
40
+ let t2;
41
+ if ($[2] !== t1) {
42
+ t2 = /* @__PURE__ */ jsx(NotFoundPage, { homeHref: t1 });
43
+ $[2] = t1;
44
+ $[3] = t2;
45
+ } else t2 = $[3];
46
+ const notFound = t2;
15
47
  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}`;
48
+ case "home": {
49
+ let t3;
50
+ if ($[4] !== basePath || $[5] !== definition) {
51
+ t3 = /* @__PURE__ */ jsx(HomePage, {
52
+ definition,
53
+ basePath
54
+ });
55
+ $[4] = basePath;
56
+ $[5] = definition;
57
+ $[6] = t3;
58
+ } else t3 = $[6];
59
+ return t3;
60
+ }
61
+ case "not-found": return notFound;
62
+ case "page": {
63
+ const page = definition.pages?.[route.page];
64
+ if (page === void 0) return notFound;
65
+ let t3;
66
+ if ($[7] !== definition || $[8] !== intl || $[9] !== page.component || $[10] !== page.label || $[11] !== page.props || $[12] !== plugins.pages) {
67
+ const Component = plugins.pages.get(page.component);
68
+ let t4;
69
+ if ($[14] !== page.label) {
70
+ t4 = /* @__PURE__ */ jsx(DocumentTitle, { parts: [page.label] });
71
+ $[14] = page.label;
72
+ $[15] = t4;
73
+ } else t4 = $[15];
74
+ t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t4, Component !== void 0 ? createElement(Component, {
75
+ ...page.props,
76
+ definition
77
+ }) : /* @__PURE__ */ jsx(Alert, {
78
+ tone: "warning",
79
+ children: intl.formatMessage(appMessages.missingPage, { component: page.component })
80
+ })] });
81
+ $[7] = definition;
82
+ $[8] = intl;
83
+ $[9] = page.component;
84
+ $[10] = page.label;
85
+ $[11] = page.props;
86
+ $[12] = plugins.pages;
87
+ $[13] = t3;
88
+ } else t3 = $[13];
89
+ return t3;
90
+ }
91
+ default: {
92
+ let resource;
93
+ let t3;
94
+ let t4;
95
+ if ($[16] !== definition || $[17] !== notFound || $[18] !== route.resource) {
96
+ t4 = Symbol.for("react.early_return_sentinel");
97
+ bb0: {
98
+ resource = findResource(definition, route.resource);
99
+ if (resource === void 0) {
100
+ t4 = notFound;
101
+ break bb0;
102
+ }
103
+ t3 = resolveResource(resource);
104
+ }
105
+ $[16] = definition;
106
+ $[17] = notFound;
107
+ $[18] = route.resource;
108
+ $[19] = resource;
109
+ $[20] = t3;
110
+ $[21] = t4;
111
+ } else {
112
+ resource = $[19];
113
+ t3 = $[20];
114
+ t4 = $[21];
115
+ }
116
+ if (t4 !== Symbol.for("react.early_return_sentinel")) return t4;
117
+ const resolved = t3;
118
+ if (route.name === "resource.index" || route.name === "resource.show") {
119
+ let t5;
120
+ if ($[22] !== basePath || $[23] !== definition || $[24] !== notFound || $[25] !== resolved || $[26] !== resource || $[27] !== route.id || $[28] !== route.name) {
121
+ t5 = resolved.abilities.viewAny ? /* @__PURE__ */ jsx(ResourceListPage, {
122
+ resolved,
123
+ basePath,
124
+ locale: definition.locale,
125
+ selectedId: route.name === "resource.show" ? route.id : null
126
+ }, resource.id) : notFound;
127
+ $[22] = basePath;
128
+ $[23] = definition;
129
+ $[24] = notFound;
130
+ $[25] = resolved;
131
+ $[26] = resource;
132
+ $[27] = route.id;
133
+ $[28] = route.name;
134
+ $[29] = t5;
135
+ } else t5 = $[29];
136
+ return t5;
137
+ }
138
+ const t5 = `${resource.id}/${route.name === "resource.create" ? "" : route.id}`;
139
+ const t6 = route.name === "resource.create" ? null : route.id;
140
+ let t7;
141
+ if ($[30] !== basePath || $[31] !== definition || $[32] !== resolved || $[33] !== t5 || $[34] !== t6) {
142
+ t7 = /* @__PURE__ */ jsx(ResourceFormPage, {
143
+ definition,
144
+ resolved,
145
+ basePath,
146
+ id: t6
147
+ }, t5);
148
+ $[30] = basePath;
149
+ $[31] = definition;
150
+ $[32] = resolved;
151
+ $[33] = t5;
152
+ $[34] = t6;
153
+ $[35] = t7;
154
+ } else t7 = $[35];
155
+ return t7;
156
+ }
20
157
  }
21
158
  }
22
159
  /**
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.
160
+ * The app shell: the layout with its sidebar, and the page of the current route. Links go
161
+ * through the history of the browser without reloading the page, and actions run through the
162
+ * adapter, refreshing what their result changed. Leaving a page with unsaved changes, by a link
163
+ * or by going back or forward, asks first.
25
164
  */
26
165
  function Shell(t0) {
27
- const $ = c(34);
28
- const { definition, basePath } = t0;
166
+ const $ = c(38);
167
+ const { definition, basePath, colorScheme, onColorSchemeChange } = t0;
29
168
  const pathname = usePathname();
169
+ const queryClient = useQueryClient();
170
+ const adapter = useDataAdapter();
30
171
  let t1;
172
+ if ($[0] !== basePath || $[1] !== pathname) {
173
+ t1 = matchRoute(pathname, basePath) ?? { name: "not-found" };
174
+ $[0] = basePath;
175
+ $[1] = pathname;
176
+ $[2] = t1;
177
+ } else t1 = $[2];
178
+ const route = t1;
179
+ const [guards] = useState(createLeaveGuards);
31
180
  let t2;
32
181
  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;
182
+ if ($[3] !== guards) {
183
+ t2 = () => setHistoryGuard(guards);
184
+ t3 = [guards];
185
+ $[3] = guards;
97
186
  $[4] = t2;
98
187
  $[5] = t3;
99
- $[6] = t4;
100
188
  } else {
101
- t1 = $[3];
102
189
  t2 = $[4];
103
190
  t3 = $[5];
104
- t4 = $[6];
105
191
  }
192
+ useEffect(t2, t3);
193
+ let t4;
194
+ if ($[6] !== basePath || $[7] !== guards) {
195
+ t4 = (href) => {
196
+ const url = new URL(href, window.location.href);
197
+ if (url.origin === window.location.origin && matchRoute(url.pathname, basePath) !== null) guards.confirmLeave().then((leave) => {
198
+ if (leave) navigate(`${url.pathname}${url.search}${url.hash}`);
199
+ });
200
+ else window.location.assign(url);
201
+ };
202
+ $[6] = basePath;
203
+ $[7] = guards;
204
+ $[8] = t4;
205
+ } else t4 = $[8];
206
+ const go = t4;
106
207
  let t5;
107
- if ($[24] !== t1) {
108
- t5 = /* @__PURE__ */ jsx("h1", { children: t1 });
109
- $[24] = t1;
110
- $[25] = t5;
111
- } else t5 = $[25];
208
+ if ($[9] !== queryClient) {
209
+ t5 = (result, t6) => {
210
+ const { resource, target } = t6;
211
+ return invalidateActionResult(queryClient, resource, result, target.selection);
212
+ };
213
+ $[9] = queryClient;
214
+ $[10] = t5;
215
+ } else t5 = $[10];
112
216
  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];
217
+ if ($[11] !== definition || $[12] !== go) {
218
+ t6 = (to) => {
219
+ const path = typeof to === "string" ? to : resolveRoute(definition, to);
220
+ if (path !== null) go(path);
221
+ };
222
+ $[11] = definition;
223
+ $[12] = go;
224
+ $[13] = t6;
225
+ } else t6 = $[13];
117
226
  let t7;
118
- if ($[27] !== t5) {
119
- t7 = /* @__PURE__ */ jsxs("main", { children: [t5, t6] });
120
- $[27] = t5;
121
- $[28] = t7;
122
- } else t7 = $[28];
227
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
228
+ t7 = /* @__PURE__ */ jsx(ActionRuns, {});
229
+ $[14] = t7;
230
+ } else t7 = $[14];
123
231
  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
- ]
232
+ if ($[15] !== basePath || $[16] !== definition || $[17] !== route) {
233
+ t8 = /* @__PURE__ */ jsx(Page, {
234
+ definition,
235
+ basePath,
236
+ route
237
+ });
238
+ $[15] = basePath;
239
+ $[16] = definition;
240
+ $[17] = route;
241
+ $[18] = t8;
242
+ } else t8 = $[18];
243
+ let t9;
244
+ if ($[19] !== basePath || $[20] !== colorScheme || $[21] !== definition || $[22] !== onColorSchemeChange || $[23] !== route || $[24] !== t8) {
245
+ t9 = /* @__PURE__ */ jsxs(AppLayout, {
246
+ definition,
247
+ basePath,
248
+ route,
249
+ colorScheme,
250
+ onColorSchemeChange,
251
+ children: [t7, t8]
252
+ });
253
+ $[19] = basePath;
254
+ $[20] = colorScheme;
255
+ $[21] = definition;
256
+ $[22] = onColorSchemeChange;
257
+ $[23] = route;
258
+ $[24] = t8;
259
+ $[25] = t9;
260
+ } else t9 = $[25];
261
+ let t10;
262
+ if ($[26] !== adapter || $[27] !== definition.locales || $[28] !== t5 || $[29] !== t6 || $[30] !== t9) {
263
+ t10 = /* @__PURE__ */ jsx(ActionRunnerProvider, {
264
+ adapter,
265
+ locales: definition.locales,
266
+ onResult: t5,
267
+ onNavigate: t6,
268
+ children: t9
269
+ });
270
+ $[26] = adapter;
271
+ $[27] = definition.locales;
272
+ $[28] = t5;
273
+ $[29] = t6;
274
+ $[30] = t9;
275
+ $[31] = t10;
276
+ } else t10 = $[31];
277
+ let t11;
278
+ if ($[32] !== go || $[33] !== t10) {
279
+ t11 = /* @__PURE__ */ jsx(RouterProvider, {
280
+ navigate: go,
281
+ children: t10
282
+ });
283
+ $[32] = go;
284
+ $[33] = t10;
285
+ $[34] = t11;
286
+ } else t11 = $[34];
287
+ let t12;
288
+ if ($[35] !== guards || $[36] !== t11) {
289
+ t12 = /* @__PURE__ */ jsx(LeaveGuardsProvider, {
290
+ guards,
291
+ children: t11
132
292
  });
133
- $[29] = t2;
134
- $[30] = t3;
135
- $[31] = t4;
136
- $[32] = t7;
137
- $[33] = t8;
138
- } else t8 = $[33];
139
- return t8;
293
+ $[35] = guards;
294
+ $[36] = t11;
295
+ $[37] = t12;
296
+ } else t12 = $[37];
297
+ return t12;
140
298
  }
141
299
  //#endregion
142
300
  export { Shell };
package/dist/Shell.js.map CHANGED
@@ -1 +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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"}
1
+ {"version":3,"file":"Shell.js","names":["definition","basePath","notFound","resolved","route","colorScheme","onColorSchemeChange","adapter","go","guards","_c","_Fragment"],"sources":["../src/Shell.tsx"],"sourcesContent":["import { useQueryClient } from '@tanstack/react-query';\nimport { createElement, useEffect, useState } from 'react';\nimport { RouterProvider } from 'react-aria-components';\n\nimport { ActionRunnerProvider, ActionRuns } from '@panneau/actions';\nimport {\n LeaveGuardsProvider,\n createLeaveGuards,\n findResource,\n resolveResource,\n usePlugins,\n} from '@panneau/core';\nimport { invalidateActionResult, useDataAdapter } from '@panneau/data/query';\nimport { appMessages } from '@panneau/intl';\nimport type { Definition, RouteReference } from '@panneau/protocol';\nimport { Alert, usePanneauIntl } from '@panneau/ui';\n\nimport { DocumentTitle } from './documentTitle';\nimport { navigate, setHistoryGuard, usePathname } from './location';\nimport { HomePage } from './pages/HomePage';\nimport { NotFoundPage } from './pages/NotFoundPage';\nimport { ResourceFormPage } from './pages/ResourceFormPage';\nimport { ResourceListPage } from './pages/ResourceListPage';\nimport { type AppRoute, matchRoute, routePath } from './routes';\nimport { AppLayout } from './shell/AppLayout';\nimport type { ColorSchemePreference } from './shell/Sidebar';\n\nexport interface ShellProps {\n definition: Definition;\n basePath: string;\n colorScheme: ColorSchemePreference;\n onColorSchemeChange: (scheme: ColorSchemePreference) => void;\n}\n\n/** The path of a named route of the definition (`routes`), with its parameters filled in. */\nfunction resolveRoute(definition: Definition, { route, params = {} }: RouteReference) {\n const path = definition.routes?.[route];\n if (path === undefined) {\n console.warn(`[panneau] The definition has no route \"${route}\".`);\n return null;\n }\n return path.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n params[name] !== undefined ? encodeURIComponent(String(params[name])) : match,\n );\n}\n\nfunction Page({\n definition,\n basePath,\n route,\n}: {\n definition: Definition;\n basePath: string;\n route: AppRoute;\n}) {\n const intl = usePanneauIntl();\n const plugins = usePlugins();\n const notFound = <NotFoundPage homeHref={routePath({ name: 'home' }, basePath)} />;\n switch (route.name) {\n case 'home':\n return <HomePage definition={definition} basePath={basePath} />;\n case 'not-found':\n return notFound;\n case 'page': {\n const page = definition.pages?.[route.page];\n if (page === undefined) {\n return notFound;\n }\n const Component = plugins.pages.get(page.component);\n // Before the page: a page that sets its own title sets it last\n return (\n <>\n <DocumentTitle parts={[page.label]} />\n {Component !== undefined ? (\n createElement(Component, { ...page.props, definition })\n ) : (\n <Alert tone=\"warning\">\n {intl.formatMessage(appMessages.missingPage, {\n component: page.component,\n })}\n </Alert>\n )}\n </>\n );\n }\n default: {\n const resource = findResource(definition, route.resource);\n if (resource === undefined) {\n return notFound;\n }\n const resolved = resolveResource(resource);\n if (route.name === 'resource.index' || route.name === 'resource.show') {\n // The show route is the list with the item's details in a panel: the same page,\n // so the list keeps its state while the panel opens, closes or changes item.\n return resolved.abilities.viewAny ? (\n <ResourceListPage\n key={resource.id}\n resolved={resolved}\n basePath={basePath}\n locale={definition.locale}\n selectedId={route.name === 'resource.show' ? route.id : null}\n />\n ) : (\n notFound\n );\n }\n return (\n <ResourceFormPage\n key={`${resource.id}/${route.name === 'resource.create' ? '' : route.id}`}\n definition={definition}\n resolved={resolved}\n basePath={basePath}\n id={route.name === 'resource.create' ? null : route.id}\n />\n );\n }\n }\n}\n\n/**\n * The app shell: the layout with its sidebar, and the page of the current route. Links go\n * through the history of the browser without reloading the page, and actions run through the\n * adapter, refreshing what their result changed. Leaving a page with unsaved changes, by a link\n * or by going back or forward, asks first.\n */\nexport function Shell({ definition, basePath, colorScheme, onColorSchemeChange }: ShellProps) {\n const pathname = usePathname();\n const queryClient = useQueryClient();\n const adapter = useDataAdapter();\n const route = matchRoute(pathname, basePath) ?? { name: 'not-found' };\n // Forms with unsaved changes guard leaving their page\n const [guards] = useState(createLeaveGuards);\n useEffect(() => setHistoryGuard(guards), [guards]);\n // Paths outside the app (a link to the site) load their page: the browser guards them.\n const go = (href: string) => {\n const url = new URL(href, window.location.href);\n if (url.origin === window.location.origin && matchRoute(url.pathname, basePath) !== null) {\n void guards.confirmLeave().then((leave) => {\n if (leave) {\n navigate(`${url.pathname}${url.search}${url.hash}`);\n }\n });\n } else {\n window.location.assign(url);\n }\n };\n return (\n <LeaveGuardsProvider guards={guards}>\n <RouterProvider navigate={go}>\n <ActionRunnerProvider\n adapter={adapter}\n locales={definition.locales}\n onResult={(result, { resource, target }) =>\n invalidateActionResult(queryClient, resource, result, target.selection)\n }\n onNavigate={(to) => {\n const path = typeof to === 'string' ? to : resolveRoute(definition, to);\n if (path !== null) {\n go(path);\n }\n }}\n >\n <AppLayout\n definition={definition}\n basePath={basePath}\n route={route}\n colorScheme={colorScheme}\n onColorSchemeChange={onColorSchemeChange}\n >\n <ActionRuns />\n <Page definition={definition} basePath={basePath} route={route} />\n </AppLayout>\n </ActionRunnerProvider>\n </RouterProvider>\n </LeaveGuardsProvider>\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,9 @@
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';
6
+ import type { NamedIconLoader } from '@panneau/ui';
5
7
  import { type UnauthorizedContext } from './Panneau';
6
8
  /** Options of `createPanneauApp()`. */
7
9
  export interface PanneauAppOptions {
@@ -18,11 +20,18 @@ export interface PanneauAppOptions {
18
20
  config?: BootConfigInput;
19
21
  /** The TanStack Query client. Defaults to a new one. */
20
22
  queryClient?: QueryClient;
23
+ /** Loads the Lucide icons that the definition names. Defaults to every Lucide icon. */
24
+ iconLoader?: NamedIconLoader | null;
21
25
  /**
22
26
  * Called once when the API answers that the user isn't authenticated. Defaults to sending the
23
27
  * browser to the login URL, when there is one.
24
28
  */
25
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;
26
35
  }
27
36
  /** A mounted app. */
28
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;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"}
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';\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"}
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"}
package/dist/cx.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** Joins class names, skipping empty ones. */
2
+ export declare function cx(...classNames: (string | false | null | undefined)[]): string;
3
+ //# sourceMappingURL=cx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cx.d.ts","sourceRoot":"","sources":["../src/cx.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,wBAAgB,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,CAE/E"}
package/dist/cx.js ADDED
@@ -0,0 +1,9 @@
1
+ //#region src/cx.ts
2
+ /** Joins class names, skipping empty ones. */
3
+ function cx(...classNames) {
4
+ return classNames.filter(Boolean).join(" ");
5
+ }
6
+ //#endregion
7
+ export { cx };
8
+
9
+ //# sourceMappingURL=cx.js.map
package/dist/cx.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cx.js","names":[],"sources":["../src/cx.ts"],"sourcesContent":["/** Joins class names, skipping empty ones. */\nexport function cx(...classNames: (string | false | null | undefined)[]): string {\n return classNames.filter(Boolean).join(' ');\n}\n"],"mappings":";;AACA,SAAgB,GAAG,GAAG,YAA2D;CAC7E,OAAO,WAAW,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAC9C"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sets the title of the browser's tab: the parts of the page, most specific first, then the name
3
+ * of the app (`Ten walks for the fall · Articles · Northwind Journal`). Empty parts are left out.
4
+ */
5
+ export declare function useDocumentTitle(parts: readonly (string | null | undefined)[]): void;
6
+ /** Sets the title of the browser's tab, as `useDocumentTitle()`. Renders nothing. */
7
+ export declare function DocumentTitle({ parts }: {
8
+ parts: readonly (string | null | undefined)[];
9
+ }): null;
10
+ //# sourceMappingURL=documentTitle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentTitle.d.ts","sourceRoot":"","sources":["../src/documentTitle.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAUpF;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAA;CAAE,QAGzF"}
@@ -0,0 +1,49 @@
1
+ import { useEffect } from "react";
2
+ import { c } from "react/compiler-runtime";
3
+ import { usePanneau } from "@panneau/core";
4
+ //#region src/documentTitle.ts
5
+ /**
6
+ * Sets the title of the browser's tab: the parts of the page, most specific first, then the name
7
+ * of the app (`Ten walks for the fall · Articles · Northwind Journal`). Empty parts are left out.
8
+ */
9
+ function useDocumentTitle(parts) {
10
+ const $ = c(6);
11
+ const { definition } = usePanneau();
12
+ const t0 = definition?.name;
13
+ let t1;
14
+ if ($[0] !== parts || $[1] !== t0) {
15
+ t1 = [...parts, t0].filter(_temp);
16
+ $[0] = parts;
17
+ $[1] = t0;
18
+ $[2] = t1;
19
+ } else t1 = $[2];
20
+ const title = t1.join(" · ");
21
+ let t2;
22
+ let t3;
23
+ if ($[3] !== title) {
24
+ t2 = () => {
25
+ if (title !== "") document.title = title;
26
+ };
27
+ t3 = [title];
28
+ $[3] = title;
29
+ $[4] = t2;
30
+ $[5] = t3;
31
+ } else {
32
+ t2 = $[4];
33
+ t3 = $[5];
34
+ }
35
+ useEffect(t2, t3);
36
+ }
37
+ /** Sets the title of the browser's tab, as `useDocumentTitle()`. Renders nothing. */
38
+ function _temp(part) {
39
+ return typeof part === "string" && part.trim() !== "";
40
+ }
41
+ function DocumentTitle(t0) {
42
+ const { parts } = t0;
43
+ useDocumentTitle(parts);
44
+ return null;
45
+ }
46
+ //#endregion
47
+ export { DocumentTitle, useDocumentTitle };
48
+
49
+ //# sourceMappingURL=documentTitle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentTitle.js","names":["_c"],"sources":["../src/documentTitle.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nimport { usePanneau } from '@panneau/core';\n\n/**\n * Sets the title of the browser's tab: the parts of the page, most specific first, then the name\n * of the app (`Ten walks for the fall · Articles · Northwind Journal`). Empty parts are left out.\n */\nexport function useDocumentTitle(parts: readonly (string | null | undefined)[]): void {\n const { definition } = usePanneau();\n const title = [...parts, definition?.name]\n .filter((part): part is string => typeof part === 'string' && part.trim() !== '')\n .join(' · ');\n useEffect(() => {\n if (title !== '') {\n document.title = title;\n }\n }, [title]);\n}\n\n/** Sets the title of the browser's tab, as `useDocumentTitle()`. Renders nothing. */\nexport function DocumentTitle({ parts }: { parts: readonly (string | null | undefined)[] }) {\n useDocumentTitle(parts);\n return null;\n}\n"],"mappings":";;;;;;;;AAQA,SAAO,iBAAA,OAAA;CAAA,MAAA,IAAAA,EAAA,CAAA;CACH,MAAA,EAAA,eAAuB,WAAW;CACT,MAAA,KAAA,YAAU;CAAM,IAAA;CAAA,IAAA,EAAA,OAAA,SAAA,EAAA,OAAA,IAAA;EAA3B,KAAA,CAAA,GAAI,OAAO,EAAgB,CAAC,CAAA,OAC9B,KAAwE;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CADrF,MAAA,QAAc,GACuE,KAC3E,KAAK;CAAE,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EACP,WAAA;GACN,IAAI,UAAU,IACV,SAAQ,QAAS;EACpB;EACF,KAAA,CAAC,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAJV,UAAU,IAIP,EAAO;AAAC;;AATR,SAAA,MAAA,MAAA;CAAA,OAGmC,OAAO,SAAS,YAAY,KAAI,KAAM,MAAM;AAAE;AAUxF,SAAO,cAAA,IAAA;CAAuB,MAAA,EAAA,UAAA;CAC1B,iBAAiB,KAAK;CAAC,OAChB;AAAI"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { createPanneauApp, type PanneauApp, type PanneauAppOptions } from './createPanneauApp';
2
2
  export { Panneau, type PanneauProps, type UnauthorizedContext } from './Panneau';
3
3
  export { readBootConfig } from './boot';
4
+ export { appComponentTokens, itemPanelTokens, shellTokens, sidebarTokens } from './shell/tokens';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
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;AACxC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Panneau } from "./Panneau.js";
2
2
  import { readBootConfig } from "./boot.js";
3
3
  import { createPanneauApp } from "./createPanneauApp.js";
4
- export { Panneau, createPanneauApp, readBootConfig };
4
+ import { appComponentTokens, itemPanelTokens, shellTokens, sidebarTokens } from "./shell/tokens.js";
5
+ export { Panneau, appComponentTokens, createPanneauApp, itemPanelTokens, readBootConfig, shellTokens, sidebarTokens };
@@ -1,7 +1,19 @@
1
1
  import { type ComponentProps } from 'react';
2
+ /** What guards going back or forward, such as forms with unsaved changes. */
3
+ export interface HistoryGuard {
4
+ /** Whether going back or forward needs a confirmation now. */
5
+ isBlocking(): boolean;
6
+ /** Resolves `true` to leave, `false` to stay. */
7
+ confirmLeave(): Promise<boolean>;
8
+ }
2
9
  /** The current path, updated on navigation and on back and forward. */
3
10
  export declare function usePathname(): string;
4
- /** Navigates to a path of the app, without reloading the page. */
11
+ /**
12
+ * Sets what guards going back and forward: the shell's leave guards. Returns a function that
13
+ * removes it.
14
+ */
15
+ export declare function setHistoryGuard(next: HistoryGuard): () => void;
16
+ /** Navigates to a path of the app, without reloading the page. It doesn't ask the guards. */
5
17
  export declare function navigate(path: string): void;
6
18
  /** A link to a path of the app. Plain clicks navigate without reloading the page. */
7
19
  export declare function Link({ href, onClick, ...props }: ComponentProps<'a'> & {