@designcrowd/library.brand-page 6.0.3 → 6.0.4

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 (383) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-BctSP4tp.js → CreatedOnBrandCrowd-de-de-Ruu5Az32.js} +3 -3
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BeNytcxt.js → CreatedOnBrandCrowd-en-us-DGUJtvld.js} +3 -3
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-hY12f5TN.js → CreatedOnBrandCrowd-es-es-Dg-1uOfV.js} +3 -3
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-C4SCU39P.js → CreatedOnBrandCrowd-fr-ca-CRKraZl8.js} +3 -3
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-C4SCU39P.js → CreatedOnBrandCrowd-fr-fr-CRKraZl8.js} +3 -3
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-C5J5kWiD.js → CreatedOnBrandCrowd-pt-br-bZ9VlEAu.js} +3 -3
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-C5J5kWiD.js → CreatedOnBrandCrowd-pt-pt-bZ9VlEAu.js} +3 -3
  8. package/lib/src/{CreatedOnDcom-de-de-DXCeZZLg.js → CreatedOnDcom-de-de-CJYfwZx8.js} +3 -3
  9. package/lib/src/{CreatedOnDcom-en-us-GeBTaofv.js → CreatedOnDcom-en-us-rzA1lVxH.js} +3 -3
  10. package/lib/src/{CreatedOnDcom-es-es-BiPmv1q-.js → CreatedOnDcom-es-es-CNwGPjik.js} +3 -3
  11. package/lib/src/{CreatedOnDcom-fr-ca-Cns_iX4-.js → CreatedOnDcom-fr-ca-DKw7OGIz.js} +3 -3
  12. package/lib/src/{CreatedOnDcom-fr-fr-CC-f_hUR.js → CreatedOnDcom-fr-fr-WzOEaAZG.js} +3 -3
  13. package/lib/src/{CreatedOnDcom-pt-br-DnhSuPKo.js → CreatedOnDcom-pt-br-DkualVhm.js} +3 -3
  14. package/lib/src/{CreatedOnDcom-pt-pt-BCgbUsqY.js → CreatedOnDcom-pt-pt-w4Nnsdzq.js} +3 -3
  15. package/lib/src/brand-page/clients/brand-page.client.d.ts +9 -9
  16. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +2 -1
  17. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.d.ts +2 -4
  18. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.js +0 -1
  19. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +2 -4
  20. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +4 -5
  21. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -1
  22. package/lib/src/brand-page/components/page/PageComponent.mixin.d.ts +1 -1
  23. package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +3 -3
  24. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +13 -13
  25. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +13 -13
  26. package/lib/src/brand-page/constants/sections/footer-display.constants.js +1 -1
  27. package/lib/src/brand-page/models/index.d.ts +13 -2
  28. package/lib/src/brand-page/models/index.js +0 -3
  29. package/lib/src/brand-page/models/payment.model.d.ts +1 -1
  30. package/lib/src/brand-page/utils/personalisation.util.js +14 -72
  31. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +19 -21
  32. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +0 -1
  33. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +10 -16
  34. package/lib/src/brand-page-maker/components/admin-background-settings/ShapePositionSlider.mixin.d.ts +1 -1
  35. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +3 -3
  36. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +170 -181
  37. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +0 -3
  38. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +0 -1
  39. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +12 -12
  40. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.js +2 -2
  41. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.js +7 -0
  42. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +149 -148
  43. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +21 -21
  44. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.js +1 -1
  45. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.d.ts +2 -4
  46. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.js +0 -1
  47. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.d.ts +2 -4
  48. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.js +0 -1
  49. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.d.ts +2 -5
  50. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.js +0 -1
  51. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.d.ts +2 -4
  52. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.js +0 -1
  53. package/lib/src/brand-page-maker/components/device/Device.mixin.d.ts +2 -4
  54. package/lib/src/brand-page-maker/components/device/Device.mixin.js +0 -1
  55. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +2 -4
  56. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +0 -1
  57. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +3 -3
  58. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +11 -11
  59. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +25 -27
  60. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +0 -1
  61. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +27 -27
  62. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.js +1 -1
  63. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +12 -17
  64. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +12 -12
  65. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +32 -30
  66. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +5 -16
  67. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +11 -11
  68. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +6 -3
  69. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  70. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +6 -6
  71. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -2
  72. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +6 -6
  73. package/lib/src/brand-page-maker/constants/config-settings-constant.js +3 -3
  74. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.d.ts +1 -1
  75. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.js +1 -1
  76. package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -1
  77. package/lib/src/brand-page-maker/models/navigation-style-configs.js +1 -1
  78. package/lib/src/brand-page-maker/routing/brand-page-maker-router.d.ts +2 -1
  79. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +378 -366
  80. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +4 -5
  81. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +5 -8
  82. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +1 -3
  83. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +3 -7
  84. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +15 -15
  85. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +0 -6
  86. package/lib/src/brand-page-maker/stores/ui/ui-store.js +0 -8
  87. package/lib/src/brand-page-maker/utils/content-settings.util.js +1 -1
  88. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +1 -1
  89. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +4 -4
  90. package/lib/src/clients/ai-assistant-client.d.ts +0 -7
  91. package/lib/src/clients/brand-page-client.d.ts +15 -16
  92. package/lib/src/clients/design-template-client.d.ts +0 -3
  93. package/lib/src/clients/media-client.d.ts +2 -2
  94. package/lib/src/clients/models.d.ts +0 -2
  95. package/lib/src/composables/useSnapshot.js +18 -18
  96. package/lib/src/css/library.brand-page-brandCrowd.min.css +324 -342
  97. package/lib/src/css/library.brand-page-brandPage.min.css +324 -620
  98. package/lib/src/css/library.brand-page-designCom.min.css +324 -342
  99. package/lib/src/css/library.brand-page-preview.min.css +324 -598
  100. package/lib/src/index.d.ts +1 -5
  101. package/lib/src/index.mjs +106 -110
  102. package/lib/src/{lib-Cw6L6CfQ.js → lib-Dy7MYyqz.js} +33240 -36457
  103. package/lib/src/lib.js +1 -11
  104. package/lib/src/metadata-builder/builders/footer-builder.js +62 -105
  105. package/lib/src/metadata-builder/builders/item-id-utils.d.ts +54 -0
  106. package/lib/src/metadata-builder/builders/item-id-utils.js +96 -0
  107. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +57 -68
  108. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +58 -93
  109. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +66 -99
  110. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +57 -17
  111. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +51 -85
  112. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +49 -74
  113. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +0 -7
  114. package/lib/src/metadata-builder/builders/section-field-utils.js +1 -1
  115. package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
  116. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +16 -7
  117. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +66 -48
  118. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.d.ts +1 -1
  119. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.js +8 -8
  120. package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +13 -13
  121. package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -3
  122. package/lib/src/shared/color-picker/components/ColorPicker.mixin.d.ts +2 -4
  123. package/lib/src/shared/color-picker/components/ColorPicker.mixin.js +2 -2
  124. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.d.ts +2 -4
  125. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.js +0 -1
  126. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.d.ts +2 -5
  127. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.js +0 -1
  128. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +1 -0
  129. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +129 -131
  130. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +1 -2
  131. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +110 -111
  132. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +81 -84
  133. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +0 -5
  134. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +109 -117
  135. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +14 -1
  136. package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +1 -0
  137. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +70 -72
  138. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +3 -4
  139. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.d.ts +4 -4
  140. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.d.ts +1 -3
  141. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.js +0 -1
  142. package/lib/src/shared/content-settings/components/images-field/ImagesField.mixin.d.ts +2 -2
  143. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +3 -4
  144. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -1
  145. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +40 -40
  146. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigOptionField.mixin.d.ts +6 -5
  147. package/lib/src/shared/content-settings/components/shape-field/ShapeField.mixin.d.ts +1 -0
  148. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +2 -2
  149. package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +1 -0
  150. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +2 -1
  151. package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +1 -0
  152. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +2 -1
  153. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -1
  154. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +28 -28
  155. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +1 -0
  156. package/lib/src/shared/content-settings/components/toggle-field/ToggleField.mixin.d.ts +2 -2
  157. package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +1 -0
  158. package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +1 -0
  159. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +39 -39
  160. package/lib/src/shared/content-settings/utils.js +1 -0
  161. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.d.ts +4 -6
  162. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.js +0 -1
  163. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.d.ts +2 -4
  164. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.js +0 -1
  165. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +21 -29
  166. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +1 -1
  167. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +51 -50
  168. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.d.ts +4 -6
  169. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.js +0 -1
  170. package/lib/src/shared/logo-settings/store/editable-logo-store.js +1 -1
  171. package/lib/src/shared/logo-settings/store/logo-settings-store.d.ts +1 -1
  172. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +5 -13
  173. package/lib/src/shared/logo-versions/LogoVersions.mixin.js +0 -1
  174. package/lib/src/shared/models.d.ts +0 -2
  175. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +6 -14
  176. package/lib/src/shared/my-designs/MyDesigns.mixin.js +0 -1
  177. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +5 -14
  178. package/lib/src/shared/my-uploads/MyMedia.mixin.js +0 -1
  179. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +5 -14
  180. package/lib/src/shared/my-uploads/MyUploads.mixin.js +0 -1
  181. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.d.ts +3 -5
  182. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +0 -1
  183. package/lib/src/shared/navigation-style-settings/store/index.d.ts +2 -2
  184. package/lib/src/shared/page-navigation/store/page-navigation-store.d.ts +2 -2
  185. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +28 -27
  186. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.js +2 -0
  187. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +179 -188
  188. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +177 -181
  189. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +1 -1
  190. package/lib/src/shared/page-settings/store/page-settings-store.d.ts +9 -9
  191. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +39 -39
  192. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.js +1 -0
  193. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +18 -18
  194. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +6 -6
  195. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +60 -66
  196. package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -1
  197. package/lib/src/shared/style-settings/store/style-settings-store.js +1 -1
  198. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +450 -20
  199. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  200. package/lib/src/shared/template-settings/models.d.ts +0 -1
  201. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +0 -4
  202. package/lib/src/shared/template-settings/store/template-settings-store.js +11 -79
  203. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +4 -9
  204. package/lib/src/utils/build-asset-manifest.d.ts +0 -4
  205. package/lib/src/utils/build-asset-manifest.js +0 -8
  206. package/lib/src/utils/minify-brand-page-metadata.d.ts +2 -0
  207. package/lib/src/utils/minify-brand-page-metadata.js +17 -2
  208. package/package.json +56 -60
  209. package/src/brand-page/components/about-section/AboutSection.vue.test.ts +5 -7
  210. package/src/brand-page/components/brand-page-footer/BrandPageFooter.vue +1 -1
  211. package/src/brand-page/components/image/Image.mixin.ts +1 -1
  212. package/src/brand-page/components/image/Image.test.ts +1 -1
  213. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +2 -1
  214. package/src/brand-page/components/images-section/ImagesSection.vue +1 -0
  215. package/src/brand-page/components/logo/LogoRender.vue +188 -188
  216. package/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.ts +0 -1
  217. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +6 -15
  218. package/src/brand-page/components/page-footer/PageFooter.vue +0 -1
  219. package/src/brand-page/components/page-header/HeaderLayout.vue +6 -12
  220. package/src/brand-page/components/page-header/PageHeader.vue +0 -1
  221. package/src/brand-page/components/shapes-section/ShapesSection.vue +1 -1
  222. package/src/brand-page/components/shop/CartModal.vue +3 -1
  223. package/src/brand-page/components/shop/FeaturedDisplay.vue +2 -2
  224. package/src/brand-page/components/shop/PaymentModal.vue +5 -1
  225. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  226. package/src/brand-page/components/shop/Shop.vue +1 -1
  227. package/src/brand-page/components/shop/TextDisplay.vue +1 -1
  228. package/src/brand-page/components/shop/ThumbnailDisplay.vue +2 -2
  229. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +3 -3
  230. package/src/brand-page/components/text-wrapper/TextWrapper.vue +1 -3
  231. package/src/brand-page/constants/sections/footer-display.constants.ts +1 -1
  232. package/src/brand-page/models/index.ts +12 -4
  233. package/src/brand-page/models/payment.model.ts +1 -2
  234. package/src/brand-page/models/shop.model.ts +2 -0
  235. package/src/brand-page/models/user-personalisation.model.ts +2 -1
  236. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +0 -3
  237. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +0 -1
  238. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +0 -2
  239. package/src/brand-page/utils/migration/migration-01_1.ts +1 -1
  240. package/src/brand-page/utils/migration/migration-02.ts +1 -0
  241. package/src/brand-page/utils/migration/migration-03.ts +1 -0
  242. package/src/brand-page/utils/migration/migration-04.ts +1 -0
  243. package/src/brand-page/utils/migration/migration-05.ts +5 -1
  244. package/src/brand-page/utils/migration/migration-05_2.ts +1 -1
  245. package/src/brand-page/utils/migration/migration-08.test.ts +1 -1
  246. package/src/brand-page/utils/personalisation.util.test.ts +0 -35
  247. package/src/brand-page/utils/personalisation.util.ts +23 -119
  248. package/src/brand-page/view-models.ts +56 -38
  249. package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +6 -6
  250. package/src/brand-page-maker/assessors/color-replacement-icon-visibility.assessor.ts +2 -2
  251. package/src/brand-page-maker/assessors/color-replacement-profile-visibility.assessor.ts +2 -2
  252. package/src/brand-page-maker/assessors/color-replacement-visibility.assessor.ts +2 -2
  253. package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +14 -14
  254. package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +0 -1
  255. package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +0 -1
  256. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +1 -5
  257. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +0 -1
  258. package/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.ts +5 -2
  259. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +5 -0
  260. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.ts +8 -0
  261. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-site-template.examples.ts +2 -0
  262. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +0 -1
  263. package/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.ts +1 -1
  264. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +2 -1
  265. package/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.ts +0 -1
  266. package/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.ts +0 -1
  267. package/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.ts +0 -1
  268. package/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.ts +0 -1
  269. package/src/brand-page-maker/components/device/Device.mixin.ts +0 -1
  270. package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +0 -1
  271. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +1 -3
  272. package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +4 -1
  273. package/src/brand-page-maker/components/seo-settings/DeleteDomainModal.vue +1 -1
  274. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +0 -1
  275. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +1 -1
  276. package/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.ts +1 -0
  277. package/src/brand-page-maker/components/seo-settings/UrlSettings.vue +1 -0
  278. package/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.vue +5 -1
  279. package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -1
  280. package/src/brand-page-maker/components/shop/ReplaceImageSettingsForShop.vue +1 -1
  281. package/src/brand-page-maker/components/social-share/SocialShare.vue +1 -1
  282. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +8 -22
  283. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +10 -5
  284. package/src/brand-page-maker/components/video-play/VideoPlayButton.vue +1 -1
  285. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +7 -3
  286. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
  287. package/src/brand-page-maker/constants/config-settings-constant.ts +5 -5
  288. package/src/brand-page-maker/convertors/text-image-display-style.convertor.ts +1 -1
  289. package/src/brand-page-maker/models/button-styles-config.ts +2 -4
  290. package/src/brand-page-maker/models/content-settings-configs.ts +2 -4
  291. package/src/brand-page-maker/models/navigation-style-configs.ts +6 -5
  292. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +1 -0
  293. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +5 -8
  294. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +3 -1
  295. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +4 -12
  296. package/src/brand-page-maker/stores/ui/ui-store.ts +0 -16
  297. package/src/brand-page-maker/utils/content-settings.util.ts +1 -1
  298. package/src/brand-page-maker/utils/rich-text-editor.util.ts +4 -4
  299. package/src/clients/ai-assistant-client.ts +0 -7
  300. package/src/clients/design-template-client.ts +0 -3
  301. package/src/clients/models.ts +0 -2
  302. package/src/composables/useSnapshot.ts +22 -19
  303. package/src/lib.ts +0 -13
  304. package/src/metadata-builder/builders/footer-builder.test.ts +229 -130
  305. package/src/metadata-builder/builders/footer-builder.ts +90 -155
  306. package/src/metadata-builder/builders/item-id-utils.test.ts +184 -0
  307. package/src/metadata-builder/builders/item-id-utils.ts +117 -0
  308. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +62 -88
  309. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +66 -129
  310. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +105 -160
  311. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +65 -20
  312. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +83 -146
  313. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +70 -122
  314. package/src/metadata-builder/builders/section-field-utils.ts +1 -1
  315. package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
  316. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +16 -7
  317. package/src/metadata-builder/parsers/section-tool-arguments.ts +66 -48
  318. package/src/plugins/google-maps-plugin/google-maps-plugin.ts +8 -8
  319. package/src/shared/background-settings/components/BackgroundSettings.vue +1 -1
  320. package/src/shared/background-settings/components/background-color/BackgroundColorSettings.vue +1 -1
  321. package/src/shared/color-picker/components/ColorPicker.mixin.ts +7 -2
  322. package/src/shared/color-picker/components/ColorPickerSwatch.mixin.ts +0 -1
  323. package/src/shared/common/NumberInput.vue +0 -1
  324. package/src/shared/common/SideBarSettingsHeader.vue +2 -2
  325. package/src/shared/confirm-modal/ConfirmModal.mixin.ts +0 -1
  326. package/src/shared/content-settings/components/booking-url-field/BookingUrlField.vue +0 -1
  327. package/src/shared/content-settings/components/button-configuration-field/ButtonConfigurationField.vue +0 -1
  328. package/src/shared/content-settings/components/color-field/ColorField.vue +10 -3
  329. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -1
  330. package/src/shared/content-settings/components/content-settings/ContentSettingsLockedButton.vue +0 -1
  331. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +0 -5
  332. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +14 -1
  333. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +6 -4
  334. package/src/shared/content-settings/components/icon-library/IconLibrary.mixin.ts +0 -1
  335. package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -1
  336. package/src/shared/content-settings/components/logo-selection-field/LogoSelectionField.vue +1 -1
  337. package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -1
  338. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +1 -1
  339. package/src/shared/content-settings/components/personalisation-role-field/PersonalisationRoleField.vue +4 -4
  340. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +8 -2
  341. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -1
  342. package/src/shared/content-settings/models.ts +2 -3
  343. package/src/shared/content-settings/utils.ts +1 -0
  344. package/src/shared/dropzone-image-uploader/components/DropzoneImageUploader.vue +0 -1
  345. package/src/shared/ecommerce-settings/store/cart-store.test.ts +1 -1
  346. package/src/shared/font-family-selector/FontFamilySelector.mixin.ts +0 -1
  347. package/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.ts +0 -1
  348. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +1 -1
  349. package/src/shared/logo-settings/components/LogoSettings.mixin.ts +1 -0
  350. package/src/shared/logo-settings/components/LogoSettingsHeader.mixin.ts +0 -1
  351. package/src/shared/logo-settings/components/LogoStyleSettingsWithState.vue +2 -2
  352. package/src/shared/logo-settings/components/LogoTemplateSearch.vue +1 -1
  353. package/src/shared/logo-settings/store/editable-logo-store.ts +1 -1
  354. package/src/shared/logo-settings/store/logo-settings-store.test.ts +4 -4
  355. package/src/shared/logo-versions/LogoVersions.mixin.ts +0 -1
  356. package/src/shared/models.ts +0 -6
  357. package/src/shared/my-designs/MyDesigns.mixin.ts +0 -1
  358. package/src/shared/my-uploads/MyMedia.mixin.ts +0 -1
  359. package/src/shared/my-uploads/MyMediaSelectionItem.vue +1 -2
  360. package/src/shared/my-uploads/MyUploads.mixin.ts +0 -1
  361. package/src/shared/my-uploads/models.ts +2 -1
  362. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +0 -1
  363. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -1
  364. package/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.ts +3 -0
  365. package/src/shared/page-settings/components/page-settings/NestedDraggable.vue +1 -1
  366. package/src/shared/page-settings/components/page-settings/PageSettings.vue +2 -1
  367. package/src/shared/page-settings/components/page-settings-section-styles/HeaderDisplayStyle.vue +1 -1
  368. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +1 -1
  369. package/src/shared/page-settings/store/page-settings-store.test.ts +8 -4
  370. package/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.ts +1 -0
  371. package/src/shared/shape-library/ShapeLibrary.vue +2 -2
  372. package/src/shared/style-settings/store/style-settings-store.ts +1 -1
  373. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  374. package/src/shared/template-settings/models.ts +0 -1
  375. package/src/shared/template-settings/store/template-settings-store.ts +18 -105
  376. package/src/shared/unsplash-library/UnsplashLibrary.vue +6 -2
  377. package/src/shared/video-library/VideoLibrary.vue +1 -1
  378. package/src/utils/build-asset-manifest.ts +0 -12
  379. package/src/utils/minify-brand-page-metadata.ts +27 -7
  380. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.d.ts +0 -103
  381. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.js +0 -178
  382. package/src/brand-page/components/banner-section/BannerSection.mixin.ts +0 -210
  383. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +0 -12
