@commercetools-demo/puck-content-manager 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -12,27 +12,8 @@ import LoadingSpinner from "@commercetools-uikit/loading-spinner";
12
12
  import TextInput from "@commercetools-uikit/text-input";
13
13
  import Label from "@commercetools-uikit/label";
14
14
  import { PlusThinIcon, SearchIcon } from "@commercetools-uikit/icons";
15
+ import Stamp from "@commercetools-uikit/stamp";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
16
- var StatusBadge = ({ variant }) => {
17
- 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)" };
18
- return /* @__PURE__ */ jsx(
19
- "span",
20
- {
21
- style: {
22
- ...styles,
23
- display: "inline-flex",
24
- alignItems: "center",
25
- padding: "2px 8px",
26
- borderRadius: "var(--border-radius-20)",
27
- fontSize: "var(--font-size-10)",
28
- fontWeight: "var(--font-weight-600)",
29
- marginRight: "4px",
30
- whiteSpace: "nowrap"
31
- },
32
- children: variant === "published" ? "Published" : variant === "draft" ? "Draft" : "No state"
33
- }
34
- );
35
- };
36
17
  var columns = [
37
18
  { key: "name", label: "Name" },
38
19
  { key: "contentType", label: "Content Type" },
@@ -178,7 +159,7 @@ var ContentList = ({ defaultContentType, onEdit }) => {
178
159
  itemRenderer: (row, column) => {
179
160
  switch (column.key) {
180
161
  case "name":
181
- return /* @__PURE__ */ jsx(Text.Body, { isBold: true, children: row.value.name });
162
+ return /* @__PURE__ */ jsx(Text.Body, { fontWeight: "bold", children: row.value.name });
182
163
  case "contentType":
183
164
  return /* @__PURE__ */ jsx(
184
165
  "code",
@@ -196,10 +177,10 @@ var ContentList = ({ defaultContentType, onEdit }) => {
196
177
  case "status": {
197
178
  const hasDraft = !!row.states.draft;
198
179
  const hasPublished = !!row.states.published;
199
- return /* @__PURE__ */ jsxs("span", { children: [
200
- hasDraft && /* @__PURE__ */ jsx(StatusBadge, { variant: "draft" }),
201
- hasPublished && /* @__PURE__ */ jsx(StatusBadge, { variant: "published" }),
202
- !hasDraft && !hasPublished && /* @__PURE__ */ jsx(StatusBadge, { variant: "none" })
180
+ return /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", gap: "4px", flexWrap: "wrap" }, children: [
181
+ hasDraft && /* @__PURE__ */ jsx(Stamp, { tone: "warning", label: "Draft", isCondensed: true }),
182
+ hasPublished && /* @__PURE__ */ jsx(Stamp, { tone: "positive", label: "Published", isCondensed: true }),
183
+ !hasDraft && !hasPublished && /* @__PURE__ */ jsx(Stamp, { tone: "secondary", label: "No state", isCondensed: true })
203
184
  ] });
204
185
  }
205
186
  case "updatedAt":
@@ -225,7 +206,7 @@ var ContentList = ({ defaultContentType, onEdit }) => {
225
206
  )
226
207
  ] }) });
227
208
  };
