@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
@@ -10,6 +10,12 @@ import type { BuilderResult } from '../../models';
10
10
  import { applyScalarFields, isValidUrl } from '../section-field-utils';
11
11
  import { BaseSectionBuilder } from './base-section-builder';
12
12
  import { validateImageGallery } from '../section-rules/image-gallery.rules';
13
+ import {
14
+ ensureItemIds,
15
+ generateItemId,
16
+ removeItemsByIds,
17
+ repositionItemByAnchor,
18
+ } from '../item-id-utils';
13
19
 
14
20
  const applyGalleryType = (
15
21
  content: ImageGalleryContent,
@@ -21,11 +27,17 @@ const applyGalleryType = (
21
27
  };
22
28
  };
23
29
 
30
+ /**
31
+ * Full rebuild: discard existing images and map the payload directly.
32
+ * Used on create and when `_replace_items` is set. Each item gets a fresh id
33
+ * (or keeps the caller-supplied `item_id` when provided).
34
+ */
24
35
  const applyGalleryImages = (
25
36
  content: ImageGalleryContent,
26
37
  images: ImageGalleryItem[],
27
38
  ): void => {
28
39
  content.images = images.map((img) => ({
40
+ id: img.item_id || generateItemId(),
29
41
  imageUrl: isValidUrl(img.image_url) ? img.image_url! : '',
30
42
  imageTitle: img.caption || '',
31
43
  width: 0,
@@ -35,84 +47,53 @@ const applyGalleryImages = (
35
47
  }));
36
48
  };
37
49
 
50
+ /**
51
+ * Id-based merge (BP-5603), mirroring testimonial-section-builder one level
52
+ * deeper into `content.images`:
53
+ * - `item_id` matches existing item → update in place; reposition if
54
+ * `move_before_item_id` is set.
55
+ * - no `item_id` → add new item, positioned by
56
+ * `move_before_item_id`.
57
+ * - `removeIds` → delete by id (order-independent).
58
+ *
59
+ * Existing items are id-backfilled first so legacy galleries become
60
+ * referenceable as soon as the metadata builder touches them.
61
+ */
38
62
  const mergeGalleryImages = (
39
63
  content: ImageGalleryContent,
40
64
  images: ImageGalleryItem[],
41
- replaceAll: boolean,
65
+ removeIds: string[] | undefined,
42
66
  ): void => {
43
- const itemsToMerge = images.filter((img) => img.insert_at === undefined);
44
-
45
- const updatedImages = itemsToMerge.map((img, index) => {
46
- const existing = content.images?.[index];
47
- const imageUrl = isValidUrl(img.image_url)
48
- ? img.image_url!
49
- : (existing?.imageUrl ?? '');
50
-
51
- return {
52
- ...(existing || {}),
53
- imageUrl,
54
- imageTitle: img.caption ?? existing?.imageTitle ?? '',
55
- width: existing?.width ?? 0,
56
- height: existing?.height ?? 0,
57
- mediaType: existing?.mediaType ?? 'image',
58
- imageLink: existing?.imageLink ?? '',
59
- };
60
- });
61
-
62
- if (
63
- !replaceAll &&
64
- content.images &&
65
- content.images.length > itemsToMerge.length
66
- ) {
67
- const extras = content.images.slice(itemsToMerge.length).map((img) => ({
68
- imageUrl: img.imageUrl ?? '',
69
- imageTitle: img.imageTitle ?? '',
70
- width: img.width ?? 0,
71
- height: img.height ?? 0,
72
- mediaType: img.mediaType ?? ('image' as const),
73
- imageLink: img.imageLink ?? '',
74
- }));
75
-
76
- updatedImages.push(...extras);
77
- }
78
-
79
- content.images = updatedImages;
80
- };
81
-
82
- const insertGalleryImages = (
83
- content: ImageGalleryContent,
84
- images: ImageGalleryItem[],
85
- ): void => {
86
- const inserts = images.filter((img) => img.insert_at !== undefined);
87
-
88
- if (!inserts.length) return;
89
-
90
- const sorted = [...inserts].sort(
91
- (a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0),
92
- );
67
+ ensureItemIds(content.images);
68
+ content.images = removeItemsByIds(content.images, removeIds);
93
69
 
94
- for (const img of sorted) {
95
- if (!isValidUrl(img.image_url)) continue;
70
+ for (const img of images) {
71
+ if (img.item_id) {
72
+ const existing = content.images.find((i) => i.id === img.item_id);
96
73
 
97
- if (content.images?.some((existing) => existing.imageUrl === img.image_url))
98
- continue;
74
+ // Unknown id skip rather than guess at a position.
75
+ if (!existing) continue;
99
76
 
100
- content.images = content.images ?? [];
101
-
102
- const pos = Math.max(
103
- 0,
104
- Math.min(img.insert_at ?? 0, content.images.length),
105
- );
77
+ if (img.image_url !== undefined) {
78
+ existing.imageUrl = isValidUrl(img.image_url) ? img.image_url! : '';
79
+ }
106
80
 
107
- content.images.splice(pos, 0, {
108
- imageUrl: img.image_url!,
109
- imageTitle: img.caption ?? '',
110
- width: 0,
111
- height: 0,
112
- mediaType: 'image',
113
- imageLink: '',
114
- colorReplacements: [],
115
- });
81
+ if (img.caption !== undefined) existing.imageTitle = img.caption;
82
+
83
+ repositionItemByAnchor(content.images, existing, img.move_before_item_id);
84
+ } else {
85
+ const newItem = {
86
+ id: generateItemId(),
87
+ imageUrl: isValidUrl(img.image_url) ? img.image_url! : '',
88
+ imageTitle: img.caption ?? '',
89
+ width: 0,
90
+ height: 0,
91
+ mediaType: 'image' as const,
92
+ imageLink: '',
93
+ };
94
+
95
+ repositionItemByAnchor(content.images, newItem, img.move_before_item_id);
96
+ }
116
97
  }
117
98
  };
118
99
 
@@ -144,26 +125,19 @@ export class ImageGalleryBuilder extends BaseSectionBuilder<ImageGalleryContent>
144
125
  applyGalleryType(content, args.gallery_type);
145
126
  }
146
127
 
147
- if (args.images && Array.isArray(args.images)) {
148
- if (this.mode === 'create') {
128
+ if (args._replace_items && args.images && Array.isArray(args.images)) {
129
+ // Full replacement: discard existing images and rebuild from the payload.
130
+ applyGalleryImages(content, args.images);
131
+ } else if (this.mode === 'create') {
132
+ if (args.images && Array.isArray(args.images)) {
149
133
  applyGalleryImages(content, args.images);
150
- } else {
151
- mergeGalleryImages(content, args.images, !!args._replace_items);
152
134
  }
153
- }
154
-
155
- if (args._remove_item_indices?.length && content.images) {
156
- const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
157
-
158
- for (const idx of sorted) {
159
- if (idx >= 0 && idx < content.images.length) {
160
- content.images.splice(idx, 1);
161
- }
162
- }
163
- }
164
-
165
- if (args.images && Array.isArray(args.images) && this.mode === 'update') {
166
- insertGalleryImages(content, args.images);
135
+ } else if (
136
+ (args.images && Array.isArray(args.images)) ||
137
+ args._remove_item_ids?.length
138
+ ) {
139
+ // Update: id-based add / edit / move / remove in a single pass.
140
+ mergeGalleryImages(content, args.images ?? [], args._remove_item_ids);
167
141
  }
168
142
 
169
143
  return { request: this.request, model };
@@ -18,12 +18,24 @@ import {
18
18
  } from '../section-field-utils';
19
19
  import { BaseSectionBuilder } from './base-section-builder';
20
20
  import { validateImagesSection } from '../section-rules/images-section.rules';
21
-
21
+ import {
22
+ ensureItemIds,
23
+ generateItemId,
24
+ removeItemsByIds,
25
+ repositionItemByAnchor,
26
+ } from '../item-id-utils';
27
+
28
+ /**
29
+ * Full replacement: discard existing items and rebuild from the payload.
30
+ * Assigns a stable `id` to each item; `itemsId` is set positionally here
31
+ * but will be re-indexed at the end of buildAsync.
32
+ */
22
33
  const applyImageItems = (
23
34
  content: ImagesSectionContent,
24
35
  items: ImagesSectionItem[],
25
36
  ): void => {
26
37
  content.items = items.map((item, index) => ({
38
+ id: item.item_id || generateItemId(),
27
39
  imageUrl: isValidUrl(item.image_url) ? item.image_url! : '',
28
40
  imageTitle: '',
29
41
  width: 0,
@@ -38,25 +50,33 @@ const applyImageItems = (
38
50
  }));
39
51
  };
40
52
 
53
+ /**
54
+ * Apply a batch of item operations by id (BP-5603), mirroring the
55
+ * section-level id-based contract one level deeper:
56
+ * - item with `item_id` matching an existing item → update in place (and
57
+ * reposition if `move_before_item_id` is set);
58
+ * - item without `item_id` → add a new item,
59
+ * positioned by `move_before_item_id`;
60
+ * - `_remove_item_ids` → delete by id.
61
+ *
62
+ * Existing items are id-backfilled first so legacy sections become
63
+ * referenceable the moment the metadata builder touches them.
64
+ * Order-independent: there are no positional indices to shift between ops.
65
+ */
41
66
  const mergeImageItems = (
42
67
  content: ImagesSectionContent,
43
68
  items: ImagesSectionItem[],
44
- replaceAll: boolean,
69
+ removeIds: string[] | undefined,
45
70
  ): void => {
46
- const hasIndexedItems = items.some((item) => item.item_index !== undefined);
71
+ ensureItemIds(content.items);
72
+ content.items = removeItemsByIds(content.items, removeIds);
47
73
 
48
- if (hasIndexedItems) {
49
- for (const item of items) {
50
- const targetIndex = item.item_index;
74
+ for (const item of items) {
75
+ if (item.item_id) {
76
+ const existing = content.items.find((i) => i.id === item.item_id);
51
77
 
52
- if (
53
- targetIndex === undefined ||
54
- targetIndex < 0 ||
55
- !content.items?.[targetIndex]
56
- )
57
- continue;
58
-
59
- const existing = content.items[targetIndex];
78
+ // Unknown id — skip rather than guess at a position.
79
+ if (!existing) continue;
60
80
 
61
81
  if (isValidUrl(item.image_url)) existing.imageUrl = item.image_url!;
62
82
 
@@ -66,47 +86,27 @@ const mergeImageItems = (
66
86
 
67
87
  if (item.button_text !== undefined)
68
88
  existing.buttonText = item.button_text || false;
69
- }
70
-
71
- return;
72
- }
73
-
74
- const itemsToMerge = items.filter((item) => item.insert_at === undefined);
75
-
76
- const updatedItems = itemsToMerge.map((item, index) => {
77
- const existing = content.items?.[index];
78
89
 
79
- return {
80
- ...(existing || {}),
81
- imageUrl: isValidUrl(item.image_url)
82
- ? item.image_url!
83
- : (existing?.imageUrl ?? ''),
84
- imageTitle: existing?.imageTitle ?? '',
85
- width: existing?.width ?? 0,
86
- height: existing?.height ?? 0,
87
- mediaType: existing?.mediaType ?? 'image',
88
- imageLink: existing?.imageLink ?? '',
89
- title: item.heading ?? existing?.title ?? '',
90
- paragraph: item.text ?? existing?.paragraph ?? '',
91
- buttonText: item.button_text ?? existing?.buttonText ?? '',
92
- itemsId: existing?.itemsId ?? index,
93
- colorReplacements: existing?.colorReplacements ?? [],
94
- };
95
- });
96
-
97
- if (
98
- !replaceAll &&
99
- content.items &&
100
- content.items.length > itemsToMerge.length
101
- ) {
102
- const remaining = content.items.slice(
103
- itemsToMerge.length,
104
- ) as typeof updatedItems;
105
-
106
- updatedItems.push(...remaining);
90
+ repositionItemByAnchor(content.items, existing, item.move_before_item_id);
91
+ } else {
92
+ const newItem = {
93
+ id: generateItemId(),
94
+ imageUrl: isValidUrl(item.image_url) ? item.image_url! : '',
95
+ imageTitle: '',
96
+ width: 0,
97
+ height: 0,
98
+ mediaType: 'image',
99
+ imageLink: '',
100
+ title: item.heading ?? '',
101
+ paragraph: item.text ?? '',
102
+ buttonText: item.button_text || false,
103
+ itemsId: 0, // re-indexed at the end of buildAsync
104
+ colorReplacements: [],
105
+ } as ImagesSectionContent['items'][number];
106
+
107
+ repositionItemByAnchor(content.items, newItem, item.move_before_item_id);
108
+ }
107
109
  }
108
-
109
- content.items = updatedItems;
110
110
  };
111
111
 
112
112
  export class ImagesSectionBuilder extends BaseSectionBuilder<ImagesSectionContent> {
@@ -192,86 +192,23 @@ export class ImagesSectionBuilder extends BaseSectionBuilder<ImagesSectionConten
192
192
  };
193
193
  }
194
194
 
195
- if (args.items && Array.isArray(args.items)) {
196
- if (this.mode === 'create') {
195
+ if (args._replace_items && args.items && Array.isArray(args.items)) {
196
+ // Full replacement: discard existing items and rebuild from the payload.
197
+ applyImageItems(content, args.items);
198
+ } else if (this.mode === 'create') {
199
+ if (args.items && Array.isArray(args.items)) {
197
200
  applyImageItems(content, args.items);
198
- } else {
199
- mergeImageItems(content, args.items, !!args._replace_items);
200
- }
201
- }
202
-
203
- // Phase 2: Item operations (remove, insert, reorder)
204
- if (args._remove_item_indices?.length && content.items) {
205
- const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
206
-
207
- for (const idx of sorted) {
208
- if (idx >= 0 && idx < content.items.length) {
209
- content.items.splice(idx, 1);
210
- }
211
- }
212
- }
213
-
214
- if (args.items && Array.isArray(args.items)) {
215
- const insertItems = args.items.filter(
216
- (item) => item.insert_at !== undefined && item.item_index === undefined,
217
- );
218
- // Process inserts in reverse order of insert_at to preserve indices
219
- const sortedInserts = [...insertItems].sort(
220
- (a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0),
221
- );
222
-
223
- for (const item of sortedInserts) {
224
- if (!isValidUrl(item.image_url)) continue;
225
-
226
- // Skip if this image_url already exists — defensive against duplicate
227
- // tool call application
228
- if (
229
- content.items?.some(
230
- (existing: any) => existing.imageUrl === item.image_url,
231
- )
232
- ) {
233
- continue;
234
- }
235
-
236
- const pos = Math.max(
237
- 0,
238
- Math.min(item.insert_at ?? 0, content.items?.length ?? 0),
239
- );
240
- const newItem = {
241
- imageUrl: item.image_url,
242
- imageTitle: '',
243
- width: 0,
244
- height: 0,
245
- mediaType: 'image',
246
- imageLink: '',
247
- title: item.heading ?? '',
248
- paragraph: item.text ?? '',
249
- buttonText: item.button_text || '',
250
- itemsId: pos,
251
- colorReplacements: [],
252
- };
253
-
254
- content.items = content.items ?? [];
255
- content.items.splice(pos, 0, newItem as any);
256
- }
257
- }
258
-
259
- if (args._reorder_items?.length && content.items) {
260
- const newOrder = args._reorder_items;
261
- const unique = new Set(newOrder);
262
-
263
- if (unique.size === newOrder.length) {
264
- const reordered = newOrder
265
- .filter((idx) => idx >= 0 && idx < content.items!.length)
266
- .map((idx) => content.items![idx]);
267
-
268
- if (reordered.length === content.items.length) {
269
- content.items = reordered;
270
- }
271
201
  }
202
+ } else if (
203
+ (args.items && Array.isArray(args.items)) ||
204
+ args._remove_item_ids?.length
205
+ ) {
206
+ // Update: id-based add / edit / move / remove in a single pass.
207
+ mergeImageItems(content, args.items ?? [], args._remove_item_ids);
272
208
  }
273
209
 
274
- // Re-index itemsId after any item operations
210
+ // Re-index itemsId after all id-based item operations (render concern —
211
+ // separate from the stable `id` used for targeting).
275
212
  if (content.items) {
276
213
  content.items.forEach((item, i) => {
277
214
  item.itemsId = i;