package/lib/src/lib.js CHANGED
@@ -31,18 +31,8 @@ export * as brandPageUtils from './brand-page/utils';
31
31
  export { getOptimalLogoSize, calculateOptimizedLogoDimensions, applyLogoImageBase64UrlToBrandPageTemplateModel, recalculateLogoContentDimensions, recalculateHeaderLogoSizes, } from './brand-page/utils/logo.util';
32
32
  export { sanitizeRTEHtml } from './brand-page-maker/utils';
33
33
  export { getPageSlugFromPageTitle } from './brand-page-maker/utils/slug.util';
34
- // AI-pipeline preview (longclaw per-turn snapshots): web-renderer's
35
- // /preview/ai-pipeline render page + manifest server route apply the agent's
36
- // tool calls to a brand-page metadata snapshot server-side and resolve the
37
- // target page by slug. These three symbols are otherwise internal to the
38
- // metadata-builder / route utils.
39
- export { executeToolCallsAsync } from './metadata-builder/ai-metadata-executor';
40
- export { findNavItemByPageSlug } from './brand-page/utils/route.util';
41
- // Tiptap-JSON RTE -> HTML (same converter the metadata builders use). Lets the
42
- // preview render the agent's raw Tiptap fields, which the renderer expects as HTML.
43
- export { tiptapJsonToHtml } from './metadata-builder/helpers/rte.helpers';
44
34
  // stores
