@designcrowd/library.brand-page 5.18.3-button-fix-1 → 5.18.3-undo-35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DQLtpdLe.js → CreatedOnBrandCrowd-de-de-nGPiEkaH.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-CvEhlADd.js → CreatedOnBrandCrowd-en-us-D3ibxOrN.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-pYQeTTC0.js → CreatedOnBrandCrowd-es-es-BAq0PV5c.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CcE-iCEq.js → CreatedOnBrandCrowd-fr-ca-9foHt2a-.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CcE-iCEq.js → CreatedOnBrandCrowd-fr-fr-9foHt2a-.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-OyhWWWyO.js → CreatedOnBrandCrowd-pt-br-DO739Uxl.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-OyhWWWyO.js → CreatedOnBrandCrowd-pt-pt-DO739Uxl.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-DH98FFLS.js → CreatedOnDcom-de-de-CFbNW8tl.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DK67NN1r.js → CreatedOnDcom-en-us-BL34V8eu.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-9-QU4BU6.js → CreatedOnDcom-es-es-BKXWvHkV.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-U9J9H9VB.js → CreatedOnDcom-fr-ca-DCyU-m6J.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DqdzB1DJ.js → CreatedOnDcom-fr-fr-DEciA_zh.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-c4UiWtkB.js → CreatedOnDcom-pt-br-BVB2zdvU.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-Do2qJsYp.js → CreatedOnDcom-pt-pt-DatUuIK6.js} +1 -1
  15. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +7 -2
  16. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +7 -2
  17. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +10 -0
  18. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +7 -2
  19. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +1 -0
  20. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +23 -2
  21. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +7 -2
  22. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +3 -0
  23. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.js +11 -0
  24. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +7 -2
  25. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +7 -2
  26. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +7 -2
  27. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +7 -2
  28. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +9 -0
  29. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +20 -1
  30. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +20 -0
  31. package/lib/src/brand-page-maker/composables/useEventTracker.js +17 -0
  32. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.d.ts +16 -0
  33. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.js +22 -0
  34. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +41 -2
  35. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +307 -5
  36. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +83 -0
  37. package/lib/src/brand-page-maker/stores/history/history-store.js +488 -0
  38. package/lib/src/brand-page-maker/stores/logo-store/logo-store.d.ts +1 -0
  39. package/lib/src/brand-page-maker/stores/user/user-store.js +1 -0
  40. package/lib/src/bundled-translations-D1q3rSEz.js +175 -0
  41. package/lib/src/bundles/bundled-translations.json +3 -1
  42. package/lib/src/constants/ui.d.ts +1 -0
  43. package/lib/src/css/library.brand-page-brandCrowd.min.css +50 -54
  44. package/lib/src/css/library.brand-page-brandPage.min.css +50 -55
  45. package/lib/src/css/library.brand-page-designCom.min.css +50 -54
  46. package/lib/src/css/library.brand-page-preview.min.css +50 -54
  47. package/lib/src/index.mjs +1 -1
  48. package/lib/src/{lib-BI3J4Mbk.js → lib-C_Pc-5bF.js} +34307 -33712
  49. package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
  50. package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
  51. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +87 -2
  52. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +5 -0
  53. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.stories.js +1 -0
  54. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +23 -2
  55. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +16 -0
  56. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +7 -2
  57. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.d.ts +3 -0
  58. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.js +19 -2
  59. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.js +18 -8
  60. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +64 -0
  61. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.js +6 -0
  62. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +19 -0
  63. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +11 -0
  64. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +10 -2
  65. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +5 -1
  66. package/lib/src/shared/logo-settings/store/editable-logo-store.js +31 -0
  67. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +24 -2
  68. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +10 -2
  69. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +23 -2
  70. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +16 -0
  71. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +23 -2
  72. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +16 -0
  73. package/package.json +1 -1
  74. package/src/brand-page/components/button/Button.vue +2 -10
  75. package/src/brand-page/components/contact-form/ContactForm.vue +2 -2
  76. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +11 -0
  77. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +2 -3
  78. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +1 -0
  79. package/src/brand-page-maker/components/cookie-collection/CookieSettings.vue +18 -17
  80. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.ts +13 -0
  81. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.vue +26 -3
  82. package/src/brand-page-maker/components/quick-link-bar/RedoButton.vue +66 -0
  83. package/src/brand-page-maker/components/quick-link-bar/UndoButton.vue +66 -0
  84. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.json +3 -1
  85. package/src/brand-page-maker/components/quick-link-bar/undo-redo-buttons.test.ts +116 -0
  86. package/src/brand-page-maker/components/save-contact/SaveContact.vue +12 -19
  87. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +10 -0
  88. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +24 -1
  89. package/src/brand-page-maker/composables/useEventTracker.ts +29 -0
  90. package/src/brand-page-maker/composables/useUndoRedoFlag.ts +26 -0
  91. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +335 -0
  92. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +371 -4
  93. package/src/brand-page-maker/stores/history/history-store.test.ts +1120 -0
  94. package/src/brand-page-maker/stores/history/history-store.ts +651 -0
  95. package/src/brand-page-maker/stores/logo-store/logo-store.ts +5 -0
  96. package/src/brand-page-maker/stores/user/user-store.ts +1 -0
  97. package/src/bundles/bundled-translations.json +3 -1
  98. package/src/constants/ui.ts +1 -0
  99. package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
  100. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +5 -0
  101. package/src/shared/content-settings/components/content-settings/ContentSettings.stories.ts +1 -0
  102. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.ts +19 -2
  103. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.vue +1 -1
  104. package/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.ts +26 -10
  105. package/src/shared/content-settings/components/logo-selection-field/LogoSelection.vue +63 -48
  106. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +4 -0
  107. package/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.ts +7 -0
  108. package/src/shared/content-settings/components/text-field/TextField.vue +1 -0
  109. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +33 -4
  110. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +11 -0
  111. package/src/shared/logo-settings/store/editable-logo-store.ts +42 -1
  112. package/lib/src/bundled-translations-B5Fkt3qd.js +0 -175