228
- var ContentManager = ({
209
+ var ContentManagerList = ({
229
210
  baseURL,
230
211
  projectKey,
231
212
  businessUnitKey,
@@ -251,115 +232,21 @@ import { PuckApiProvider as PuckApiProvider2, usePuckContent } from "@commerceto
251
232
  import {
252
233
  ComponentSearchProvider,
253
234
  ComponentsPanel,
254
- ComponentItemFilter
235
+ ComponentItemFilter,
236
+ EditorToolbar
255
237
  } from "@commercetools-demo/puck-editor";
238
+ import {
239
+ VersionHistoryProvider,
240
+ VersionPreviewBanner,
241
+ VersionAwareFieldsPanel,
242
+ VersionHistoryButton,
243
+ useVersionHistoryPanel,
244
+ useVersionDiff
245
+ } from "@commercetools-demo/puck-version-history";
246
+ import LoadingSpinner2 from "@commercetools-uikit/loading-spinner";
247
+ import Text2 from "@commercetools-uikit/text";
248
+ import Spacings2 from "@commercetools-uikit/spacings";
256
249
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
257
- var BADGE_STYLES = {
258
- saving: { bg: "rgba(251, 191, 36, 0.12)", color: "var(--status-saving)", border: "rgba(251, 191, 36, 0.3)" },
259
- unsaved: { bg: "rgba(100, 116, 139, 0.12)", color: "var(--text-muted)", border: "rgba(100, 116, 139, 0.3)" },
260
- draft: { bg: "rgba(129, 140, 248, 0.12)", color: "var(--status-draft)", border: "rgba(129, 140, 248, 0.3)" },
261
- published: { bg: "rgba(6, 214, 160, 0.12)", color: "var(--status-published)", border: "rgba(6, 214, 160, 0.3)" }
262
- };
263
- var StatusBadge2 = ({
264
- label,
265
- variant
266
- }) => {
267
- const bs = BADGE_STYLES[variant];
268
- return /* @__PURE__ */ jsx2(
269
- "span",
270
- {
271
- style: {
272
- display: "inline-flex",
273
- alignItems: "center",
274
- padding: "2px 10px",
275
- borderRadius: "12px",
276
- fontSize: "12px",
277
- fontWeight: 600,
278
- background: bs.bg,
279
- color: bs.color,
280
- border: `1px solid ${bs.border}`
281
- },
282
- children: label
283
- }
284
- );
285
- };
286
- var ContentToolbar = ({
287
- saving,
288
- isDirty,
289
- states,
290
- onSave,
291
- onPublish,
292
- onRevert
293
- }) => {
294
- const hasDraft = Boolean(states.draft);
295
- const hasPublished = Boolean(states.published);
296
- return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" }, children: [
297
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
298
- saving && /* @__PURE__ */ jsx2(StatusBadge2, { label: "Saving\u2026", variant: "saving" }),
299
- !saving && isDirty && /* @__PURE__ */ jsx2(StatusBadge2, { label: "Unsaved", variant: "unsaved" }),
300
- !saving && !isDirty && hasDraft && /* @__PURE__ */ jsx2(StatusBadge2, { label: "Draft", variant: "draft" }),
301
- hasPublished && /* @__PURE__ */ jsx2(StatusBadge2, { label: "Published", variant: "published" })
302
- ] }),
303
- hasDraft && hasPublished && /* @__PURE__ */ jsx2(
304
- "button",
305
- {
306
- onClick: onRevert,
307
- disabled: saving,
308
- style: {
309
- padding: "6px 14px",
310
- borderRadius: "4px",
311
- border: "1px solid var(--border-glow)",
312
- background: "transparent",
313
- color: "var(--text-muted)",
314
- fontWeight: 500,
315
- fontSize: "13px",
316
- cursor: saving ? "not-allowed" : "pointer",
317
- opacity: saving ? 0.5 : 1
318
- },
319
- children: "Revert to Published"
320
- }
321
- ),
322
- /* @__PURE__ */ jsx2(
323
- "button",
324
- {
325
- onClick: onSave,
326
- disabled: !isDirty || saving,
327
- style: {
328
- padding: "6px 14px",
329
- borderRadius: "4px",
330
- border: "1px solid var(--border-glow)",
331
- background: "transparent",
332
- color: "var(--text-muted)",
333
- fontWeight: 500,
334
- fontSize: "13px",
335
- cursor: !isDirty || saving ? "not-allowed" : "pointer",
336
- opacity: !isDirty || saving ? 0.4 : 1
337
- },
338
- children: "Save"
339
- }
340
- ),
341
- /* @__PURE__ */ jsx2(
342
- "button",
343
- {
344
- onClick: onPublish,
345
- disabled: saving,
346
- style: {
347
- padding: "6px 16px",
348
- borderRadius: "4px",
349
- border: "1px solid var(--accent-cyan)",
350
- background: "rgba(0, 212, 255, 0.1)",
351
- color: "var(--accent-cyan)",
352
- fontWeight: 600,
353
- fontSize: "13px",
354
- cursor: saving ? "not-allowed" : "pointer",
355
- opacity: saving ? 0.5 : 1,
356
- boxShadow: "0 0 12px rgba(0, 212, 255, 0.15)"
357
- },
358
- children: hasPublished ? "Re-publish" : "Publish"
359
- }
360
- )
361
- ] });
362
- };
363
250
  var ContentEditorInner = ({
364
251
  contentKey,
365
252
  config,
@@ -370,16 +257,35 @@ var ContentEditorInner = ({
370
257
  const {
371
258
  content,
372
259
  states,
260
+ versions,
373
261
  saving,
374
262
  loading,
375
263
  error,
376
264
  saveDraft,
377
265
  publish,
378
- revertToPublished
266
+ revertToPublished,
267
+ loadVersions
379
268
  } = usePuckContent(contentKey);
380
269
  const latestDataRef = useRef(null);
381
270
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState2(false);
271
+ const [isApplyingVersion, setIsApplyingVersion] = useState2(false);
272
+ const currentData = states.draft?.data ?? content?.data ?? {
273
+ content: [],
274
+ root: { props: {} }
275
+ };
276
+ const versionHistory = useVersionHistoryPanel({
277
+ versions,
278
+ loadVersions,
279
+ currentData
280
+ });
281
+ const diff = useVersionDiff(
282
+ versionHistory.previewData,
283
+ currentData
284
+ );
285
+ const isPreviewingRef = useRef(false);
286
+ isPreviewingRef.current = versionHistory.isPreviewingHistory;
382
287
  const handleChange = useCallback((data) => {
288
+ if (isPreviewingRef.current) return;
383
289
  latestDataRef.current = data;
384
290
  setHasUnsavedChanges(true);
385
291
  }, []);
@@ -415,6 +321,21 @@ var ContentEditorInner = ({
415
321
  onError?.(err);
416
322
  }
417
323
  }, [revertToPublished, onError]);
324
+ const handleApplyVersion = useCallback(async () => {
325
+ const versionData = versionHistory.previewData;
326
+ if (!versionData) return;
327
+ setIsApplyingVersion(true);
328
+ try {
329
+ await saveDraft(versionData);
330
+ setHasUnsavedChanges(false);
331
+ onSave?.(versionData);
332
+ versionHistory.clearSelection();
333
+ } catch (err) {
334
+ onError?.(err);
335
+ } finally {
336
+ setIsApplyingVersion(false);
337
+ }
338
+ }, [versionHistory, saveDraft, onSave, onError]);
418
339
  const contentConfig = useMemo(() => {
419
340
  const otherRootFields = Object.fromEntries(
420
341
  Object.entries(config.root?.fields ?? {}).filter(([k]) => k !== "title")
@@ -437,69 +358,73 @@ var ContentEditorInner = ({
437
358
  };
438
359
  }, [config]);
439
360
  if (loading) {
440
- return /* @__PURE__ */ jsx2(
441
- "div",
442
- {
443
- style: {
444
- display: "flex",
445
- alignItems: "center",
446
- justifyContent: "center",
447
- height: "100vh",
448
- fontSize: "16px",
449
- color: "var(--text-muted)"
450
- },
451
- children: "Loading editor\u2026"
452
- }
453
- );
361
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }, children: /* @__PURE__ */ jsxs2(Spacings2.Stack, { scale: "m", alignItems: "center", children: [
362
+ /* @__PURE__ */ jsx2(LoadingSpinner2, {}),
363
+ /* @__PURE__ */ jsx2(Text2.Body, { tone: "secondary", children: "Loading editor\u2026" })
364
+ ] }) });
454
365
  }
455
366
  if (error) {
456
- return /* @__PURE__ */ jsxs2(
457
- "div",
458
- {
459
- style: {
460
- padding: "32px",
461
- color: "var(--status-error)",
462
- background: "rgba(248, 113, 113, 0.08)",
463
- border: "1px solid rgba(248, 113, 113, 0.25)",
464
- borderRadius: "8px",
465
- margin: "16px"
466
- },
467
- children: [
468
- /* @__PURE__ */ jsx2("strong", { children: "Error loading content:" }),
469
- " ",
470
- error
471
- ]
472
- }
473
- );
367
+ return /* @__PURE__ */ jsx2("div", { style: { padding: "32px" }, children: /* @__PURE__ */ jsxs2(Text2.Body, { tone: "negative", children: [
368
+ /* @__PURE__ */ jsx2("strong", { children: "Error loading content:" }),
369
+ " ",
370
+ error
371
+ ] }) });
474
372
  }
475
- const activeData = states.draft?.data ?? content?.data ?? {
476
- content: [],
477
- root: { props: {} }
478
- };
479
- return /* @__PURE__ */ jsx2(ComponentSearchProvider, { children: /* @__PURE__ */ jsx2(
480
- Puck,
373
+ const activeData = versionHistory.previewData ?? currentData;
374
+ const toolbarStates = states;
375
+ return /* @__PURE__ */ jsx2(
376
+ VersionHistoryProvider,
481
377
  {
482
- config: contentConfig,
483
- data: activeData,
484
- onChange: handleChange,
485
- onPublish: handlePublish,
486
- overrides: {
487
- headerActions: () => /* @__PURE__ */ jsx2(
488
- ContentToolbar,
489
- {
490
- saving,
491
- isDirty: hasUnsavedChanges,
492
- states,
493
- onSave: () => void handleSave(),
494
- onPublish: () => void handlePublish(activeData),
495
- onRevert: () => void handleRevert()
378
+ diff,
379
+ isPreviewingHistory: versionHistory.isPreviewingHistory,
380
+ versions,
381
+ isLoadingVersions: versionHistory.isLoadingVersions,
382
+ selectedVersionId: versionHistory.selectedVersionId,
383
+ isApplying: isApplyingVersion,
384
+ onVersionSelect: versionHistory.selectVersion,
385
+ onApply: () => void handleApplyVersion(),
386
+ onDiscard: versionHistory.clearSelection,
387
+ onLoadVersions: versionHistory.openPanel,
388
+ children: /* @__PURE__ */ jsx2(ComponentSearchProvider, { children: /* @__PURE__ */ jsx2(
389
+ Puck,
390
+ {
391
+ config: contentConfig,
392
+ data: activeData,
393
+ onChange: handleChange,
394
+ onPublish: handlePublish,
395
+ overrides: {
396
+ headerActions: () => versionHistory.isPreviewingHistory ? /* @__PURE__ */ jsxs2(Spacings2.Inline, { scale: "s", alignItems: "center", children: [
397
+ /* @__PURE__ */ jsx2(
398
+ VersionPreviewBanner,
399
+ {
400
+ timestamp: versionHistory.selectedVersion.timestamp,
401
+ onApply: () => void handleApplyVersion(),
402
+ onDiscard: versionHistory.clearSelection,
403
+ isApplying: isApplyingVersion
404
+ }
405
+ ),
406
+ /* @__PURE__ */ jsx2(VersionHistoryButton, { disabled: isApplyingVersion })
407
+ ] }) : /* @__PURE__ */ jsx2(
408
+ EditorToolbar,
409
+ {
410
+ saving,
411
+ isDirty: hasUnsavedChanges,
412
+ states: toolbarStates,
413
+ onSave: () => void handleSave(),
414
+ onPublish: () => void handlePublish(activeData),
415
+ onRevert: () => void handleRevert(),
416
+ showPublishButton: true
417
+ }
418
+ ),
419
+ components: ({ children }) => /* @__PURE__ */ jsx2(ComponentsPanel, { children }),
420
+ componentItem: ({ children, name }) => /* @__PURE__ */ jsx2(ComponentItemFilter, { name, children }),
421
+ fields: ({ children, isLoading }) => /* @__PURE__ */ jsx2(VersionAwareFieldsPanel, { isLoading, children })
496
422
  }
497
- ),
498
- components: ({ children }) => /* @__PURE__ */ jsx2(ComponentsPanel, { children }),
499
- componentItem: ({ children, name }) => /* @__PURE__ */ jsx2(ComponentItemFilter, { name, children })
500
- }
423
+ },
424
+ versionHistory.selectedVersionId ?? "current"
425
+ ) })
501
426
  }
502
- ) });
427
+ );
503
428
  };
504
429
  var ContentEditor = ({
505
430
  baseURL,
@@ -546,8 +471,18 @@ import "@measured/puck/puck.css";
546
471
  import {
547
472
  ComponentSearchProvider as ComponentSearchProvider2,
548
473
  ComponentsPanel as ComponentsPanel2,
549
- ComponentItemFilter as ComponentItemFilter2
474
+ ComponentItemFilter as ComponentItemFilter2,
475
+ defaultPuckConfig,
476
+ EditorToolbar as EditorToolbar2
550
477
  } from "@commercetools-demo/puck-editor";
478
+ import {
479
+ VersionHistoryProvider as VersionHistoryProvider2,
480
+ VersionHistoryButton as VersionHistoryButton2,
481
+ VersionPreviewBanner as VersionPreviewBanner2,
482
+ VersionAwareFieldsPanel as VersionAwareFieldsPanel2,
483
+ useVersionHistoryPanel as useVersionHistoryPanel2,
484
+ useVersionDiff as useVersionDiff2
485
+ } from "@commercetools-demo/puck-version-history";
551
486
  import {
552
487
  PuckApiProvider as PuckApiProvider3,
553
488
  usePuckContents as usePuckContents2,
@@ -558,128 +493,17 @@ import PrimaryButton2 from "@commercetools-uikit/primary-button";
558
493
  import SecondaryButton2 from "@commercetools-uikit/secondary-button";
559
494
  import FlatButton2 from "@commercetools-uikit/flat-button";
560
495
  import Card2 from "@commercetools-uikit/card";
561
- import Spacings2 from "@commercetools-uikit/spacings";
562
- import Text2 from "@commercetools-uikit/text";
563
- import LoadingSpinner2 from "@commercetools-uikit/loading-spinner";
496
+ import Spacings3 from "@commercetools-uikit/spacings";
497
+ import Text3 from "@commercetools-uikit/text";
498
+ import LoadingSpinner3 from "@commercetools-uikit/loading-spinner";
564
499
  import TextInput2 from "@commercetools-uikit/text-input";
565
500
  import Label2 from "@commercetools-uikit/label";
501
+ import Stamp2 from "@commercetools-uikit/stamp";
566
502
  import { PlusThinIcon as PlusThinIcon2, SearchIcon as SearchIcon2, AngleLeftIcon } from "@commercetools-uikit/icons";
567
503
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
568
- var StatusBadge3 = ({ variant }) => {
569
- 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)" };
570
- return /* @__PURE__ */ jsx3(
571
- "span",
572
- {
573
- style: {
574
- ...styles,
575
- display: "inline-flex",
576
- alignItems: "center",
577
- padding: "2px 8px",
578
- borderRadius: "var(--border-radius-20)",
579
- fontSize: "var(--font-size-10)",
580
- fontWeight: "var(--font-weight-600)",
581
- marginRight: "4px",
582
- whiteSpace: "nowrap"
583
- },
584
- children: variant === "published" ? "Published" : variant === "draft" ? "Draft" : "No state"
585
- }
586
- );
587
- };
588
- var BADGE_STYLES2 = {
589
- saving: { bg: "rgba(251, 191, 36, 0.12)", color: "var(--status-saving)", border: "rgba(251, 191, 36, 0.3)" },
590
- unsaved: { bg: "rgba(100, 116, 139, 0.12)", color: "var(--text-muted)", border: "rgba(100, 116, 139, 0.3)" },
591
- draft: { bg: "rgba(129, 140, 248, 0.12)", color: "var(--status-draft)", border: "rgba(129, 140, 248, 0.3)" },
592
- published: { bg: "rgba(6, 214, 160, 0.12)", color: "var(--status-published)", border: "rgba(6, 214, 160, 0.3)" }
593
- };
594
- var EditorStatusBadge = ({ label, variant }) => {
595
- const bs = BADGE_STYLES2[variant];
596
- return /* @__PURE__ */ jsx3(
597
- "span",
598
- {
599
- style: {
600
- display: "inline-flex",
601
- alignItems: "center",
602
- padding: "2px 10px",
603
- borderRadius: "12px",
604
- fontSize: "12px",
605
- fontWeight: 600,
606
- background: bs.bg,
607
- color: bs.color,
608
- border: `1px solid ${bs.border}`
609
- },
610
- children: label
611
- }
612
- );
613
- };
614
- var ContentToolbar2 = ({ saving, isDirty, states, onSave, onPublish, onRevert }) => {
615
- const hasDraft = Boolean(states.draft);
616
- const hasPublished = Boolean(states.published);
617
- return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" }, children: [
618
- /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
619
- saving && /* @__PURE__ */ jsx3(EditorStatusBadge, { label: "Saving\u2026", variant: "saving" }),
620
- !saving && isDirty && /* @__PURE__ */ jsx3(EditorStatusBadge, { label: "Unsaved", variant: "unsaved" }),
621
- !saving && !isDirty && hasDraft && /* @__PURE__ */ jsx3(EditorStatusBadge, { label: "Draft", variant: "draft" }),
622
- hasPublished && /* @__PURE__ */ jsx3(EditorStatusBadge, { label: "Published", variant: "published" })
623
- ] }),
624
- hasDraft && hasPublished && /* @__PURE__ */ jsx3(
625
- "button",
626
- {
627
- onClick: onRevert,
628
- disabled: saving,
629
- style: {
630
- padding: "6px 14px",
631
- borderRadius: "4px",
632
- border: "1px solid var(--border-glow)",
633
- background: "transparent",
634
- color: "var(--text-muted)",
635
- fontWeight: 500,
636
- fontSize: "13px",
637
- cursor: saving ? "not-allowed" : "pointer",
638
- opacity: saving ? 0.5 : 1
639
- },
640
- children: "Revert to Published"
641
- }
642
- ),
643
- /* @__PURE__ */ jsx3(
644
- "button",
645
- {
646
- onClick: onSave,
647
- disabled: !isDirty || saving,
648
- style: {
649
- padding: "6px 14px",
650
- borderRadius: "4px",
651
- border: "1px solid var(--border-glow)",
652
- background: "transparent",
653
- color: "var(--text-muted)",
654
- fontWeight: 500,
655
- fontSize: "13px",
656
- cursor: !isDirty || saving ? "not-allowed" : "pointer",
657
- opacity: !isDirty || saving ? 0.4 : 1
658
- },
659
- children: "Save"
660
- }
661
- ),
662
- /* @__PURE__ */ jsx3(
663
- "button",
664
- {
665
- onClick: onPublish,
666
- disabled: saving,
667
- style: {
668
- padding: "6px 16px",
669
- borderRadius: "4px",
670
- border: "1px solid var(--accent-cyan)",
671
- background: "rgba(0, 212, 255, 0.1)",
672
- color: "var(--accent-cyan)",
673
- fontWeight: 600,
674
- fontSize: "13px",
675
- cursor: saving ? "not-allowed" : "pointer",
676
- opacity: saving ? 0.5 : 1,
677
- boxShadow: "0 0 12px rgba(0, 212, 255, 0.15)"
678
- },
679
- children: hasPublished ? "Re-publish" : "Publish"
680
- }
681
- )
682
- ] });
504
+ var DEFAULT_CONFIG = {
505
+ ...defaultPuckConfig,
506
+ components: { ...defaultPuckConfig.components }
683
507
  };