45
- export { useBrandPageMakerStore, useBrandPageMakerUserStore, useUiStore, useBrandPageContainerStore, useEventManagerStore, useLocalisedRouteStore, useVideoStore, useRouteStore, } from './brand-page-maker/stores';
35
+ export { useBrandPageMakerStore, useBrandPageMakerUserStore, useUiStore, useBrandPageContainerStore, useEventManagerStore, useLocalisedRouteStore, useVideoStore, } from './brand-page-maker/stores';
46
36
  export { useShopConfigStore } from './shared/ecommerce-settings/store/shop-settings-store';
47
37
  // for jest, need to set active pinia in library.brand-page as well
48
38
  import { createPinia, setActivePinia } from 'pinia';
@@ -1,7 +1,8 @@
1
1
  import {} from '../../brand-page/models';
2
2
  import { BaseMetadataBuilder, } from '../models';
3
3
  import { FOOTER_CHECKS } from './section-rules/footer.rules';
4
- import { applyDetachedStyleOverride, normalizeStyleValue, } from './section-field-utils';
4
+ import { applyDetachedStyleOverride } from './section-field-utils';
5
+ import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from './item-id-utils';
5
6
  const normaliseSocialUrl = (url) => {
6
7
  for (const prefix of ['mailto:', 'tel:']) {
7
8
  if (url.startsWith(prefix))
@@ -9,100 +10,64 @@ const normaliseSocialUrl = (url) => {
9
10
  }
10
11
  return url;
11
12
  };
12
- const makeSocialLink = (icon, url) => ({
13
- imageUrl: icon || '',
14
- url: normaliseSocialUrl(url || ''),
15
- imageTitle: '',
16
- width: 0,
17
- height: 0,
18
- imageLink: '',
19
- });
20
- const hasSocialLinkMutation = (args) => args._replace_social_links === true ||
21
- (args._remove_social_link_indices?.length ?? 0) > 0 ||
22
- (args._reorder_social_links?.length ?? 0) > 0 ||
23
- (args.social_links?.length ?? 0) > 0;
24
- /**
25
- * Social links are a GLOBAL footer concern — one logical list that both
26
- * viewports render identically. Derive the new list ONCE from the current one
27
- * WITHOUT mutating the input, so the caller can assign an independent copy to
28
- * each viewport.
29
- *
30
- * Why this can't mutate per-viewport in place: footers migrated from the legacy
31
- * single `footerStyles` model (migration-01) share ONE `socialLinks` array
32
- * reference across pageFooterDesktop and pageFooterMobile, and `cloneDeep`
33
- * preserves that shared reference. Running an in-place `splice` once per
34
- * viewport therefore applies it TWICE to the same array — e.g. one requested
35
- * removal index drops two links. Compute-once + assign-fresh is correct for
36
- * both shared (legacy) and independent (new-model) footers.
37
- */
38
- const computeSocialLinks = (current, args) => {
39
- // _replace_social_links: replace entire list (empty/absent social_links = clear all).
40
- // A replacement supersedes every other social link mutation.
41
- if (args._replace_social_links) {
42
- return (args.social_links ?? []).map((l) => makeSocialLink(l.social_link_icon, l.url));
43
- }
44
- const links = [...(current ?? [])];
45
- // item_index-based updates for existing links — replace the item reference
46
- // (never mutate the original object, which may be shared across viewports).
47
- for (const link of args.social_links ?? []) {
48
- if (link.item_index === undefined)
49
- continue;
50
- const existing = links[link.item_index];
51
- if (!existing)
52
- continue;
53
- links[link.item_index] = {
54
- ...existing,
55
- ...(link.social_link_icon !== undefined
56
- ? { imageUrl: link.social_link_icon }
57
- : {}),
58
- ...(link.url !== undefined ? { url: normaliseSocialUrl(link.url) } : {}),
59
- };
60
- }
61
- // Remove by index (descending order to preserve indices during splice).
62
- if (args._remove_social_link_indices?.length) {
63
- const sorted = [...args._remove_social_link_indices].sort((a, b) => b - a);
64
- for (const idx of sorted) {
65
- if (idx >= 0 && idx < links.length)
66
- links.splice(idx, 1);
67
- }
68
- }
69
- // Insert new links (descending insert_at order to preserve positions).
70
- const insertLinks = (args.social_links ?? []).filter((l) => l.insert_at !== undefined && l.item_index === undefined);
71
- const sortedInserts = [...insertLinks].sort((a, b) => b.insert_at - a.insert_at);
72
- for (const link of sortedInserts) {
73
- const pos = Math.max(0, Math.min(link.insert_at, links.length));
74
- links.splice(pos, 0, makeSocialLink(link.social_link_icon, link.url));
75
- }
76
- // Reorder (requires ALL indices — partial reorder is not supported).
77
- if (args._reorder_social_links?.length) {
78
- const newOrder = args._reorder_social_links;
79
- const unique = new Set(newOrder);
80
- if (unique.size === newOrder.length &&
81
- newOrder.every((idx) => idx >= 0 && idx < links.length)) {
82
- const reordered = newOrder.map((idx) => links[idx]);
83
- if (reordered.length === links.length)
84
- return reordered;
85
- }
86
- }
87
- return links;
88
- };
89
13
  const applyGlobalFooterChanges = (footer, args, textStyleOptions) => {
90
14
  if (args.copyright_text !== undefined)
91
15
  footer.copyrightText = args.copyright_text;
92
- // copyright_text_style is the same text-style object sections use (typography
93
- // + colour). Normalise each value the way section styles are normalised
94
- // (letterSpacing int→em, lineHeight snap, null→''), then detach from the
95
- // global preset via the override helper so a single call resolves the preset
96
- // and clears textStyleType once see resolveGlobalPresetIntoStyle (BP-5420).
97
- if (args.copyright_text_style) {
98
- const updates = {};
99
- for (const [key, value] of Object.entries(args.copyright_text_style)) {
100
- const normalized = normalizeStyleValue(key, value);
101
- if (normalized !== undefined)
102
- updates[key] = normalized;
16
+ if (args.copyright_text_font_family !== undefined)
17
+ footer.copyrightStyle = applyDetachedStyleOverride(footer.copyrightStyle, { fontFamily: args.copyright_text_font_family }, textStyleOptions);
18
+ const links = args.social_links;
19
+ // _replace_social_links: replace entire list (empty/absent social_links = clear all).
20
+ // When replacing, all other social link mutations (remove, insert, reorder) are skipped —
21
+ // they are superseded by the replacement and running them would cause duplicates.
22
+ if (args._replace_social_links) {
23
+ footer.socialLinks = (links ?? []).map((l) => ({
24
+ id: generateItemId(),
25
+ imageUrl: l.social_link_icon || '',
26
+ url: normaliseSocialUrl(l.url || ''),
27
+ imageTitle: '',
28
+ width: 0,
29
+ height: 0,
30
+ imageLink: '',
31
+ }));
32
+ }
33
+ else {
34
+ // Targeted mutations — only run when NOT replacing the entire list.
35
+ // BP-5603: id-based contract (item_id / move_before_item_id / _remove_social_link_ids).
36
+ // Backfill ids on legacy links so they become referenceable after this call.
37
+ ensureItemIds(footer.socialLinks);
38
+ // Remove by id (order-independent — no index shifting needed).
39
+ footer.socialLinks = removeItemsByIds(footer.socialLinks, args._remove_social_link_ids);
40
+ // Update existing links (item_id present) or insert new links (no item_id).
41
+ if (links?.length) {
42
+ footer.socialLinks = footer.socialLinks ?? [];
43
+ for (const link of links) {
44
+ if (link.item_id) {
45
+ // Update existing link in place; reposition if move_before_item_id set.
46
+ const existing = footer.socialLinks.find((l) => l.id === link.item_id);
47
+ // Unknown id — skip rather than guess at a position.
48
+ if (!existing)
49
+ continue;
50
+ if (link.social_link_icon !== undefined)
51
+ existing.imageUrl = link.social_link_icon;
52
+ if (link.url !== undefined)
53
+ existing.url = normaliseSocialUrl(link.url);
54
+ repositionItemByAnchor(footer.socialLinks, existing, link.move_before_item_id);
55
+ }
56
+ else {
57
+ // New link — assign a stable id and position via move_before_item_id.
58
+ const newLink = {
59
+ id: generateItemId(),
60
+ imageUrl: link.social_link_icon || '',
61
+ url: normaliseSocialUrl(link.url || ''),
62
+ imageTitle: '',
63
+ width: 0,
64
+ height: 0,
65
+ imageLink: '',
66
+ };
67
+ repositionItemByAnchor(footer.socialLinks, newLink, link.move_before_item_id);
68
+ }
69
+ }
103
70
  }
104
- if (Object.keys(updates).length > 0)
105
- footer.copyrightStyle = applyDetachedStyleOverride(footer.copyrightStyle, updates, textStyleOptions);
106
71
  }
107
72
  };
108
73
  const applyViewportFooterChanges = (footer, overrides) => {
@@ -120,6 +85,11 @@ const applyViewportFooterChanges = (footer, overrides) => {
120
85
  color: overrides.icon_color,
121
86
  fill: overrides.icon_color,
122
87
  };
88
+ if (overrides.copyright_text_color !== undefined)
89
+ footer.copyrightStyle = {
90
+ ...footer.copyrightStyle,
91
+ color: overrides.copyright_text_color,
92
+ };
123
93
  if (overrides.is_logo_visible !== undefined)
124
94
  footer.isLogoVisible = overrides.is_logo_visible;
125
95
  if (overrides.logo_image_height !== undefined)
@@ -156,24 +126,11 @@ export class FooterBuilder extends BaseMetadataBuilder {
156
126
  }
157
127
  const args = this.request.payload ?? {};
158
128
  const textStyleOptions = model.styles?.textStyles?.textStyleOptions;
159
- // Global scalar/style fields (copyright text + font) apply to both
160
- // viewports. These are idempotent assignments, safe to run per-viewport.
129
+ // Global fields (copyright_text, social links) always apply to both viewports.
161
130
  if (model.pageFooterDesktop)
162
131
  applyGlobalFooterChanges(model.pageFooterDesktop, args, textStyleOptions);
163
132
  if (model.pageFooterMobile)
164
133
  applyGlobalFooterChanges(model.pageFooterMobile, args, textStyleOptions);
165
- // Social links are a single global list. Derive the new list ONCE, then
166
- // assign an INDEPENDENT copy to each viewport — never mutate a (possibly
167
- // shared) viewport array in place. See computeSocialLinks.
168
- if (hasSocialLinkMutation(args)) {
169
- const current = model.pageFooterDesktop?.socialLinks ??
170
- model.pageFooterMobile?.socialLinks;
171
- const updated = computeSocialLinks(current, args);
172
- if (model.pageFooterDesktop)
173
- model.pageFooterDesktop.socialLinks = updated.map((l) => ({ ...l }));
174
- if (model.pageFooterMobile)
175
- model.pageFooterMobile.socialLinks = updated.map((l) => ({ ...l }));
176
- }
177
134
  // Viewport-specific styling via explicit sub-objects.
178
135
  if (args.desktop && model.pageFooterDesktop)
179
136
  applyViewportFooterChanges(model.pageFooterDesktop, args.desktop);
@@ -0,0 +1,54 @@
1
+ import type { BrandPageModel } from '../../brand-page/models';
2
+ /**
3
+ * Sentinel anchor meaning "the end of the list", mirroring the section-level
4
+ * `move_before_content_id: "__end__"` convention used in base-section-builder.
5
+ */
6
+ export declare const END_ITEM_ANCHOR = "__end__";
7
+ /** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
8
+ export declare const generateItemId: () => string;
9
+ /**
10
+ * Walk an entire BrandPageModel and backfill a stable uuid `id` onto every
11
+ * nested array item that lacks one (gallery images, images/shapes/testimonial
12
+ * items, text items, social links, and footer social links).
13
+ *
14
+ * BP-5603: this must run BEFORE the model is minified for the AI, so the same
15
+ * id the AI is shown (and copies into `item_id`) is the one the executor later
16
+ * matches. The maker holds a single live model instance for both the minify
17
+ * and the apply step, so mutating it here makes the ids round-trip; they then
18
+ * persist on the next save. Idempotent — existing ids are preserved.
19
+ */
20
+ export declare const ensureBrandPageItemIds: (model: BrandPageModel) => void;
21
+ /**
22
+ * Backfill ids onto any items missing one. Per BP-5603 this runs in the
23
+ * metadata builder when a section is processed, so the persisted metadata
24
+ * returned to the client gains stable ids that subsequent AI tool calls can
25
+ * reference. Mutates in place.
26
+ */
27
+ export declare const ensureItemIds: <T extends {
28
+ id?: string | undefined;
29
+ }>(items: T[] | undefined) => void;
30
+ /**
31
+ * Remove items whose id appears in `ids`. Order-independent (no descending
32
+ * index sort needed) — the whole point of the id-based migration. Items
33
+ * without an id are never removed by id.
34
+ */
35
+ export declare const removeItemsByIds: <T extends {
36
+ id?: string | undefined;
37
+ }>(items: T[] | undefined, ids: string[] | undefined) => T[];
38
+ /**
39
+ * Position `item` within `items` relative to an anchor id — the item-level
40
+ * mirror of base-section-builder's `moveContent`:
41
+ *
42
+ * - `moveBeforeItemId === undefined` → leave an existing item where it is;
43
+ * append a new (not-yet-present) item to the end.
44
+ * - `moveBeforeItemId === "__end__"` → move/insert at the very end.
45
+ * - anchor id found → insert immediately before it.
46
+ * - anchor id not found → fall through to the end (same
47
+ * forgiving behaviour as `moveContent`).
48
+ *
49
+ * Mutates `items` in place. `item` may be an existing element of `items`
50
+ * (a move) or a brand-new object (an insert).
51
+ */
52
+ export declare const repositionItemByAnchor: <T extends {
53
+ id?: string | undefined;
54
+ }>(items: T[], item: T, moveBeforeItemId: string | undefined) => void;
@@ -0,0 +1,96 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ /**
3
+ * Sentinel anchor meaning "the end of the list", mirroring the section-level
4
+ * `move_before_content_id: "__end__"` convention used in base-section-builder.
5
+ */
6
+ export const END_ITEM_ANCHOR = '__end__';
7
+ /** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
8
+ export const generateItemId = () => uuidv4();
9
+ /**
10
+ * Walk an entire BrandPageModel and backfill a stable uuid `id` onto every
11
+ * nested array item that lacks one (gallery images, images/shapes/testimonial
12
+ * items, text items, social links, and footer social links).
13
+ *
14
+ * BP-5603: this must run BEFORE the model is minified for the AI, so the same
15
+ * id the AI is shown (and copies into `item_id`) is the one the executor later
16
+ * matches. The maker holds a single live model instance for both the minify
17
+ * and the apply step, so mutating it here makes the ids round-trip; they then
18
+ * persist on the next save. Idempotent — existing ids are preserved.
19
+ */
20
+ export const ensureBrandPageItemIds = (model) => {
21
+ const ensureContentItemIds = (content) => {
22
+ // Every array field that the minifier surfaces as a list of items.
23
+ for (const field of ['images', 'items', 'textItems', 'links']) {
24
+ const arr = content[field];
25
+ if (Array.isArray(arr))
26
+ ensureItemIds(arr);
27
+ }
28
+ };
29
+ for (const page of model.pages ?? []) {
30
+ for (const content of page.contents ?? []) {
31
+ ensureContentItemIds(content);
32
+ }
33
+ }
34
+ ensureItemIds(model.pageFooterDesktop?.socialLinks);
35
+ ensureItemIds(model.pageFooterMobile?.socialLinks);
36
+ };
37
+ /**
38
+ * Backfill ids onto any items missing one. Per BP-5603 this runs in the
39
+ * metadata builder when a section is processed, so the persisted metadata
40
+ * returned to the client gains stable ids that subsequent AI tool calls can
41
+ * reference. Mutates in place.
42
+ */
43
+ export const ensureItemIds = (items) => {
44
+ if (!items)
45
+ return;
46
+ for (const item of items) {
47
+ if (!item.id)
48
+ item.id = generateItemId();
49
+ }
50
+ };
51
+ /**
52
+ * Remove items whose id appears in `ids`. Order-independent (no descending
53
+ * index sort needed) — the whole point of the id-based migration. Items
54
+ * without an id are never removed by id.
55
+ */
56
+ export const removeItemsByIds = (items, ids) => {
57
+ if (!items?.length)
58
+ return items ?? [];
59
+ if (!ids?.length)
60
+ return items;
61
+ const toRemove = new Set(ids);
62
+ return items.filter((item) => !item.id || !toRemove.has(item.id));
63
+ };
64
+ /**
65
+ * Position `item` within `items` relative to an anchor id — the item-level
66
+ * mirror of base-section-builder's `moveContent`:
67
+ *
68
+ * - `moveBeforeItemId === undefined` → leave an existing item where it is;
69
+ * append a new (not-yet-present) item to the end.
70
+ * - `moveBeforeItemId === "__end__"` → move/insert at the very end.
71
+ * - anchor id found → insert immediately before it.
72
+ * - anchor id not found → fall through to the end (same
73
+ * forgiving behaviour as `moveContent`).
74
+ *
75
+ * Mutates `items` in place. `item` may be an existing element of `items`
76
+ * (a move) or a brand-new object (an insert).
77
+ */
78
+ export const repositionItemByAnchor = (items, item, moveBeforeItemId) => {
79
+ const currentIndex = items.indexOf(item);
80
+ if (moveBeforeItemId === undefined) {
81
+ if (currentIndex === -1)
82
+ items.push(item);
83
+ return;
84
+ }
85
+ if (currentIndex !== -1)
86
+ items.splice(currentIndex, 1);
87
+ const anchorIndex = moveBeforeItemId === END_ITEM_ANCHOR
88
+ ? -1
89
+ : items.findIndex((i) => i.id === moveBeforeItemId);
90
+ if (anchorIndex !== -1) {
91
+ items.splice(anchorIndex, 0, item);
92
+ }
93
+ else {
94
+ items.push(item);
95
+ }
96
+ };
@@ -1,14 +1,21 @@
1
1
  import { applyScalarFields, isValidUrl } from '../section-field-utils';
2
2
  import { BaseSectionBuilder } from './base-section-builder';
3
3
  import { validateImageGallery } from '../section-rules/image-gallery.rules';
4
+ import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
4
5
  const applyGalleryType = (content, galleryType) => {
5
6
  content.galleryStyles = {
6
7
  ...(content.galleryStyles || {}),
7
8
  galleryType: galleryType,
8
9
  };
9
10
  };
11
+ /**
12
+ * Full rebuild: discard existing images and map the payload directly.
13
+ * Used on create and when `_replace_items` is set. Each item gets a fresh id
14
+ * (or keeps the caller-supplied `item_id` when provided).
15
+ */
10
16
  const applyGalleryImages = (content, images) => {
11
17
  content.images = images.map((img) => ({
18
+ id: img.item_id || generateItemId(),
12
19
  imageUrl: isValidUrl(img.image_url) ? img.image_url : '',
13
20
  imageTitle: img.caption || '',
14
21
  width: 0,
@@ -17,59 +24,46 @@ const applyGalleryImages = (content, images) => {
17
24
  imageLink: '',
18
25
  }));
19
26
  };
20
- const mergeGalleryImages = (content, images, replaceAll) => {
21
- const itemsToMerge = images.filter((img) => img.insert_at === undefined);
22
- const updatedImages = itemsToMerge.map((img, index) => {
23
- const existing = content.images?.[index];
24
- const imageUrl = isValidUrl(img.image_url)
25
- ? img.image_url
26
- : (existing?.imageUrl ?? '');
27
- return {
28
- ...(existing || {}),
29
- imageUrl,
30
- imageTitle: img.caption ?? existing?.imageTitle ?? '',
31
- width: existing?.width ?? 0,
32
- height: existing?.height ?? 0,
33
- mediaType: existing?.mediaType ?? 'image',
34
- imageLink: existing?.imageLink ?? '',
35
- };
36
- });
37
- if (!replaceAll &&
38
- content.images &&
39
- content.images.length > itemsToMerge.length) {
40
- const extras = content.images.slice(itemsToMerge.length).map((img) => ({
41
- imageUrl: img.imageUrl ?? '',
42
- imageTitle: img.imageTitle ?? '',
43
- width: img.width ?? 0,
44
- height: img.height ?? 0,
45
- mediaType: img.mediaType ?? 'image',
46
- imageLink: img.imageLink ?? '',
47
- }));
48
- updatedImages.push(...extras);
49
- }
50
- content.images = updatedImages;
51
- };
52
- const insertGalleryImages = (content, images) => {
53
- const inserts = images.filter((img) => img.insert_at !== undefined);
54
- if (!inserts.length)
55
- return;
56
- const sorted = [...inserts].sort((a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0));
57
- for (const img of sorted) {
58
- if (!isValidUrl(img.image_url))
59
- continue;
60
- if (content.images?.some((existing) => existing.imageUrl === img.image_url))
61
- continue;
62
- content.images = content.images ?? [];
63
- const pos = Math.max(0, Math.min(img.insert_at ?? 0, content.images.length));
64
- content.images.splice(pos, 0, {
65
- imageUrl: img.image_url,
66
- imageTitle: img.caption ?? '',
67
- width: 0,
68
- height: 0,
69
- mediaType: 'image',
70
- imageLink: '',
71
- colorReplacements: [],
72
- });
27
+ /**
28
+ * Id-based merge (BP-5603), mirroring testimonial-section-builder one level
29
+ * deeper into `content.images`:
30
+ * - `item_id` matches existing item → update in place; reposition if
31
+ * `move_before_item_id` is set.
32
+ * - no `item_id` → add new item, positioned by
33
+ * `move_before_item_id`.
34
+ * - `removeIds` → delete by id (order-independent).
35
+ *
36
+ * Existing items are id-backfilled first so legacy galleries become
37
+ * referenceable as soon as the metadata builder touches them.
38
+ */
39
+ const mergeGalleryImages = (content, images, removeIds) => {
40
+ ensureItemIds(content.images);
41
+ content.images = removeItemsByIds(content.images, removeIds);
42
+ for (const img of images) {
43
+ if (img.item_id) {
44
+ const existing = content.images.find((i) => i.id === img.item_id);
45
+ // Unknown id — skip rather than guess at a position.
46
+ if (!existing)
47
+ continue;
48
+ if (img.image_url !== undefined) {
49
+ existing.imageUrl = isValidUrl(img.image_url) ? img.image_url : '';
50
+ }
51
+ if (img.caption !== undefined)
52
+ existing.imageTitle = img.caption;
53
+ repositionItemByAnchor(content.images, existing, img.move_before_item_id);
54
+ }
55
+ else {
56
+ const newItem = {
57
+ id: generateItemId(),
58
+ imageUrl: isValidUrl(img.image_url) ? img.image_url : '',
59
+ imageTitle: img.caption ?? '',
60
+ width: 0,
61
+ height: 0,
62
+ mediaType: 'image',
63
+ imageLink: '',
64
+ };
65
+ repositionItemByAnchor(content.images, newItem, img.move_before_item_id);
66
+ }
73
67
  }
74
68
  };
75
69
  export class ImageGalleryBuilder extends BaseSectionBuilder {
@@ -91,24 +85,19 @@ export class ImageGalleryBuilder extends BaseSectionBuilder {
91
85
  if (args.gallery_type) {
92
86
  applyGalleryType(content, args.gallery_type);
93
87
  }
94
- if (args.images && Array.isArray(args.images)) {
95
- if (this.mode === 'create') {
96
- applyGalleryImages(content, args.images);
97
- }
98
- else {
99
- mergeGalleryImages(content, args.images, !!args._replace_items);
100
- }
88
+ if (args._replace_items && args.images && Array.isArray(args.images)) {
89
+ // Full replacement: discard existing images and rebuild from the payload.
90
+ applyGalleryImages(content, args.images);
101
91
  }
102
- if (args._remove_item_indices?.length && content.images) {
103
- const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
104
- for (const idx of sorted) {
105
- if (idx >= 0 && idx < content.images.length) {
106
- content.images.splice(idx, 1);
107
- }
92
+ else if (this.mode === 'create') {
93
+ if (args.images && Array.isArray(args.images)) {
94
+ applyGalleryImages(content, args.images);
108
95
  }
109
96
  }
110
- if (args.images && Array.isArray(args.images) && this.mode === 'update') {
111
- insertGalleryImages(content, args.images);
97
+ else if ((args.images && Array.isArray(args.images)) ||
98
+ args._remove_item_ids?.length) {
99
+ // Update: id-based add / edit / move / remove in a single pass.
100
+ mergeGalleryImages(content, args.images ?? [], args._remove_item_ids);
112
101
  }
113
102
  return { request: this.request, model };
114
103
  }