@@ -40,6 +40,14 @@ import { useUiBackgroundSettingsStore } from '@shared/background-settings/store'
40
40
  import { useBrandPageMakerUserStore } from '../user';
41
41
  import { useBrandPageContainerStore } from '../brandpage-container';
42
42
  import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
43
+ import { useUiNavigationStyleSettingsStore } from '@shared/navigation-style-settings/store';
44
+ import {
45
+ CONTENT_SETTINGS_MODES,
46
+ useUiContentSettingsStore,
47
+ } from '@shared/content-settings/store';
48
+ import { useUiSideBarStore } from '@shared/side-bar/store';
49
+ import { useUiEditableLogoStore } from '@shared/logo-settings/store/editable-logo-store';
50
+ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
43
51
  import { PAGE_SECTIONS } from '@shared/page-settings/models';
44
52
  import { FabricRenderClient } from '../../../clients/fabric-render-client';
45
53
  import { setLocaleAsync } from '@src/composables/useTranslate';
@@ -560,4 +568,331 @@ describe('brand page maker store module', () => {
560
568
  // Assert
561
569
  expect(setDesignTemplateTokenSpy).not.toHaveBeenCalled();
562
570
  });
571
+
572
+ // BP-5506 regression: applyHistorySnapshot must replace nested navigation
573
+ // style refs as a whole, not deep-merge them. The previous bug was that
574
+ // object-form $patch would leave keys present in the live state but absent
575
+ // from the snapshot in place — e.g. switching nav button styles then
576
+ // undoing would leave the new style's borderColor / borderRadius applied.
577
+ test('applyHistorySnapshot replaces navigation styles wholesale (no key bleed across undo)', async () => {
578
+ // Arrange — initialise the maker so `applyHistorySnapshot` has a
579
+ // populated set of dependent stores to write into.
580
+ const makerStore = useBrandPageMakerStore();
581
+ const navigationStyleSettingsStore = useUiNavigationStyleSettingsStore();
582
+
583
+ await makerStore.initialise(INITIALISE_PAYLOAD);
584
+
585
+ // Build snapshot A — the "older" state we'll undo back to. Keep the
586
+ // navigation simple: only borderRadius is set on selectedButtonStyle.
587
+ const snapshotA = {
588
+ ...makerStore.brandPageData,
589
+ pageHeaderDesktop: {
590
+ ...makerStore.brandPageData.pageHeaderDesktop,
591
+ navigation: {
592
+ ...makerStore.brandPageData.pageHeaderDesktop?.navigation,
593
+ selectedButtonStyle: {
594
+ borderRadius: '0px',
595
+ },
596
+ },
597
+ },
598
+ } as BrandPageModel;
599
+
600
+ // Build snapshot B — the "newer" state with extra keys that the
601
+ // older snapshot does NOT have. If $patch deep-merged, these would
602
+ // survive an undo back to A.
603
+ const snapshotB = {
604
+ ...snapshotA,
605
+ pageHeaderDesktop: {
606
+ ...snapshotA.pageHeaderDesktop,
607
+ navigation: {
608
+ ...snapshotA.pageHeaderDesktop?.navigation,
609
+ selectedButtonStyle: {
610
+ borderRadius: '12px',
611
+ borderColor: 'rgb(255, 0, 0)',
612
+ borderStyle: 'dashed',
613
+ borderWidth: '4px',
614
+ },
615
+ },
616
+ },
617
+ } as BrandPageModel;
618
+
619
+ // Act — apply newer first (simulates the user making the edit), then
620
+ // older (simulates the undo). NavigationDesktop's constructor folds
621
+ // its input over a defaults object, so we read the resulting state
622
+ // and assert against the keys that came from snapshotB but NOT from
623
+ // snapshotA.
624
+ await makerStore.applyHistorySnapshot(snapshotB);
625
+ await makerStore.applyHistorySnapshot(snapshotA);
626
+
627
+ // Assert — after the undo, no keys from B should bleed through onto
628
+ // A's selectedButtonStyle. Specifically the values that are unique to
629
+ // B (red dashed border) must not be present.
630
+ const restored =
631
+ navigationStyleSettingsStore.navigation[PAGE_SECTIONS.header][
632
+ VIEWPORTS.desktop
633
+ ];
634
+ const restoredSelected = restored.selectedButtonStyle;
635
+
636
+ expect(restoredSelected.borderRadius).toBe('0px');
637
+ // The B-only values must not survive the undo. NavigationStyles'
638
+ // constructor seeds defaults for selectedButtonStyle, so we assert
639
+ // the *exact* B-only values are gone rather than a strict superset.
640
+ expect(restoredSelected.borderColor).not.toBe('rgb(255, 0, 0)');
641
+ expect(restoredSelected.borderStyle).not.toBe('dashed');
642
+ expect(restoredSelected.borderWidth).not.toBe('4px');
643
+ });
644
+
645
+ // BP-5506 regression: undoing a page-add must clear the URL/active-page
646
+ // back to a page that exists in the restored snapshot. The page-tabs
647
+ // carousel keys "selected" off the route URL; after `setNav` removes the
648
+ // added route, no nav item matches the URL slug and the highlight
649
+ // disappears. `applyHistorySnapshot` accepts an `activePageId` and writes
650
+ // it through `pageNavigationStore.setCurrentActivePage` so the routeStore
651
+ // and `currentPage` getter realign.
652
+ test('applyHistorySnapshot updates pageNavigation.activePageId when given a valid id', async () => {
653
+ const makerStore = useBrandPageMakerStore();
654
+ const pageNavigationStore = usePageNavigationStore();
655
+
656
+ await makerStore.initialise(INITIALISE_PAYLOAD);
657
+
658
+ const restoredPageId = pageNavigationStore.routes[0]?.pageId;
659
+
660
+ expect(restoredPageId).toBeDefined();
661
+
662
+ pageNavigationStore.activePageId = '';
663
+
664
+ await makerStore.applyHistorySnapshot(
665
+ makerStore.brandPageData,
666
+ restoredPageId,
667
+ );
668
+
669
+ expect(pageNavigationStore.activePageId).toBe(restoredPageId);
670
+ });
671
+
672
+ test('applyHistorySnapshot falls back to first/default route when no activePageId is provided', async () => {
673
+ const makerStore = useBrandPageMakerStore();
674
+ const pageNavigationStore = usePageNavigationStore();
675
+
676
+ await makerStore.initialise(INITIALISE_PAYLOAD);
677
+
678
+ const expectedFirstId =
679
+ pageNavigationStore.getFirstOrDefaultRoute()?.pageId;
680
+
681
+ expect(expectedFirstId).toBeDefined();
682
+
683
+ pageNavigationStore.activePageId = 'stale-page-id-not-in-nav';
684
+
685
+ await makerStore.applyHistorySnapshot(makerStore.brandPageData);
686
+
687
+ expect(pageNavigationStore.activePageId).toBe(expectedFirstId);
688
+ });
689
+
690
+ // BP-5506 follow-up: undoing a non-page-structural edit (e.g. a title
691
+ // change) must NOT push a new route. The router push fires
692
+ // `router.afterEach`, and BrandPageMaker.mixin's afterEach hook resets
693
+ // the content-settings modeStack — which would snap the sidebar back
694
+ // to the default Content tab on every undo, even when the user was
695
+ // deep-editing a content item. Same-page navigation MUST be skipped.
696
+ test('applyHistorySnapshot does NOT touch modeStack when active page is unchanged', async () => {
697
+ const makerStore = useBrandPageMakerStore();
698
+ const pageNavigationStore = usePageNavigationStore();
699
+ const contentSettingsStore = useUiContentSettingsStore();
700
+
701
+ await makerStore.initialise(INITIALISE_PAYLOAD);
702
+
703
+ const activePageId = pageNavigationStore.routes[0]?.pageId;
704
+
705
+ expect(activePageId).toBeDefined();
706
+
707
+ pageNavigationStore.activePageId = activePageId!;
708
+
709
+ // User is deep-editing a content item — focused mode pushed onto the stack.
710
+ const realItemId = contentSettingsStore.items[0]?.id;
711
+
712
+ expect(realItemId).toBeDefined();
713
+
714
+ contentSettingsStore.pushMode({
715
+ mode: CONTENT_SETTINGS_MODES.focusedContentItem,
716
+ selectedItemId: realItemId,
717
+ });
718
+ contentSettingsStore.selectedItemId = realItemId;
719
+
720
+ expect(contentSettingsStore.mode).toBe(
721
+ CONTENT_SETTINGS_MODES.focusedContentItem,
722
+ );
723
+
724
+ // Apply a snapshot whose activePageId equals the current page (i.e.
725
+ // a non-structural edit that didn't change pages — title edit, color
726
+ // change, etc.).
727
+ await makerStore.applyHistorySnapshot(
728
+ makerStore.brandPageData,
729
+ activePageId,
730
+ );
731
+
732
+ // Mode stack is preserved — no router.afterEach was triggered.
733
+ expect(contentSettingsStore.mode).toBe(
734
+ CONTENT_SETTINGS_MODES.focusedContentItem,
735
+ );
736
+ expect(contentSettingsStore.selectedItemId).toBe(realItemId);
737
+ });
738
+
739
+ // BP-5506 regression: when undoing a content add, the selected item
740
+ // disappears. The fallback must restore the Content tab's natural
741
+ // landing state (mode = edit, selectedItemId = null), not just switch
742
+ // tabs — otherwise `<FocusedContentItemSettings>` keeps rendering for
743
+ // a missing item and paints a blank panel.
744
+ test('applyHistorySnapshot resets sidebar to default Content tab when selected item is gone', async () => {
745
+ const makerStore = useBrandPageMakerStore();
746
+ const contentSettingsStore = useUiContentSettingsStore();
747
+ const sideBarStore = useUiSideBarStore();
748
+
749
+ await makerStore.initialise(INITIALISE_PAYLOAD);
750
+
751
+ // Simulate the user opening a content item's focused settings.
752
+ const orphanItemId = 'orphan-content-id-not-in-snapshot';
753
+
754
+ contentSettingsStore.pushMode({
755
+ mode: CONTENT_SETTINGS_MODES.focusedContentItem,
756
+ selectedItemId: orphanItemId,
757
+ });
758
+ contentSettingsStore.selectedItemId = orphanItemId;
759
+ sideBarStore.setSelectedTabName({
760
+ tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
761
+ });
762
+
763
+ // Pre-condition: panel is showing the focused content item.
764
+ expect(contentSettingsStore.mode).toBe(
765
+ CONTENT_SETTINGS_MODES.focusedContentItem,
766
+ );
767
+ expect(contentSettingsStore.selectedItemId).toBe(orphanItemId);
768
+
769
+ // Snapshot does NOT contain orphanItemId — simulates undo of an add.
770
+ await makerStore.applyHistorySnapshot(makerStore.brandPageData);
771
+
772
+ // Post-condition: same shape as a fresh Content tab click.
773
+ expect(contentSettingsStore.mode).toBe(CONTENT_SETTINGS_MODES.edit);
774
+ expect(contentSettingsStore.selectedItemId).toBeNull();
775
+ expect(sideBarStore.selectedTabName).toBe(
776
+ SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
777
+ );
778
+ });
779
+
780
+ // BP-5506 follow-up: applyHistorySnapshot accepts a `logoEdits` JSON
781
+ // string (sidecar to brandPageData; pre-purchase logo-tab form-field
782
+ // state). On undo it must wholesale-replace `editableLogoStore.logoEdits`
783
+ // so the form fields reflect the pre-edit state. Wholesale replacement
784
+ // matters because a previous entry's textObjects/colors must NOT leak
785
+ // through (e.g. switching template A→B then undoing must NOT keep B's
786
+ // textObject ids in A's restored state).
787
+ test('applyHistorySnapshot restores editableLogoStore.logoEdits from sidecar', async () => {
788
+ const makerStore = useBrandPageMakerStore();
789
+ const editableLogoStore = useUiEditableLogoStore();
790
+
791
+ await makerStore.initialise(INITIALISE_PAYLOAD);
792
+
793
+ // User has typed "AcmeCo" — current logoEdits state.
794
+ editableLogoStore.logoEdits.textObjects = [
795
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
796
+ {
797
+ id: 't1',
798
+ role: 'primary-text',
799
+ text: 'AcmeCo',
800
+ textEnabled: true,
801
+ } as any,
802
+ ];
803
+
804
+ // The history entry the user is undoing TO captured "Acme".
805
+ const sidecar = JSON.stringify({
806
+ backgroundObject: { id: 'bg', type: 'rect', role: 'background' },
807
+ logoObject: {
808
+ id: 'lg',
809
+ type: 'group',
810
+ role: 'logo',
811
+ logoColors: [],
812
+ logoStrokeColors: [],
813
+ },
814
+ textObjects: [
815
+ { id: 't1', role: 'primary-text', text: 'Acme', textEnabled: true },
816
+ ],
817
+ });
818
+
819
+ await makerStore.applyHistorySnapshot(
820
+ makerStore.brandPageData,
821
+ undefined,
822
+ sidecar,
823
+ );
824
+
825
+ expect(editableLogoStore.logoEdits.textObjects).toEqual([
826
+ { id: 't1', role: 'primary-text', text: 'Acme', textEnabled: true },
827
+ ]);
828
+ });
829
+
830
+ test('applyHistorySnapshot wholesale-replaces logoEdits (no leak from prior state)', async () => {
831
+ const makerStore = useBrandPageMakerStore();
832
+ const editableLogoStore = useUiEditableLogoStore();
833
+
834
+ await makerStore.initialise(INITIALISE_PAYLOAD);
835
+
836
+ // Current state has TWO textObjects (e.g. user is on template B with a
837
+ // logo + tagline).
838
+ editableLogoStore.logoEdits.textObjects = [
839
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
840
+ {
841
+ id: 'b-1',
842
+ role: 'primary-text',
843
+ text: 'Brand B',
844
+ textEnabled: true,
845
+ } as any,
846
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
847
+ { id: 'b-2', role: 'tagline', text: 'tagline', textEnabled: true } as any,
848
+ ];
849
+
850
+ // Undo target captured template A — only ONE textObject with a
851
+ // different id. After restore, b-1 / b-2 must be gone.
852
+ const sidecar = JSON.stringify({
853
+ backgroundObject: { id: 'bg', type: 'rect', role: 'background' },
854
+ logoObject: {
855
+ id: 'lg',
856
+ type: 'group',
857
+ role: 'logo',
858
+ logoColors: [],
859
+ logoStrokeColors: [],
860
+ },
861
+ textObjects: [
862
+ { id: 'a-1', role: 'primary-text', text: 'Brand A', textEnabled: true },
863
+ ],
864
+ });
865
+
866
+ await makerStore.applyHistorySnapshot(
867
+ makerStore.brandPageData,
868
+ undefined,
869
+ sidecar,
870
+ );
871
+
872
+ expect(editableLogoStore.logoEdits.textObjects).toHaveLength(1);
873
+ expect(editableLogoStore.logoEdits.textObjects[0].id).toBe('a-1');
874
+ });
875
+
876
+ test('applyHistorySnapshot leaves logoEdits untouched when sidecar is undefined', async () => {
877
+ const makerStore = useBrandPageMakerStore();
878
+ const editableLogoStore = useUiEditableLogoStore();
879
+
880
+ await makerStore.initialise(INITIALISE_PAYLOAD);
881
+
882
+ editableLogoStore.logoEdits.textObjects = [
883
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
884
+ {
885
+ id: 't1',
886
+ role: 'primary-text',
887
+ text: 'Acme',
888
+ textEnabled: true,
889
+ } as any,
890
+ ];
891
+
892
+ // No third arg — pre-existing entries from before this feature shipped.
893
+ await makerStore.applyHistorySnapshot(makerStore.brandPageData);
894
+
895
+ // Still 'Acme' — no restore attempted.
896
+ expect(editableLogoStore.logoEdits.textObjects[0].text).toBe('Acme');
897
+ });
563
898
  });