684
508
  var NAV_BAR_STYLE = {
685
509
  position: "sticky",
@@ -749,11 +573,11 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
749
573
  }
750
574
  };
751
575
  const rows = contents.map((c) => ({ ...c, id: c.key }));
752
- return /* @__PURE__ */ jsx3("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: /* @__PURE__ */ jsxs3(Spacings2.Stack, { scale: "l", children: [
753
- /* @__PURE__ */ jsxs3(Spacings2.Inline, { justifyContent: "space-between", alignItems: "center", children: [
754
- /* @__PURE__ */ jsxs3(Spacings2.Inline, { scale: "m", alignItems: "center", children: [
576
+ return /* @__PURE__ */ jsx3("div", { style: { maxWidth: "1200px", margin: "0 auto", padding: "32px 24px" }, children: /* @__PURE__ */ jsxs3(Spacings3.Stack, { scale: "l", children: [
577
+ /* @__PURE__ */ jsxs3(Spacings3.Inline, { justifyContent: "space-between", alignItems: "center", children: [
578
+ /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "m", alignItems: "center", children: [
755
579
  backButton,
756
- /* @__PURE__ */ jsx3(Text2.Headline, { as: "h1", children: "Content Items" })
580
+ /* @__PURE__ */ jsx3(Text3.Headline, { as: "h1", children: "Content Items" })
757
581
  ] }),
758
582
  /* @__PURE__ */ jsx3(
759
583
  PrimaryButton2,
@@ -764,11 +588,11 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
764
588
  }
765
589
  )
766
590
  ] }),
767
- showCreate && /* @__PURE__ */ jsx3(Card2, { insetScale: "l", children: /* @__PURE__ */ jsxs3(Spacings2.Stack, { scale: "m", children: [
768
- /* @__PURE__ */ jsx3(Text2.Subheadline, { as: "h4", isBold: true, children: "Create Content Item" }),
769
- createError && /* @__PURE__ */ jsx3(Text2.Body, { tone: "negative", children: createError }),
770
- /* @__PURE__ */ jsxs3(Spacings2.Inline, { scale: "m", children: [
771
- /* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(Spacings2.Stack, { scale: "xs", children: [
591
+ showCreate && /* @__PURE__ */ jsx3(Card2, { insetScale: "l", children: /* @__PURE__ */ jsxs3(Spacings3.Stack, { scale: "m", children: [
592
+ /* @__PURE__ */ jsx3(Text3.Subheadline, { as: "h4", isBold: true, children: "Create Content Item" }),
593
+ createError && /* @__PURE__ */ jsx3(Text3.Body, { tone: "negative", children: createError }),
594
+ /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "m", children: [
595
+ /* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(Spacings3.Stack, { scale: "xs", children: [
772
596
  /* @__PURE__ */ jsx3(Label2, { htmlFor: "create-content-name", children: "Name" }),
773
597
  /* @__PURE__ */ jsx3(
774
598
  TextInput2,
@@ -780,7 +604,7 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
780
604
  }
781
605
  )
782
606
  ] }) }),
783
- /* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(Spacings2.Stack, { scale: "xs", children: [
607
+ /* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs3(Spacings3.Stack, { scale: "xs", children: [
784
608
  /* @__PURE__ */ jsx3(Label2, { htmlFor: "create-content-type", children: "Content Type" }),
785
609
  /* @__PURE__ */ jsx3(
786
610
  TextInput2,
@@ -793,7 +617,7 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
793
617
  )
794
618
  ] }) })
795
619
  ] }),
796
- /* @__PURE__ */ jsxs3(Spacings2.Inline, { scale: "s", children: [
620
+ /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "s", children: [
797
621
  /* @__PURE__ */ jsx3(
798
622
  PrimaryButton2,
799
623
  {
@@ -805,7 +629,7 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
805
629
  /* @__PURE__ */ jsx3(SecondaryButton2, { label: "Cancel", onClick: () => setShowCreate(false) })
806
630
  ] })
807
631
  ] }) }),
808
- /* @__PURE__ */ jsxs3(Spacings2.Inline, { scale: "s", alignItems: "center", children: [
632
+ /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "s", alignItems: "center", children: [
809
633
  /* @__PURE__ */ jsx3("div", { style: { flex: 1, maxWidth: "280px" }, children: /* @__PURE__ */ jsx3(
810
634
  TextInput2,
811
635
  {
@@ -834,8 +658,8 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
834
658
  ),
835
659
  /* @__PURE__ */ jsx3(FlatButton2, { label: "Refresh", onClick: () => void refresh() })
836
660
  ] }),
837
- error && /* @__PURE__ */ jsx3(Text2.Body, { tone: "negative", children: error }),
838
- loading ? /* @__PURE__ */ jsx3("div", { style: { display: "flex", justifyContent: "center", padding: "48px" }, children: /* @__PURE__ */ jsx3(LoadingSpinner2, {}) }) : contents.length === 0 ? /* @__PURE__ */ jsx3(Spacings2.Stack, { scale: "m", alignItems: "center", children: /* @__PURE__ */ jsx3(Text2.Body, { tone: "secondary", children: "No content items found." }) }) : /* @__PURE__ */ jsx3(
661
+ error && /* @__PURE__ */ jsx3(Text3.Body, { tone: "negative", children: error }),
662
+ loading ? /* @__PURE__ */ jsx3("div", { style: { display: "flex", justifyContent: "center", padding: "48px" }, children: /* @__PURE__ */ jsx3(LoadingSpinner3, {}) }) : contents.length === 0 ? /* @__PURE__ */ jsx3(Spacings3.Stack, { scale: "m", alignItems: "center", children: /* @__PURE__ */ jsx3(Text3.Body, { tone: "secondary", children: "No content items found." }) }) : /* @__PURE__ */ jsx3(
839
663
  DataTable2,
840
664
  {
841
665
  columns: COLUMNS,
@@ -843,7 +667,7 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
843
667
  itemRenderer: (row, column) => {
844
668
  switch (column.key) {
845
669
  case "name":
846
- return /* @__PURE__ */ jsx3(Text2.Body, { isBold: true, children: row.value.name });
670
+ return /* @__PURE__ */ jsx3(Text3.Body, { fontWeight: "bold", children: row.value.name });
847
671
  case "contentType":
848
672
  return /* @__PURE__ */ jsx3(
849
673
  "code",
@@ -861,16 +685,16 @@ var ContentListRoute = ({ defaultContentType, backButton }) => {
861
685
  case "status": {
862
686
  const hasDraft = !!row.states.draft;
863
687
  const hasPublished = !!row.states.published;
864
- return /* @__PURE__ */ jsxs3("span", { children: [
865
- hasDraft && /* @__PURE__ */ jsx3(StatusBadge3, { variant: "draft" }),
866
- hasPublished && /* @__PURE__ */ jsx3(StatusBadge3, { variant: "published" }),
867
- !hasDraft && !hasPublished && /* @__PURE__ */ jsx3(StatusBadge3, { variant: "none" })
688
+ return /* @__PURE__ */ jsxs3("span", { style: { display: "inline-flex", gap: "4px", flexWrap: "wrap" }, children: [
689
+ hasDraft && /* @__PURE__ */ jsx3(Stamp2, { tone: "warning", label: "Draft", isCondensed: true }),
690
+ hasPublished && /* @__PURE__ */ jsx3(Stamp2, { tone: "positive", label: "Published", isCondensed: true }),
691
+ !hasDraft && !hasPublished && /* @__PURE__ */ jsx3(Stamp2, { tone: "secondary", label: "No state", isCondensed: true })
868
692
  ] });
869
693
  }
870
694
  case "updatedAt":
871
- return /* @__PURE__ */ jsx3(Text2.Body, { tone: "secondary", children: new Date(row.value.updatedAt).toLocaleDateString() });
695
+ return /* @__PURE__ */ jsx3(Text3.Body, { tone: "secondary", children: new Date(row.value.updatedAt).toLocaleDateString() });
872
696
  case "actions":
873
- return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
697
+ return /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "s", alignItems: "center", children: [
874
698
  /* @__PURE__ */ jsx3(
875
699
  PrimaryButton2,
876
700
  {
@@ -905,16 +729,29 @@ var ContentEditorRoute = ({ config, backButton }) => {
905
729
  const {
906
730
  content,
907
731
  states,
732
+ versions,
908
733
  saving,
909
734
  loading,
910
735
  error,
911
736
  saveDraft,
912
737
  publish,
913
- revertToPublished
738
+ revertToPublished,
739
+ loadVersions
914
740
  } = usePuckContent2(contentKey);
915
741
  const latestDataRef = useRef2(null);
916
742
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState3(false);
743
+ const [isApplyingVersion, setIsApplyingVersion] = useState3(false);
744
+ const currentData = states.draft?.data ?? content?.data ?? { content: [], root: { props: {} } };
745
+ const versionHistory = useVersionHistoryPanel2({
746
+ versions,
747
+ loadVersions,
748
+ currentData
749
+ });
750
+ const diff = useVersionDiff2(versionHistory.previewData, currentData);
751
+ const isPreviewingRef = useRef2(false);
752
+ isPreviewingRef.current = versionHistory.isPreviewingHistory;
917
753
  const handleChange = useCallback2((data) => {
754
+ if (isPreviewingRef.current) return;
918
755
  latestDataRef.current = data;
919
756
  setHasUnsavedChanges(true);
920
757
  }, []);
@@ -948,6 +785,20 @@ var ContentEditorRoute = ({ config, backButton }) => {
948
785
  console.error("[ContentManagerRouter] revert error:", err);
949
786
  }
950
787
  }, [revertToPublished]);
788
+ const handleApplyVersion = useCallback2(async () => {
789
+ const versionData = versionHistory.previewData;
790
+ if (!versionData) return;
791
+ setIsApplyingVersion(true);
792
+ try {
793
+ await saveDraft(versionData);
794
+ setHasUnsavedChanges(false);
795
+ versionHistory.clearSelection();
796
+ } catch (err) {
797
+ console.error("[ContentManagerRouter] apply version error:", err);
798
+ } finally {
799
+ setIsApplyingVersion(false);
800
+ }
801
+ }, [versionHistory, saveDraft]);
951
802
  const contentConfig = useMemo2(() => {
952
803
  const otherRootFields = Object.fromEntries(
953
804
  Object.entries(config.root?.fields ?? {}).filter(([k]) => k !== "title")
@@ -970,86 +821,90 @@ var ContentEditorRoute = ({ config, backButton }) => {
970
821
  };
971
822
  }, [config]);
972
823
  if (loading) {
973
- return /* @__PURE__ */ jsx3(
974
- "div",
975
- {
976
- style: {
977
- display: "flex",
978
- alignItems: "center",
979
- justifyContent: "center",
980
- height: "100vh",
981
- fontSize: "16px",
982
- color: "var(--text-muted)"
983
- },
984
- children: "Loading editor\u2026"
985
- }
986
- );
824
+ return /* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }, children: /* @__PURE__ */ jsxs3(Spacings3.Stack, { scale: "m", alignItems: "center", children: [
825
+ /* @__PURE__ */ jsx3(LoadingSpinner3, {}),
826
+ /* @__PURE__ */ jsx3(Text3.Body, { tone: "secondary", children: "Loading editor\u2026" })
827
+ ] }) });
987
828
  }
988
829
  if (error) {
989
- return /* @__PURE__ */ jsxs3(
990
- "div",
991
- {
992
- style: {
993
- padding: "32px",
994
- color: "var(--status-error)",
995
- background: "rgba(248, 113, 113, 0.08)",
996
- border: "1px solid rgba(248, 113, 113, 0.25)",
997
- borderRadius: "8px",
998
- margin: "16px"
999
- },
1000
- children: [
1001
- /* @__PURE__ */ jsx3("strong", { children: "Error loading content:" }),
1002
- " ",
1003
- error
1004
- ]
1005
- }
1006
- );
830
+ return /* @__PURE__ */ jsx3("div", { style: { padding: "32px" }, children: /* @__PURE__ */ jsxs3(Text3.Body, { tone: "negative", children: [
831
+ /* @__PURE__ */ jsx3("strong", { children: "Error loading content:" }),
832
+ " ",
833
+ error
834
+ ] }) });
1007
835
  }
1008
- const activeData = states.draft?.data ?? content?.data ?? {
1009
- content: [],
1010
- root: { props: {} }
1011
- };
1012
- return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
1013
- /* @__PURE__ */ jsxs3("div", { style: NAV_BAR_STYLE, children: [
1014
- backButton,
1015
- backButton && /* @__PURE__ */ jsx3(Text2.Body, { tone: "secondary", children: "/" }),
1016
- /* @__PURE__ */ jsx3(
1017
- FlatButton2,
1018
- {
1019
- label: "Content Items",
1020
- icon: /* @__PURE__ */ jsx3(AngleLeftIcon, {}),
1021
- iconPosition: "left",
1022
- onClick: () => history.push("/")
1023
- }
1024
- ),
1025
- /* @__PURE__ */ jsx3(Text2.Body, { tone: "secondary", children: "/" }),
1026
- /* @__PURE__ */ jsx3(Text2.Body, { isBold: true, children: contentName })
1027
- ] }),
1028
- /* @__PURE__ */ jsx3("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ jsx3(ComponentSearchProvider2, { children: /* @__PURE__ */ jsx3(
1029
- Puck2,
1030
- {
1031
- config: contentConfig,
1032
- data: activeData,
1033
- onChange: handleChange,
1034
- onPublish: handlePublish,
1035
- overrides: {
1036
- headerActions: () => /* @__PURE__ */ jsx3(
1037
- ContentToolbar2,
836
+ const activeData = versionHistory.previewData ?? currentData;
837
+ const toolbarStates = states;
838
+ return /* @__PURE__ */ jsx3(
839
+ VersionHistoryProvider2,
840
+ {
841
+ diff,
842
+ isPreviewingHistory: versionHistory.isPreviewingHistory,
843
+ versions,
844
+ isLoadingVersions: versionHistory.isLoadingVersions,
845
+ selectedVersionId: versionHistory.selectedVersionId,
846
+ isApplying: isApplyingVersion,
847
+ onVersionSelect: versionHistory.selectVersion,
848
+ onApply: () => void handleApplyVersion(),
849
+ onDiscard: versionHistory.clearSelection,
850
+ onLoadVersions: versionHistory.openPanel,
851
+ children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
852
+ /* @__PURE__ */ jsxs3("div", { style: NAV_BAR_STYLE, children: [
853
+ backButton,
854
+ backButton && /* @__PURE__ */ jsx3(Text3.Body, { tone: "secondary", children: "/" }),
855
+ /* @__PURE__ */ jsx3(
856
+ FlatButton2,
1038
857
  {
1039
- saving,
1040
- isDirty: hasUnsavedChanges,
1041
- states,
1042
- onSave: () => void handleSave(),
1043
- onPublish: () => void handlePublish(activeData),
1044
- onRevert: () => void handleRevert()
858
+ label: "Content Items",
859
+ icon: /* @__PURE__ */ jsx3(AngleLeftIcon, {}),
860
+ iconPosition: "left",
861
+ onClick: () => history.push("/")
1045
862
  }
1046
863
  ),
1047
- components: ({ children }) => /* @__PURE__ */ jsx3(ComponentsPanel2, { children }),
1048
- componentItem: ({ children, name }) => /* @__PURE__ */ jsx3(ComponentItemFilter2, { name, children })
1049
- }
1050
- }
1051
- ) }) })
1052
- ] });
864
+ /* @__PURE__ */ jsx3(Text3.Body, { tone: "secondary", children: "/" }),
865
+ /* @__PURE__ */ jsx3(Text3.Body, { fontWeight: "bold", children: contentName })
866
+ ] }),
867
+ /* @__PURE__ */ jsx3("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ jsx3(ComponentSearchProvider2, { children: /* @__PURE__ */ jsx3(
868
+ Puck2,
869
+ {
870
+ config: contentConfig,
871
+ data: activeData,
872
+ onChange: handleChange,
873
+ onPublish: handlePublish,
874
+ overrides: {
875
+ headerActions: () => versionHistory.isPreviewingHistory ? /* @__PURE__ */ jsxs3(Spacings3.Inline, { scale: "s", alignItems: "center", children: [
876
+ /* @__PURE__ */ jsx3(
877
+ VersionPreviewBanner2,
878
+ {
879
+ timestamp: versionHistory.selectedVersion.timestamp,
880
+ onApply: () => void handleApplyVersion(),
881
+ onDiscard: versionHistory.clearSelection,
882
+ isApplying: isApplyingVersion
883
+ }
884
+ ),
885
+ /* @__PURE__ */ jsx3(VersionHistoryButton2, { disabled: isApplyingVersion })
886
+ ] }) : /* @__PURE__ */ jsx3(
887
+ EditorToolbar2,
888
+ {
889
+ saving,
890
+ isDirty: hasUnsavedChanges,
891
+ states: toolbarStates,
892
+ onSave: () => void handleSave(),
893
+ onPublish: () => void handlePublish(activeData),
894
+ onRevert: () => void handleRevert(),
895
+ showPublishButton: true
896
+ }
897
+ ),
898
+ components: ({ children }) => /* @__PURE__ */ jsx3(ComponentsPanel2, { children }),
899
+ componentItem: ({ children, name }) => /* @__PURE__ */ jsx3(ComponentItemFilter2, { name, children }),
900
+ fields: ({ children, isLoading }) => /* @__PURE__ */ jsx3(VersionAwareFieldsPanel2, { isLoading, children })
901
+ }
902
+ },
903
+ versionHistory.selectedVersionId ?? "current"
904
+ ) }) })
905
+ ] })
906
+ }
907
+ );
1053
908
  };
1054
909
  var ContentManagerRouterInner = ({
1055
910
  config,
@@ -1072,13 +927,13 @@ var ContentManagerRouterInner = ({
1072
927
  }
1073
928
  )
1074
929
  ] });
1075
- var ContentManagerRouter = ({
930
+ var ContentManager = ({
1076
931
  parentUrl,
1077
932
  baseURL,
1078
933
  projectKey,
1079
934
  businessUnitKey,
1080
935
  jwtToken,
1081
- config,
936
+ config = DEFAULT_CONFIG,
1082
937
  defaultContentType,
1083
938
  backButton
1084
939
  }) => /* @__PURE__ */ jsx3(
@@ -1101,6 +956,6 @@ var ContentManagerRouter = ({
1101
956
  export {
1102
957
  ContentEditor,
1103
958
  ContentManager,
1104
- ContentManagerRouter
959
+ ContentManagerList
1105
960
  };
1106
961
  //# sourceMappingURL=index.mjs.map