@commercetools-demo/puck-page-manager 0.1.0

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.
@@ -0,0 +1,18 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Config } from '@measured/puck';
3
+
4
+ interface PageManagerProps {
5
+ /** URL path where this manager is mounted, e.g. "/pages" — used as router basename */
6
+ parentUrl: string;
7
+ baseURL: string;
8
+ projectKey: string;
9
+ businessUnitKey: string;
10
+ jwtToken: string;
11
+ /** Puck component config — passed to editor and preview */
12
+ config: Config;
13
+ /** Optional element rendered before the breadcrumb in editor/preview headers */
14
+ backButton?: ReactNode;
15
+ }
16
+ declare const PageManager: React.FC<PageManagerProps>;
17
+
18
+ export { PageManager, type PageManagerProps };
@@ -0,0 +1,18 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Config } from '@measured/puck';
3
+
4
+ interface PageManagerProps {
5
+ /** URL path where this manager is mounted, e.g. "/pages" — used as router basename */
6
+ parentUrl: string;
7
+ baseURL: string;
8
+ projectKey: string;
9
+ businessUnitKey: string;
10
+ jwtToken: string;
11
+ /** Puck component config — passed to editor and preview */
12
+ config: Config;
13
+ /** Optional element rendered before the breadcrumb in editor/preview headers */
14
+ backButton?: ReactNode;
15
+ }
16
+ declare const PageManager: React.FC<PageManagerProps>;
17
+
18
+ export { PageManager, type PageManagerProps };
package/dist/index.js ADDED
@@ -0,0 +1,413 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ PageManager: () => PageManager
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/PageManager.tsx
38
+ var import_react = require("react");
39
+ var import_react_router_dom = require("react-router-dom");
40
+ var import_puck_api = require("@commercetools-demo/puck-api");
41
+ var import_puck_editor = require("@commercetools-demo/puck-editor");
42
+ var import_puck_renderer = require("@commercetools-demo/puck-renderer");
43
+ var import_data_table = __toESM(require("@commercetools-uikit/data-table"));
44
+ var import_primary_button = __toESM(require("@commercetools-uikit/primary-button"));
45
+ var import_secondary_button = __toESM(require("@commercetools-uikit/secondary-button"));
46
+ var import_flat_button = __toESM(require("@commercetools-uikit/flat-button"));
47
+ var import_card = __toESM(require("@commercetools-uikit/card"));
48
+ var import_spacings = __toESM(require("@commercetools-uikit/spacings"));
49
+ var import_text = __toESM(require("@commercetools-uikit/text"));
50
+ var import_loading_spinner = __toESM(require("@commercetools-uikit/loading-spinner"));
51
+ var import_text_input = __toESM(require("@commercetools-uikit/text-input"));
52
+ var import_label = __toESM(require("@commercetools-uikit/label"));
53
+ var import_icons = require("@commercetools-uikit/icons");
54
+ var import_jsx_runtime = require("react/jsx-runtime");
55
+ var StatusBadge = ({ variant }) => {
56
+ const styles = variant === "published" ? { background: "var(--color-success-95)", color: "var(--color-success-40)", border: "1px solid var(--color-success-85)" } : variant === "draft" ? { background: "var(--color-warning-95)", color: "var(--color-warning-40)", border: "1px solid var(--color-warning-85)" } : { background: "var(--color-neutral-95)", color: "var(--color-neutral-50)", border: "1px solid var(--color-neutral-85)" };
57
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
58
+ "span",
59
+ {
60
+ style: {
61
+ ...styles,
62
+ display: "inline-flex",
63
+ alignItems: "center",
64
+ padding: "2px 8px",
65
+ borderRadius: "var(--border-radius-20)",
66
+ fontSize: "var(--font-size-10)",
67
+ fontWeight: "var(--font-weight-600)",
68
+ marginRight: "4px",
69
+ whiteSpace: "nowrap"
70
+ },
71
+ children: variant === "published" ? "Published" : variant === "draft" ? "Draft" : "No state"
72
+ }
73
+ );
74
+ };
75
+ var NAV_BAR_STYLE = {
76
+ position: "sticky",
77
+ top: 0,
78
+ display: "flex",
79
+ alignItems: "center",
80
+ gap: "12px",
81
+ padding: "8px 16px",
82
+ background: "var(--color-surface, #fff)",
83
+ borderBottom: "1px solid var(--color-neutral-90)",
84
+ zIndex: 200,
85
+ flexShrink: 0
86
+ };
87
+ var COLUMNS = [
88
+ { key: "name", label: "Name" },
89
+ { key: "slug", label: "Slug" },
90
+ { key: "status", label: "Status" },
91
+ { key: "updatedAt", label: "Updated" },
92
+ { key: "actions", label: "Actions", shouldIgnoreRowClick: true }
93
+ ];
94
+ var PageList = ({ backButton }) => {
95
+ const navigate = (0, import_react_router_dom.useNavigate)();
96
+ const { pages, loading, error, createPage, deletePage, refresh } = (0, import_puck_api.usePuckPages)();
97
+ const [creating, setCreating] = (0, import_react.useState)(false);
98
+ const [newName, setNewName] = (0, import_react.useState)("");
99
+ const [newSlug, setNewSlug] = (0, import_react.useState)("");
100
+ const [formError, setFormError] = (0, import_react.useState)("");
101
+ const [submitting, setSubmitting] = (0, import_react.useState)(false);
102
+ const [deleting, setDeleting] = (0, import_react.useState)(null);
103
+ const handleCreate = async () => {
104
+ if (!newName.trim()) {
105
+ setFormError("Name is required");
106
+ return;
107
+ }
108
+ if (!newSlug.trim()) {
109
+ setFormError("Slug is required");
110
+ return;
111
+ }
112
+ setFormError("");
113
+ setSubmitting(true);
114
+ try {
115
+ const input = {
116
+ name: newName.trim(),
117
+ slug: newSlug.trim().startsWith("/") ? newSlug.trim() : `/${newSlug.trim()}`
118
+ };
119
+ const created = await createPage(input);
120
+ setCreating(false);
121
+ setNewName("");
122
+ setNewSlug("");
123
+ navigate(`/${created.key}/edit`, { state: { pageName: created.value.name } });
124
+ } catch (err) {
125
+ setFormError(err.message);
126
+ } finally {
127
+ setSubmitting(false);
128
+ }
129
+ };
130
+ const handleDelete = async (page) => {
131
+ if (!confirm(`Delete "${page.value.name}"? This cannot be undone.`)) return;
132
+ setDeleting(page.key);
133
+ try {
134
+ await deletePage(page.key);
135
+ await refresh();
136
+ } finally {
137
+ setDeleting(null);
138
+ }
139
+ };
140
+ if (loading) {
141
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "64px", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_loading_spinner.default, {}) });
142
+ }
143
+ if (error) {
144
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "32px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_text.default.Body, { tone: "negative", children: [
145
+ "Error: ",
146
+ error
147
+ ] }) });
148
+ }
149
+ const rows = pages.map((p) => ({ ...p, id: p.key }));
150
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "l", children: [
151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Inline, { justifyContent: "space-between", alignItems: "center", children: [
152
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Inline, { scale: "m", alignItems: "center", children: [
153
+ backButton,
154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Headline, { as: "h1", children: "Puck Pages" })
155
+ ] }),
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
157
+ import_primary_button.default,
158
+ {
159
+ label: "New Page",
160
+ iconLeft: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.PlusThinIcon, {}),
161
+ onClick: () => setCreating(true)
162
+ }
163
+ )
164
+ ] }),
165
+ creating && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_card.default, { insetScale: "l", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "m", children: [
166
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Subheadline, { as: "h4", isBold: true, children: "Create New Page" }),
167
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Inline, { scale: "m", children: [
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_label.default, { htmlFor: "new-page-name", children: "Name *" }),
170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
171
+ import_text_input.default,
172
+ {
173
+ id: "new-page-name",
174
+ value: newName,
175
+ onChange: (e) => setNewName(e.target.value),
176
+ placeholder: "Home Page"
177
+ }
178
+ )
179
+ ] }) }),
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_label.default, { htmlFor: "new-page-slug", children: "Slug *" }),
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
183
+ import_text_input.default,
184
+ {
185
+ id: "new-page-slug",
186
+ value: newSlug,
187
+ onChange: (e) => setNewSlug(e.target.value),
188
+ placeholder: "/home"
189
+ }
190
+ )
191
+ ] }) })
192
+ ] }),
193
+ formError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "negative", children: formError }),
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Inline, { scale: "s", children: [
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
196
+ import_primary_button.default,
197
+ {
198
+ label: submitting ? "Creating\u2026" : "Create",
199
+ onClick: () => void handleCreate(),
200
+ isDisabled: submitting
201
+ }
202
+ ),
203
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
204
+ import_secondary_button.default,
205
+ {
206
+ label: "Cancel",
207
+ onClick: () => {
208
+ setCreating(false);
209
+ setFormError("");
210
+ }
211
+ }
212
+ )
213
+ ] })
214
+ ] }) }),
215
+ pages.length === 0 && !creating ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "m", alignItems: "center", children: [
216
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: "No pages yet." }),
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
218
+ import_primary_button.default,
219
+ {
220
+ label: "Create first page",
221
+ iconLeft: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.PlusThinIcon, {}),
222
+ onClick: () => setCreating(true)
223
+ }
224
+ )
225
+ ] }) : pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
226
+ import_data_table.default,
227
+ {
228
+ columns: COLUMNS,
229
+ rows,
230
+ itemRenderer: (row, column) => {
231
+ switch (column.key) {
232
+ case "name":
233
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_spacings.default.Stack, { scale: "xs", children: [
234
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { isBold: true, children: row.value.name }),
235
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Detail, { tone: "secondary", children: row.key })
236
+ ] });
237
+ case "slug":
238
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
239
+ "code",
240
+ {
241
+ style: {
242
+ background: "var(--color-neutral-95)",
243
+ padding: "2px 6px",
244
+ borderRadius: "var(--border-radius-4)",
245
+ fontSize: "var(--font-size-10)",
246
+ fontFamily: "monospace"
247
+ },
248
+ children: row.value.slug
249
+ }
250
+ );
251
+ case "status":
252
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
253
+ row.states.draft && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { variant: "draft" }),
254
+ row.states.published && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { variant: "published" }),
255
+ !row.states.draft && !row.states.published && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { variant: "none" })
256
+ ] });
257
+ case "updatedAt":
258
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: new Date(row.value.updatedAt).toLocaleString() });
259
+ case "actions":
260
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
262
+ import_primary_button.default,
263
+ {
264
+ label: "Edit",
265
+ size: "20",
266
+ onClick: () => navigate(`/${row.key}/edit`, { state: { pageName: row.value.name } })
267
+ }
268
+ ),
269
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
270
+ import_secondary_button.default,
271
+ {
272
+ label: "Preview",
273
+ size: "20",
274
+ onClick: () => navigate(`/${row.key}/preview`, { state: { pageName: row.value.name } })
275
+ }
276
+ ),
277
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
278
+ import_flat_button.default,
279
+ {
280
+ tone: "critical",
281
+ label: deleting === row.key ? "\u2026" : "Delete",
282
+ isDisabled: deleting === row.key,
283
+ onClick: () => void handleDelete(row)
284
+ }
285
+ )
286
+ ] });
287
+ default:
288
+ return null;
289
+ }
290
+ }
291
+ }
292
+ ) : null
293
+ ] }) });
294
+ };
295
+ var PageEditorRoute = ({ config, backButton }) => {
296
+ const { pageKey } = (0, import_react_router_dom.useParams)();
297
+ const navigate = (0, import_react_router_dom.useNavigate)();
298
+ const location = (0, import_react_router_dom.useLocation)();
299
+ const { baseURL, projectKey, businessUnitKey, jwtToken } = (0, import_puck_api.usePuckApiContext)();
300
+ const pageName = location.state?.pageName ?? pageKey ?? "Page";
301
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: NAV_BAR_STYLE, children: [
303
+ backButton,
304
+ backButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
305
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
306
+ import_flat_button.default,
307
+ {
308
+ label: "Pages",
309
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.AngleLeftIcon, {}),
310
+ iconPosition: "left",
311
+ onClick: () => navigate("/")
312
+ }
313
+ ),
314
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { isBold: true, children: pageName })
316
+ ] }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
318
+ import_puck_editor.PuckEditor,
319
+ {
320
+ baseURL,
321
+ projectKey,
322
+ businessUnitKey,
323
+ jwtToken: jwtToken ?? "",
324
+ pageKey,
325
+ config,
326
+ onError: (err) => {
327
+ console.error("[PageManager] editor error:", err);
328
+ }
329
+ }
330
+ ) })
331
+ ] });
332
+ };
333
+ var PagePreviewRoute = ({ config, backButton }) => {
334
+ const { pageKey } = (0, import_react_router_dom.useParams)();
335
+ const navigate = (0, import_react_router_dom.useNavigate)();
336
+ const location = (0, import_react_router_dom.useLocation)();
337
+ const pageName = location.state?.pageName ?? pageKey ?? "Page";
338
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: NAV_BAR_STYLE, children: [
340
+ backButton,
341
+ backButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
343
+ import_flat_button.default,
344
+ {
345
+ label: "Pages",
346
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.AngleLeftIcon, {}),
347
+ iconPosition: "left",
348
+ onClick: () => navigate("/")
349
+ }
350
+ ),
351
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { tone: "secondary", children: "/" }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_text.default.Body, { isBold: true, children: pageName }),
353
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
354
+ "span",
355
+ {
356
+ style: {
357
+ background: "var(--color-primary-95)",
358
+ color: "var(--color-primary-25)",
359
+ border: "1px solid var(--color-primary-85)",
360
+ display: "inline-flex",
361
+ alignItems: "center",
362
+ padding: "2px 10px",
363
+ borderRadius: "var(--border-radius-20)",
364
+ fontSize: "var(--font-size-10)",
365
+ fontWeight: "var(--font-weight-600)"
366
+ },
367
+ children: "Preview"
368
+ }
369
+ )
370
+ ] }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_puck_renderer.PuckRenderer, { pageKey, mode: "preview", config })
372
+ ] });
373
+ };
374
+ var PageManagerInner = ({ config, backButton }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_router_dom.Routes, { children: [
375
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router_dom.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageList, { backButton }) }),
376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
377
+ import_react_router_dom.Route,
378
+ {
379
+ path: "/:pageKey/edit",
380
+ element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageEditorRoute, { config, backButton })
381
+ }
382
+ ),
383
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
384
+ import_react_router_dom.Route,
385
+ {
386
+ path: "/:pageKey/preview",
387
+ element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PagePreviewRoute, { config, backButton })
388
+ }
389
+ )
390
+ ] });
391
+ var PageManager = ({
392
+ parentUrl,
393
+ baseURL,
394
+ projectKey,
395
+ businessUnitKey,
396
+ jwtToken,
397
+ config,
398
+ backButton
399
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
400
+ import_puck_api.PuckApiProvider,
401
+ {
402
+ baseURL,
403
+ projectKey,
404
+ businessUnitKey,
405
+ jwtToken,
406
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router_dom.BrowserRouter, { basename: parentUrl, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageManagerInner, { config, backButton }) })
407
+ }
408
+ );
409
+ // Annotate the CommonJS export names for ESM import in node:
410
+ 0 && (module.exports = {
411
+ PageManager
412
+ });
413
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/PageManager.tsx"],"sourcesContent":["export { PageManager } from './PageManager';\nexport type { PageManagerProps } from './PageManager';\n","import React, { useState, type ReactNode } from 'react';\nimport {\n BrowserRouter,\n Routes,\n Route,\n useNavigate,\n useParams,\n useLocation,\n} from 'react-router-dom';\nimport {\n PuckApiProvider,\n usePuckPages,\n usePuckApiContext,\n} from '@commercetools-demo/puck-api';\nimport { PuckEditor } from '@commercetools-demo/puck-editor';\nimport { PuckRenderer } from '@commercetools-demo/puck-renderer';\nimport type { Config } from '@measured/puck';\nimport type { CreatePuckPageInput, PuckPageListItem } from '@commercetools-demo/puck-types';\nimport DataTable from '@commercetools-uikit/data-table';\nimport PrimaryButton from '@commercetools-uikit/primary-button';\nimport SecondaryButton from '@commercetools-uikit/secondary-button';\nimport FlatButton from '@commercetools-uikit/flat-button';\nimport Card from '@commercetools-uikit/card';\nimport Spacings from '@commercetools-uikit/spacings';\nimport Text from '@commercetools-uikit/text';\nimport LoadingSpinner from '@commercetools-uikit/loading-spinner';\nimport TextInput from '@commercetools-uikit/text-input';\nimport Label from '@commercetools-uikit/label';\nimport { PlusThinIcon, AngleLeftIcon } from '@commercetools-uikit/icons';\n\n// ---------------------------------------------------------------------------\n// Status badge\n// ---------------------------------------------------------------------------\n\nconst StatusBadge: React.FC<{ variant: 'draft' | 'published' | 'none' }> = ({ variant }) => {\n const styles: React.CSSProperties =\n variant === 'published'\n ? { background: 'var(--color-success-95)', color: 'var(--color-success-40)', border: '1px solid var(--color-success-85)' }\n : variant === 'draft'\n ? { background: 'var(--color-warning-95)', color: 'var(--color-warning-40)', border: '1px solid var(--color-warning-85)' }\n : { background: 'var(--color-neutral-95)', color: 'var(--color-neutral-50)', border: '1px solid var(--color-neutral-85)' };\n return (\n <span\n style={{\n ...styles,\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 8px',\n borderRadius: 'var(--border-radius-20)',\n fontSize: 'var(--font-size-10)',\n fontWeight: 'var(--font-weight-600)',\n marginRight: '4px',\n whiteSpace: 'nowrap',\n }}\n >\n {variant === 'published' ? 'Published' : variant === 'draft' ? 'Draft' : 'No state'}\n </span>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Shared nav bar style\n// ---------------------------------------------------------------------------\n\nconst NAV_BAR_STYLE: React.CSSProperties = {\n position: 'sticky',\n top: 0,\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '8px 16px',\n background: 'var(--color-surface, #fff)',\n borderBottom: '1px solid var(--color-neutral-90)',\n zIndex: 200,\n flexShrink: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Table columns\n// ---------------------------------------------------------------------------\n\ntype PageRow = PuckPageListItem & { id: string };\n\nconst COLUMNS = [\n { key: 'name', label: 'Name' },\n { key: 'slug', label: 'Slug' },\n { key: 'status', label: 'Status' },\n { key: 'updatedAt', label: 'Updated' },\n { key: 'actions', label: 'Actions', shouldIgnoreRowClick: true },\n];\n\n// ---------------------------------------------------------------------------\n// PageList route\n// ---------------------------------------------------------------------------\n\ninterface PageListProps {\n backButton?: ReactNode;\n}\n\nconst PageList: React.FC<PageListProps> = ({ backButton }) => {\n const navigate = useNavigate();\n const { pages, loading, error, createPage, deletePage, refresh } = usePuckPages();\n\n const [creating, setCreating] = useState(false);\n const [newName, setNewName] = useState('');\n const [newSlug, setNewSlug] = useState('');\n const [formError, setFormError] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [deleting, setDeleting] = useState<string | null>(null);\n\n const handleCreate = async () => {\n if (!newName.trim()) { setFormError('Name is required'); return; }\n if (!newSlug.trim()) { setFormError('Slug is required'); return; }\n setFormError('');\n setSubmitting(true);\n try {\n const input: CreatePuckPageInput = {\n name: newName.trim(),\n slug: newSlug.trim().startsWith('/') ? newSlug.trim() : `/${newSlug.trim()}`,\n };\n const created = await createPage(input);\n setCreating(false);\n setNewName('');\n setNewSlug('');\n navigate(`/${created.key}/edit`, { state: { pageName: created.value.name } });\n } catch (err) {\n setFormError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleDelete = async (page: PuckPageListItem) => {\n if (!confirm(`Delete \"${page.value.name}\"? This cannot be undone.`)) return;\n setDeleting(page.key);\n try {\n await deletePage(page.key);\n await refresh();\n } finally {\n setDeleting(null);\n }\n };\n\n if (loading) {\n return (\n <div style={{ padding: '64px', display: 'flex', justifyContent: 'center' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n if (error) {\n return (\n <div style={{ padding: '32px' }}>\n <Text.Body tone=\"negative\">Error: {error}</Text.Body>\n </div>\n );\n }\n\n const rows: PageRow[] = pages.map((p) => ({ ...p, id: p.key }));\n\n return (\n <div style={{ maxWidth: '1200px', margin: '0 auto', padding: '32px 24px' }}>\n <Spacings.Stack scale=\"l\">\n <Spacings.Inline justifyContent=\"space-between\" alignItems=\"center\">\n <Spacings.Inline scale=\"m\" alignItems=\"center\">\n {backButton}\n <Text.Headline as=\"h1\">Puck Pages</Text.Headline>\n </Spacings.Inline>\n <PrimaryButton\n label=\"New Page\"\n iconLeft={<PlusThinIcon />}\n onClick={() => setCreating(true)}\n />\n </Spacings.Inline>\n\n {creating && (\n <Card insetScale=\"l\">\n <Spacings.Stack scale=\"m\">\n <Text.Subheadline as=\"h4\" isBold>Create New Page</Text.Subheadline>\n <Spacings.Inline scale=\"m\">\n <div style={{ flex: 1 }}>\n <Spacings.Stack scale=\"xs\">\n <Label htmlFor=\"new-page-name\">Name *</Label>\n <TextInput\n id=\"new-page-name\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n placeholder=\"Home Page\"\n />\n </Spacings.Stack>\n </div>\n <div style={{ flex: 1 }}>\n <Spacings.Stack scale=\"xs\">\n <Label htmlFor=\"new-page-slug\">Slug *</Label>\n <TextInput\n id=\"new-page-slug\"\n value={newSlug}\n onChange={(e) => setNewSlug(e.target.value)}\n placeholder=\"/home\"\n />\n </Spacings.Stack>\n </div>\n </Spacings.Inline>\n {formError && <Text.Body tone=\"negative\">{formError}</Text.Body>}\n <Spacings.Inline scale=\"s\">\n <PrimaryButton\n label={submitting ? 'Creating…' : 'Create'}\n onClick={() => void handleCreate()}\n isDisabled={submitting}\n />\n <SecondaryButton\n label=\"Cancel\"\n onClick={() => { setCreating(false); setFormError(''); }}\n />\n </Spacings.Inline>\n </Spacings.Stack>\n </Card>\n )}\n\n {pages.length === 0 && !creating ? (\n <Spacings.Stack scale=\"m\" alignItems=\"center\">\n <Text.Body tone=\"secondary\">No pages yet.</Text.Body>\n <PrimaryButton\n label=\"Create first page\"\n iconLeft={<PlusThinIcon />}\n onClick={() => setCreating(true)}\n />\n </Spacings.Stack>\n ) : pages.length > 0 ? (\n <DataTable\n columns={COLUMNS}\n rows={rows}\n itemRenderer={(row: PageRow, column) => {\n switch (column.key) {\n case 'name':\n return (\n <Spacings.Stack scale=\"xs\">\n <Text.Body isBold>{row.value.name}</Text.Body>\n <Text.Detail tone=\"secondary\">{row.key}</Text.Detail>\n </Spacings.Stack>\n );\n case 'slug':\n return (\n <code\n style={{\n background: 'var(--color-neutral-95)',\n padding: '2px 6px',\n borderRadius: 'var(--border-radius-4)',\n fontSize: 'var(--font-size-10)',\n fontFamily: 'monospace',\n }}\n >\n {row.value.slug}\n </code>\n );\n case 'status':\n return (\n <span>\n {row.states.draft && <StatusBadge variant=\"draft\" />}\n {row.states.published && <StatusBadge variant=\"published\" />}\n {!row.states.draft && !row.states.published && <StatusBadge variant=\"none\" />}\n </span>\n );\n case 'updatedAt':\n return (\n <Text.Body tone=\"secondary\">\n {new Date(row.value.updatedAt).toLocaleString()}\n </Text.Body>\n );\n case 'actions':\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <PrimaryButton\n label=\"Edit\"\n size=\"20\"\n onClick={() =>\n navigate(`/${row.key}/edit`, { state: { pageName: row.value.name } })\n }\n />\n <SecondaryButton\n label=\"Preview\"\n size=\"20\"\n onClick={() =>\n navigate(`/${row.key}/preview`, { state: { pageName: row.value.name } })\n }\n />\n <FlatButton\n tone=\"critical\"\n label={deleting === row.key ? '…' : 'Delete'}\n isDisabled={deleting === row.key}\n onClick={() => void handleDelete(row)}\n />\n </div>\n );\n default:\n return null;\n }\n }}\n />\n ) : null}\n </Spacings.Stack>\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// PageEditorRoute\n// ---------------------------------------------------------------------------\n\ninterface RouteProps {\n config: Config;\n backButton?: ReactNode;\n}\n\nconst PageEditorRoute: React.FC<RouteProps> = ({ config, backButton }) => {\n const { pageKey } = useParams<{ pageKey: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const { baseURL, projectKey, businessUnitKey, jwtToken } = usePuckApiContext();\n const pageName =\n (location.state as { pageName?: string } | null)?.pageName ?? pageKey ?? 'Page';\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>\n <div style={NAV_BAR_STYLE}>\n {backButton}\n {backButton && <Text.Body tone=\"secondary\">/</Text.Body>}\n <FlatButton\n label=\"Pages\"\n icon={<AngleLeftIcon />}\n iconPosition=\"left\"\n onClick={() => navigate('/')}\n />\n <Text.Body tone=\"secondary\">/</Text.Body>\n <Text.Body isBold>{pageName}</Text.Body>\n </div>\n <div style={{ flex: 1, overflow: 'hidden' }}>\n <PuckEditor\n baseURL={baseURL}\n projectKey={projectKey}\n businessUnitKey={businessUnitKey}\n jwtToken={jwtToken ?? ''}\n pageKey={pageKey!}\n config={config}\n onError={(err: Error) => { console.error('[PageManager] editor error:', err); }}\n />\n </div>\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// PagePreviewRoute\n// ---------------------------------------------------------------------------\n\nconst PagePreviewRoute: React.FC<RouteProps> = ({ config, backButton }) => {\n const { pageKey } = useParams<{ pageKey: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const pageName =\n (location.state as { pageName?: string } | null)?.pageName ?? pageKey ?? 'Page';\n\n return (\n <div>\n <div style={NAV_BAR_STYLE}>\n {backButton}\n {backButton && <Text.Body tone=\"secondary\">/</Text.Body>}\n <FlatButton\n label=\"Pages\"\n icon={<AngleLeftIcon />}\n iconPosition=\"left\"\n onClick={() => navigate('/')}\n />\n <Text.Body tone=\"secondary\">/</Text.Body>\n <Text.Body isBold>{pageName}</Text.Body>\n <span\n style={{\n background: 'var(--color-primary-95)',\n color: 'var(--color-primary-25)',\n border: '1px solid var(--color-primary-85)',\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 10px',\n borderRadius: 'var(--border-radius-20)',\n fontSize: 'var(--font-size-10)',\n fontWeight: 'var(--font-weight-600)',\n }}\n >\n Preview\n </span>\n </div>\n <PuckRenderer pageKey={pageKey} mode=\"preview\" config={config} />\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Inner router component\n// ---------------------------------------------------------------------------\n\ninterface PageManagerInnerProps {\n config: Config;\n backButton?: ReactNode;\n}\n\nconst PageManagerInner: React.FC<PageManagerInnerProps> = ({ config, backButton }) => (\n <Routes>\n <Route path=\"/\" element={<PageList backButton={backButton} />} />\n <Route\n path=\"/:pageKey/edit\"\n element={<PageEditorRoute config={config} backButton={backButton} />}\n />\n <Route\n path=\"/:pageKey/preview\"\n element={<PagePreviewRoute config={config} backButton={backButton} />}\n />\n </Routes>\n);\n\n// ---------------------------------------------------------------------------\n// Public component\n// ---------------------------------------------------------------------------\n\nexport interface PageManagerProps {\n /** URL path where this manager is mounted, e.g. \"/pages\" — used as router basename */\n parentUrl: string;\n baseURL: string;\n projectKey: string;\n businessUnitKey: string;\n jwtToken: string;\n /** Puck component config — passed to editor and preview */\n config: Config;\n /** Optional element rendered before the breadcrumb in editor/preview headers */\n backButton?: ReactNode;\n}\n\nexport const PageManager: React.FC<PageManagerProps> = ({\n parentUrl,\n baseURL,\n projectKey,\n businessUnitKey,\n jwtToken,\n config,\n backButton,\n}) => (\n <PuckApiProvider\n baseURL={baseURL}\n projectKey={projectKey}\n businessUnitKey={businessUnitKey}\n jwtToken={jwtToken}\n >\n <BrowserRouter basename={parentUrl}>\n <PageManagerInner config={config} backButton={backButton} />\n </BrowserRouter>\n </PuckApiProvider>\n);\n"],"mappings":"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","names":["LoadingSpinner","Text","Spacings","PrimaryButton","Card","Label","TextInput","SecondaryButton","DataTable","FlatButton"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,387 @@
1
+ // src/PageManager.tsx
2
+ import { useState } from "react";
3
+ import {
4
+ BrowserRouter,
5
+ Routes,
6
+ Route,
7
+ useNavigate,
8
+ useParams,
9
+ useLocation
10
+ } from "react-router-dom";
11
+ import {
12
+ PuckApiProvider,
13
+ usePuckPages,
14
+ usePuckApiContext
15
+ } from "@commercetools-demo/puck-api";
16
+ import { PuckEditor } from "@commercetools-demo/puck-editor";
17
+ import { PuckRenderer } from "@commercetools-demo/puck-renderer";
18
+ import DataTable from "@commercetools-uikit/data-table";
19
+ import PrimaryButton from "@commercetools-uikit/primary-button";
20
+ import SecondaryButton from "@commercetools-uikit/secondary-button";
21
+ import FlatButton from "@commercetools-uikit/flat-button";
22
+ import Card from "@commercetools-uikit/card";
23
+ import Spacings from "@commercetools-uikit/spacings";
24
+ import Text from "@commercetools-uikit/text";
25
+ import LoadingSpinner from "@commercetools-uikit/loading-spinner";
26
+ import TextInput from "@commercetools-uikit/text-input";
27
+ import Label from "@commercetools-uikit/label";
28
+ import { PlusThinIcon, AngleLeftIcon } from "@commercetools-uikit/icons";
29
+ import { jsx, jsxs } from "react/jsx-runtime";
30
+ var StatusBadge = ({ variant }) => {
31
+ const styles = variant === "published" ? { background: "var(--color-success-95)", color: "var(--color-success-40)", border: "1px solid var(--color-success-85)" } : variant === "draft" ? { background: "var(--color-warning-95)", color: "var(--color-warning-40)", border: "1px solid var(--color-warning-85)" } : { background: "var(--color-neutral-95)", color: "var(--color-neutral-50)", border: "1px solid var(--color-neutral-85)" };
32
+ return /* @__PURE__ */ jsx(
33
+ "span",
34
+ {
35
+ style: {
36
+ ...styles,
37
+ display: "inline-flex",
38
+ alignItems: "center",
39
+ padding: "2px 8px",
40
+ borderRadius: "var(--border-radius-20)",
41
+ fontSize: "var(--font-size-10)",
42
+ fontWeight: "var(--font-weight-600)",
43
+ marginRight: "4px",
44
+ whiteSpace: "nowrap"
45
+ },
46
+ children: variant === "published" ? "Published" : variant === "draft" ? "Draft" : "No state"
47
+ }
48
+ );
49
+ };
50
+ var NAV_BAR_STYLE = {
51
+ position: "sticky",
52
+ top: 0,
53
+ display: "flex",
54
+ alignItems: "center",
55
+ gap: "12px",
56
+ padding: "8px 16px",
57
+ background: "var(--color-surface, #fff)",
58
+ borderBottom: "1px solid var(--color-neutral-90)",
59
+ zIndex: 200,
60
+ flexShrink: 0
61
+ };
62
+ var COLUMNS = [
63
+ { key: "name", label: "Name" },
64
+ { key: "slug", label: "Slug" },
65
+ { key: "status", label: "Status" },
66
+ { key: "updatedAt", label: "Updated" },
67
+ { key: "actions", label: "Actions", shouldIgnoreRowClick: true }
68
+ ];
69
+ var PageList = ({ backButton }) => {
70
+ const navigate = useNavigate();
71
+ const { pages, loading, error, createPage, deletePage, refresh } = usePuckPages();
72
+ const [creating, setCreating] = useState(false);
73
+ const [newName, setNewName] = useState("");
74
+ const [newSlug, setNewSlug] = useState("");
75
+ const [formError, setFormError] = useState("");
76
+ const [submitting, setSubmitting] = useState(false);
77
+ const [deleting, setDeleting] = useState(null);
78
+ const handleCreate = async () => {
79
+ if (!newName.trim()) {
80
+ setFormError("Name is required");
81
+ return;
82
+ }
83
+ if (!newSlug.trim()) {
84
+ setFormError("Slug is required");
85
+ return;
86
+ }
87
+ setFormError("");
88
+ setSubmitting(true);
89
+ try {
90
+ const input = {
91
+ name: newName.trim(),
92
+ slug: newSlug.trim().startsWith("/") ? newSlug.trim() : `/${newSlug.trim()}`
93
+ };
94
+ const created = await createPage(input);
95
+ setCreating(false);
96
+ setNewName("");
97
+ setNewSlug("");
98
+ navigate(`/${created.key}/edit`, { state: { pageName: created.value.name } });
99
+ } catch (err) {
100
+ setFormError(err.message);
101
+ } finally {
102
+ setSubmitting(false);
103
+ }
104
+ };
105
+ const handleDelete = async (page) => {
106
+ if (!confirm(`Delete "${page.value.name}"? This cannot be undone.`)) return;
107
+ setDeleting(page.key);
108
+ try {
109
+ await deletePage(page.key);
110
+ await refresh();
111
+ } finally {
112
+ setDeleting(null);
113
+ }
114
+ };
115
+ if (loading) {
116
+ return /* @__PURE__ */ jsx("div", { style: { padding: "64px", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx(LoadingSpinner, {}) });
117
+ }
118
+ if (error) {
119
+ return /* @__PURE__ */ jsx("div", { style: { padding: "32px" }, children: /* @__PURE__ */ jsxs(Text.Body, { tone: "negative", children: [
120
+ "Error: ",
121
+ error
122
+ ] }) });
123
+ }
124
+ const rows = pages.map((p) => ({ ...p, id: p.key }));
125
+ return /* @__PURE__ */ jsx("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "l", children: [
126
+ /* @__PURE__ */ jsxs(Spacings.Inline, { justifyContent: "space-between", alignItems: "center", children: [
127
+ /* @__PURE__ */ jsxs(Spacings.Inline, { scale: "m", alignItems: "center", children: [
128
+ backButton,
129
+ /* @__PURE__ */ jsx(Text.Headline, { as: "h1", children: "Puck Pages" })
130
+ ] }),
131
+ /* @__PURE__ */ jsx(
132
+ PrimaryButton,
133
+ {
134
+ label: "New Page",
135
+ iconLeft: /* @__PURE__ */ jsx(PlusThinIcon, {}),
136
+ onClick: () => setCreating(true)
137
+ }
138
+ )
139
+ ] }),
140
+ creating && /* @__PURE__ */ jsx(Card, { insetScale: "l", children: /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "m", children: [
141
+ /* @__PURE__ */ jsx(Text.Subheadline, { as: "h4", isBold: true, children: "Create New Page" }),
142
+ /* @__PURE__ */ jsxs(Spacings.Inline, { scale: "m", children: [
143
+ /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "xs", children: [
144
+ /* @__PURE__ */ jsx(Label, { htmlFor: "new-page-name", children: "Name *" }),
145
+ /* @__PURE__ */ jsx(
146
+ TextInput,
147
+ {
148
+ id: "new-page-name",
149
+ value: newName,
150
+ onChange: (e) => setNewName(e.target.value),
151
+ placeholder: "Home Page"
152
+ }
153
+ )
154
+ ] }) }),
155
+ /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "xs", children: [
156
+ /* @__PURE__ */ jsx(Label, { htmlFor: "new-page-slug", children: "Slug *" }),
157
+ /* @__PURE__ */ jsx(
158
+ TextInput,
159
+ {
160
+ id: "new-page-slug",
161
+ value: newSlug,
162
+ onChange: (e) => setNewSlug(e.target.value),
163
+ placeholder: "/home"
164
+ }
165
+ )
166
+ ] }) })
167
+ ] }),
168
+ formError && /* @__PURE__ */ jsx(Text.Body, { tone: "negative", children: formError }),
169
+ /* @__PURE__ */ jsxs(Spacings.Inline, { scale: "s", children: [
170
+ /* @__PURE__ */ jsx(
171
+ PrimaryButton,
172
+ {
173
+ label: submitting ? "Creating\u2026" : "Create",
174
+ onClick: () => void handleCreate(),
175
+ isDisabled: submitting
176
+ }
177
+ ),
178
+ /* @__PURE__ */ jsx(
179
+ SecondaryButton,
180
+ {
181
+ label: "Cancel",
182
+ onClick: () => {
183
+ setCreating(false);
184
+ setFormError("");
185
+ }
186
+ }
187
+ )
188
+ ] })
189
+ ] }) }),
190
+ pages.length === 0 && !creating ? /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "m", alignItems: "center", children: [
191
+ /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: "No pages yet." }),
192
+ /* @__PURE__ */ jsx(
193
+ PrimaryButton,
194
+ {
195
+ label: "Create first page",
196
+ iconLeft: /* @__PURE__ */ jsx(PlusThinIcon, {}),
197
+ onClick: () => setCreating(true)
198
+ }
199
+ )
200
+ ] }) : pages.length > 0 ? /* @__PURE__ */ jsx(
201
+ DataTable,
202
+ {
203
+ columns: COLUMNS,
204
+ rows,
205
+ itemRenderer: (row, column) => {
206
+ switch (column.key) {
207
+ case "name":
208
+ return /* @__PURE__ */ jsxs(Spacings.Stack, { scale: "xs", children: [
209
+ /* @__PURE__ */ jsx(Text.Body, { isBold: true, children: row.value.name }),
210
+ /* @__PURE__ */ jsx(Text.Detail, { tone: "secondary", children: row.key })
211
+ ] });
212
+ case "slug":
213
+ return /* @__PURE__ */ jsx(
214
+ "code",
215
+ {
216
+ style: {
217
+ background: "var(--color-neutral-95)",
218
+ padding: "2px 6px",
219
+ borderRadius: "var(--border-radius-4)",
220
+ fontSize: "var(--font-size-10)",
221
+ fontFamily: "monospace"
222
+ },
223
+ children: row.value.slug
224
+ }
225
+ );
226
+ case "status":
227
+ return /* @__PURE__ */ jsxs("span", { children: [
228
+ row.states.draft && /* @__PURE__ */ jsx(StatusBadge, { variant: "draft" }),
229
+ row.states.published && /* @__PURE__ */ jsx(StatusBadge, { variant: "published" }),
230
+ !row.states.draft && !row.states.published && /* @__PURE__ */ jsx(StatusBadge, { variant: "none" })
231
+ ] });
232
+ case "updatedAt":
233
+ return /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: new Date(row.value.updatedAt).toLocaleString() });
234
+ case "actions":
235
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
236
+ /* @__PURE__ */ jsx(
237
+ PrimaryButton,
238
+ {
239
+ label: "Edit",
240
+ size: "20",
241
+ onClick: () => navigate(`/${row.key}/edit`, { state: { pageName: row.value.name } })
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsx(
245
+ SecondaryButton,
246
+ {
247
+ label: "Preview",
248
+ size: "20",
249
+ onClick: () => navigate(`/${row.key}/preview`, { state: { pageName: row.value.name } })
250
+ }
251
+ ),
252
+ /* @__PURE__ */ jsx(
253
+ FlatButton,
254
+ {
255
+ tone: "critical",
256
+ label: deleting === row.key ? "\u2026" : "Delete",
257
+ isDisabled: deleting === row.key,
258
+ onClick: () => void handleDelete(row)
259
+ }
260
+ )
261
+ ] });
262
+ default:
263
+ return null;
264
+ }
265
+ }
266
+ }
267
+ ) : null
268
+ ] }) });
269
+ };
270
+ var PageEditorRoute = ({ config, backButton }) => {
271
+ const { pageKey } = useParams();
272
+ const navigate = useNavigate();
273
+ const location = useLocation();
274
+ const { baseURL, projectKey, businessUnitKey, jwtToken } = usePuckApiContext();
275
+ const pageName = location.state?.pageName ?? pageKey ?? "Page";
276
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
277
+ /* @__PURE__ */ jsxs("div", { style: NAV_BAR_STYLE, children: [
278
+ backButton,
279
+ backButton && /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: "/" }),
280
+ /* @__PURE__ */ jsx(
281
+ FlatButton,
282
+ {
283
+ label: "Pages",
284
+ icon: /* @__PURE__ */ jsx(AngleLeftIcon, {}),
285
+ iconPosition: "left",
286
+ onClick: () => navigate("/")
287
+ }
288
+ ),
289
+ /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: "/" }),
290
+ /* @__PURE__ */ jsx(Text.Body, { isBold: true, children: pageName })
291
+ ] }),
292
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
293
+ PuckEditor,
294
+ {
295
+ baseURL,
296
+ projectKey,
297
+ businessUnitKey,
298
+ jwtToken: jwtToken ?? "",
299
+ pageKey,
300
+ config,
301
+ onError: (err) => {
302
+ console.error("[PageManager] editor error:", err);
303
+ }
304
+ }
305
+ ) })
306
+ ] });
307
+ };
308
+ var PagePreviewRoute = ({ config, backButton }) => {
309
+ const { pageKey } = useParams();
310
+ const navigate = useNavigate();
311
+ const location = useLocation();
312
+ const pageName = location.state?.pageName ?? pageKey ?? "Page";
313
+ return /* @__PURE__ */ jsxs("div", { children: [
314
+ /* @__PURE__ */ jsxs("div", { style: NAV_BAR_STYLE, children: [
315
+ backButton,
316
+ backButton && /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: "/" }),
317
+ /* @__PURE__ */ jsx(
318
+ FlatButton,
319
+ {
320
+ label: "Pages",
321
+ icon: /* @__PURE__ */ jsx(AngleLeftIcon, {}),
322
+ iconPosition: "left",
323
+ onClick: () => navigate("/")
324
+ }
325
+ ),
326
+ /* @__PURE__ */ jsx(Text.Body, { tone: "secondary", children: "/" }),
327
+ /* @__PURE__ */ jsx(Text.Body, { isBold: true, children: pageName }),
328
+ /* @__PURE__ */ jsx(
329
+ "span",
330
+ {
331
+ style: {
332
+ background: "var(--color-primary-95)",
333
+ color: "var(--color-primary-25)",
334
+ border: "1px solid var(--color-primary-85)",
335
+ display: "inline-flex",
336
+ alignItems: "center",
337
+ padding: "2px 10px",
338
+ borderRadius: "var(--border-radius-20)",
339
+ fontSize: "var(--font-size-10)",
340
+ fontWeight: "var(--font-weight-600)"
341
+ },
342
+ children: "Preview"
343
+ }
344
+ )
345
+ ] }),
346
+ /* @__PURE__ */ jsx(PuckRenderer, { pageKey, mode: "preview", config })
347
+ ] });
348
+ };
349
+ var PageManagerInner = ({ config, backButton }) => /* @__PURE__ */ jsxs(Routes, { children: [
350
+ /* @__PURE__ */ jsx(Route, { path: "/", element: /* @__PURE__ */ jsx(PageList, { backButton }) }),
351
+ /* @__PURE__ */ jsx(
352
+ Route,
353
+ {
354
+ path: "/:pageKey/edit",
355
+ element: /* @__PURE__ */ jsx(PageEditorRoute, { config, backButton })
356
+ }
357
+ ),
358
+ /* @__PURE__ */ jsx(
359
+ Route,
360
+ {
361
+ path: "/:pageKey/preview",
362
+ element: /* @__PURE__ */ jsx(PagePreviewRoute, { config, backButton })
363
+ }
364
+ )
365
+ ] });
366
+ var PageManager = ({
367
+ parentUrl,
368
+ baseURL,
369
+ projectKey,
370
+ businessUnitKey,
371
+ jwtToken,
372
+ config,
373
+ backButton
374
+ }) => /* @__PURE__ */ jsx(
375
+ PuckApiProvider,
376
+ {
377
+ baseURL,
378
+ projectKey,
379
+ businessUnitKey,
380
+ jwtToken,
381
+ children: /* @__PURE__ */ jsx(BrowserRouter, { basename: parentUrl, children: /* @__PURE__ */ jsx(PageManagerInner, { config, backButton }) })
382
+ }
383
+ );
384
+ export {
385
+ PageManager
386
+ };
387
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/PageManager.tsx"],"sourcesContent":["import React, { useState, type ReactNode } from 'react';\nimport {\n BrowserRouter,\n Routes,\n Route,\n useNavigate,\n useParams,\n useLocation,\n} from 'react-router-dom';\nimport {\n PuckApiProvider,\n usePuckPages,\n usePuckApiContext,\n} from '@commercetools-demo/puck-api';\nimport { PuckEditor } from '@commercetools-demo/puck-editor';\nimport { PuckRenderer } from '@commercetools-demo/puck-renderer';\nimport type { Config } from '@measured/puck';\nimport type { CreatePuckPageInput, PuckPageListItem } from '@commercetools-demo/puck-types';\nimport DataTable from '@commercetools-uikit/data-table';\nimport PrimaryButton from '@commercetools-uikit/primary-button';\nimport SecondaryButton from '@commercetools-uikit/secondary-button';\nimport FlatButton from '@commercetools-uikit/flat-button';\nimport Card from '@commercetools-uikit/card';\nimport Spacings from '@commercetools-uikit/spacings';\nimport Text from '@commercetools-uikit/text';\nimport LoadingSpinner from '@commercetools-uikit/loading-spinner';\nimport TextInput from '@commercetools-uikit/text-input';\nimport Label from '@commercetools-uikit/label';\nimport { PlusThinIcon, AngleLeftIcon } from '@commercetools-uikit/icons';\n\n// ---------------------------------------------------------------------------\n// Status badge\n// ---------------------------------------------------------------------------\n\nconst StatusBadge: React.FC<{ variant: 'draft' | 'published' | 'none' }> = ({ variant }) => {\n const styles: React.CSSProperties =\n variant === 'published'\n ? { background: 'var(--color-success-95)', color: 'var(--color-success-40)', border: '1px solid var(--color-success-85)' }\n : variant === 'draft'\n ? { background: 'var(--color-warning-95)', color: 'var(--color-warning-40)', border: '1px solid var(--color-warning-85)' }\n : { background: 'var(--color-neutral-95)', color: 'var(--color-neutral-50)', border: '1px solid var(--color-neutral-85)' };\n return (\n <span\n style={{\n ...styles,\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 8px',\n borderRadius: 'var(--border-radius-20)',\n fontSize: 'var(--font-size-10)',\n fontWeight: 'var(--font-weight-600)',\n marginRight: '4px',\n whiteSpace: 'nowrap',\n }}\n >\n {variant === 'published' ? 'Published' : variant === 'draft' ? 'Draft' : 'No state'}\n </span>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Shared nav bar style\n// ---------------------------------------------------------------------------\n\nconst NAV_BAR_STYLE: React.CSSProperties = {\n position: 'sticky',\n top: 0,\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n padding: '8px 16px',\n background: 'var(--color-surface, #fff)',\n borderBottom: '1px solid var(--color-neutral-90)',\n zIndex: 200,\n flexShrink: 0,\n};\n\n// ---------------------------------------------------------------------------\n// Table columns\n// ---------------------------------------------------------------------------\n\ntype PageRow = PuckPageListItem & { id: string };\n\nconst COLUMNS = [\n { key: 'name', label: 'Name' },\n { key: 'slug', label: 'Slug' },\n { key: 'status', label: 'Status' },\n { key: 'updatedAt', label: 'Updated' },\n { key: 'actions', label: 'Actions', shouldIgnoreRowClick: true },\n];\n\n// ---------------------------------------------------------------------------\n// PageList route\n// ---------------------------------------------------------------------------\n\ninterface PageListProps {\n backButton?: ReactNode;\n}\n\nconst PageList: React.FC<PageListProps> = ({ backButton }) => {\n const navigate = useNavigate();\n const { pages, loading, error, createPage, deletePage, refresh } = usePuckPages();\n\n const [creating, setCreating] = useState(false);\n const [newName, setNewName] = useState('');\n const [newSlug, setNewSlug] = useState('');\n const [formError, setFormError] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [deleting, setDeleting] = useState<string | null>(null);\n\n const handleCreate = async () => {\n if (!newName.trim()) { setFormError('Name is required'); return; }\n if (!newSlug.trim()) { setFormError('Slug is required'); return; }\n setFormError('');\n setSubmitting(true);\n try {\n const input: CreatePuckPageInput = {\n name: newName.trim(),\n slug: newSlug.trim().startsWith('/') ? newSlug.trim() : `/${newSlug.trim()}`,\n };\n const created = await createPage(input);\n setCreating(false);\n setNewName('');\n setNewSlug('');\n navigate(`/${created.key}/edit`, { state: { pageName: created.value.name } });\n } catch (err) {\n setFormError((err as Error).message);\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleDelete = async (page: PuckPageListItem) => {\n if (!confirm(`Delete \"${page.value.name}\"? This cannot be undone.`)) return;\n setDeleting(page.key);\n try {\n await deletePage(page.key);\n await refresh();\n } finally {\n setDeleting(null);\n }\n };\n\n if (loading) {\n return (\n <div style={{ padding: '64px', display: 'flex', justifyContent: 'center' }}>\n <LoadingSpinner />\n </div>\n );\n }\n\n if (error) {\n return (\n <div style={{ padding: '32px' }}>\n <Text.Body tone=\"negative\">Error: {error}</Text.Body>\n </div>\n );\n }\n\n const rows: PageRow[] = pages.map((p) => ({ ...p, id: p.key }));\n\n return (\n <div style={{ maxWidth: '1200px', margin: '0 auto', padding: '32px 24px' }}>\n <Spacings.Stack scale=\"l\">\n <Spacings.Inline justifyContent=\"space-between\" alignItems=\"center\">\n <Spacings.Inline scale=\"m\" alignItems=\"center\">\n {backButton}\n <Text.Headline as=\"h1\">Puck Pages</Text.Headline>\n </Spacings.Inline>\n <PrimaryButton\n label=\"New Page\"\n iconLeft={<PlusThinIcon />}\n onClick={() => setCreating(true)}\n />\n </Spacings.Inline>\n\n {creating && (\n <Card insetScale=\"l\">\n <Spacings.Stack scale=\"m\">\n <Text.Subheadline as=\"h4\" isBold>Create New Page</Text.Subheadline>\n <Spacings.Inline scale=\"m\">\n <div style={{ flex: 1 }}>\n <Spacings.Stack scale=\"xs\">\n <Label htmlFor=\"new-page-name\">Name *</Label>\n <TextInput\n id=\"new-page-name\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n placeholder=\"Home Page\"\n />\n </Spacings.Stack>\n </div>\n <div style={{ flex: 1 }}>\n <Spacings.Stack scale=\"xs\">\n <Label htmlFor=\"new-page-slug\">Slug *</Label>\n <TextInput\n id=\"new-page-slug\"\n value={newSlug}\n onChange={(e) => setNewSlug(e.target.value)}\n placeholder=\"/home\"\n />\n </Spacings.Stack>\n </div>\n </Spacings.Inline>\n {formError && <Text.Body tone=\"negative\">{formError}</Text.Body>}\n <Spacings.Inline scale=\"s\">\n <PrimaryButton\n label={submitting ? 'Creating…' : 'Create'}\n onClick={() => void handleCreate()}\n isDisabled={submitting}\n />\n <SecondaryButton\n label=\"Cancel\"\n onClick={() => { setCreating(false); setFormError(''); }}\n />\n </Spacings.Inline>\n </Spacings.Stack>\n </Card>\n )}\n\n {pages.length === 0 && !creating ? (\n <Spacings.Stack scale=\"m\" alignItems=\"center\">\n <Text.Body tone=\"secondary\">No pages yet.</Text.Body>\n <PrimaryButton\n label=\"Create first page\"\n iconLeft={<PlusThinIcon />}\n onClick={() => setCreating(true)}\n />\n </Spacings.Stack>\n ) : pages.length > 0 ? (\n <DataTable\n columns={COLUMNS}\n rows={rows}\n itemRenderer={(row: PageRow, column) => {\n switch (column.key) {\n case 'name':\n return (\n <Spacings.Stack scale=\"xs\">\n <Text.Body isBold>{row.value.name}</Text.Body>\n <Text.Detail tone=\"secondary\">{row.key}</Text.Detail>\n </Spacings.Stack>\n );\n case 'slug':\n return (\n <code\n style={{\n background: 'var(--color-neutral-95)',\n padding: '2px 6px',\n borderRadius: 'var(--border-radius-4)',\n fontSize: 'var(--font-size-10)',\n fontFamily: 'monospace',\n }}\n >\n {row.value.slug}\n </code>\n );\n case 'status':\n return (\n <span>\n {row.states.draft && <StatusBadge variant=\"draft\" />}\n {row.states.published && <StatusBadge variant=\"published\" />}\n {!row.states.draft && !row.states.published && <StatusBadge variant=\"none\" />}\n </span>\n );\n case 'updatedAt':\n return (\n <Text.Body tone=\"secondary\">\n {new Date(row.value.updatedAt).toLocaleString()}\n </Text.Body>\n );\n case 'actions':\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <PrimaryButton\n label=\"Edit\"\n size=\"20\"\n onClick={() =>\n navigate(`/${row.key}/edit`, { state: { pageName: row.value.name } })\n }\n />\n <SecondaryButton\n label=\"Preview\"\n size=\"20\"\n onClick={() =>\n navigate(`/${row.key}/preview`, { state: { pageName: row.value.name } })\n }\n />\n <FlatButton\n tone=\"critical\"\n label={deleting === row.key ? '…' : 'Delete'}\n isDisabled={deleting === row.key}\n onClick={() => void handleDelete(row)}\n />\n </div>\n );\n default:\n return null;\n }\n }}\n />\n ) : null}\n </Spacings.Stack>\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// PageEditorRoute\n// ---------------------------------------------------------------------------\n\ninterface RouteProps {\n config: Config;\n backButton?: ReactNode;\n}\n\nconst PageEditorRoute: React.FC<RouteProps> = ({ config, backButton }) => {\n const { pageKey } = useParams<{ pageKey: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const { baseURL, projectKey, businessUnitKey, jwtToken } = usePuckApiContext();\n const pageName =\n (location.state as { pageName?: string } | null)?.pageName ?? pageKey ?? 'Page';\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>\n <div style={NAV_BAR_STYLE}>\n {backButton}\n {backButton && <Text.Body tone=\"secondary\">/</Text.Body>}\n <FlatButton\n label=\"Pages\"\n icon={<AngleLeftIcon />}\n iconPosition=\"left\"\n onClick={() => navigate('/')}\n />\n <Text.Body tone=\"secondary\">/</Text.Body>\n <Text.Body isBold>{pageName}</Text.Body>\n </div>\n <div style={{ flex: 1, overflow: 'hidden' }}>\n <PuckEditor\n baseURL={baseURL}\n projectKey={projectKey}\n businessUnitKey={businessUnitKey}\n jwtToken={jwtToken ?? ''}\n pageKey={pageKey!}\n config={config}\n onError={(err: Error) => { console.error('[PageManager] editor error:', err); }}\n />\n </div>\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// PagePreviewRoute\n// ---------------------------------------------------------------------------\n\nconst PagePreviewRoute: React.FC<RouteProps> = ({ config, backButton }) => {\n const { pageKey } = useParams<{ pageKey: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const pageName =\n (location.state as { pageName?: string } | null)?.pageName ?? pageKey ?? 'Page';\n\n return (\n <div>\n <div style={NAV_BAR_STYLE}>\n {backButton}\n {backButton && <Text.Body tone=\"secondary\">/</Text.Body>}\n <FlatButton\n label=\"Pages\"\n icon={<AngleLeftIcon />}\n iconPosition=\"left\"\n onClick={() => navigate('/')}\n />\n <Text.Body tone=\"secondary\">/</Text.Body>\n <Text.Body isBold>{pageName}</Text.Body>\n <span\n style={{\n background: 'var(--color-primary-95)',\n color: 'var(--color-primary-25)',\n border: '1px solid var(--color-primary-85)',\n display: 'inline-flex',\n alignItems: 'center',\n padding: '2px 10px',\n borderRadius: 'var(--border-radius-20)',\n fontSize: 'var(--font-size-10)',\n fontWeight: 'var(--font-weight-600)',\n }}\n >\n Preview\n </span>\n </div>\n <PuckRenderer pageKey={pageKey} mode=\"preview\" config={config} />\n </div>\n );\n};\n\n// ---------------------------------------------------------------------------\n// Inner router component\n// ---------------------------------------------------------------------------\n\ninterface PageManagerInnerProps {\n config: Config;\n backButton?: ReactNode;\n}\n\nconst PageManagerInner: React.FC<PageManagerInnerProps> = ({ config, backButton }) => (\n <Routes>\n <Route path=\"/\" element={<PageList backButton={backButton} />} />\n <Route\n path=\"/:pageKey/edit\"\n element={<PageEditorRoute config={config} backButton={backButton} />}\n />\n <Route\n path=\"/:pageKey/preview\"\n element={<PagePreviewRoute config={config} backButton={backButton} />}\n />\n </Routes>\n);\n\n// ---------------------------------------------------------------------------\n// Public component\n// ---------------------------------------------------------------------------\n\nexport interface PageManagerProps {\n /** URL path where this manager is mounted, e.g. \"/pages\" — used as router basename */\n parentUrl: string;\n baseURL: string;\n projectKey: string;\n businessUnitKey: string;\n jwtToken: string;\n /** Puck component config — passed to editor and preview */\n config: Config;\n /** Optional element rendered before the breadcrumb in editor/preview headers */\n backButton?: ReactNode;\n}\n\nexport const PageManager: React.FC<PageManagerProps> = ({\n parentUrl,\n baseURL,\n projectKey,\n businessUnitKey,\n jwtToken,\n config,\n backButton,\n}) => (\n <PuckApiProvider\n baseURL={baseURL}\n projectKey={projectKey}\n businessUnitKey={businessUnitKey}\n jwtToken={jwtToken}\n >\n <BrowserRouter basename={parentUrl}>\n <PageManagerInner config={config} backButton={backButton} />\n </BrowserRouter>\n </PuckApiProvider>\n);\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@commercetools-demo/puck-page-manager",
3
+ "version": "0.1.0",
4
+ "description": "Router-aware page manager UI (list, editor, preview) for the Puck CMS integration",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "package.json"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "build:watch": "tsup --watch",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "dependencies": {
28
+ "@commercetools-demo/puck-api": "^0.1.0",
29
+ "@commercetools-demo/puck-editor": "^0.1.0",
30
+ "@commercetools-demo/puck-renderer": "^0.1.0",
31
+ "@commercetools-demo/puck-types": "^0.1.0",
32
+ "@commercetools-uikit/card": "^20.5.0",
33
+ "@commercetools-uikit/data-table": "^20.5.0",
34
+ "@commercetools-uikit/flat-button": "^20.5.0",
35
+ "@commercetools-uikit/icons": "^20.5.0",
36
+ "@commercetools-uikit/label": "^20.5.0",
37
+ "@commercetools-uikit/loading-spinner": "^20.5.0",
38
+ "@commercetools-uikit/primary-button": "^20.5.0",
39
+ "@commercetools-uikit/secondary-button": "^20.5.0",
40
+ "@commercetools-uikit/spacings": "^20.5.0",
41
+ "@commercetools-uikit/text": "^20.5.0",
42
+ "@commercetools-uikit/text-input": "^20.5.0",
43
+ "@measured/puck": "^0.18.2"
44
+ },
45
+ "peerDependencies": {
46
+ "react": ">=19.0.0",
47
+ "react-dom": ">=19.0.0",
48
+ "react-intl": ">=6.0.0",
49
+ "react-router-dom": ">=5.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/react": "^18",
53
+ "@types/react-dom": "^18",
54
+ "tsup": "^8.3.0",
55
+ "typescript": "^5.7.2"
56
+ }
57
+ }