@designcrowd/library.brand-page 6.0.5 → 6.0.6-ast-bugs

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 (395) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DhzvKlTS.js → CreatedOnBrandCrowd-de-de-SHCspMwS.js} +3 -3
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DKH4lmNV.js → CreatedOnBrandCrowd-en-us-C6lITAAT.js} +3 -3
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-RloPCLuV.js → CreatedOnBrandCrowd-es-es-Uh69c4vZ.js} +3 -3
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Cu9e2H0K.js → CreatedOnBrandCrowd-fr-ca-Bb0rp7BV.js} +3 -3
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Cu9e2H0K.js → CreatedOnBrandCrowd-fr-fr-Bb0rp7BV.js} +3 -3
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-CiCnjxBZ.js → CreatedOnBrandCrowd-pt-br-DsrQHcjs.js} +3 -3
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-CiCnjxBZ.js → CreatedOnBrandCrowd-pt-pt-DsrQHcjs.js} +3 -3
  8. package/lib/src/{CreatedOnDcom-de-de-CwlnedFV.js → CreatedOnDcom-de-de-BshZYzSp.js} +3 -3
  9. package/lib/src/{CreatedOnDcom-en-us-DFHex61v.js → CreatedOnDcom-en-us-CLu8mKUW.js} +3 -3
  10. package/lib/src/{CreatedOnDcom-es-es-BTxH6I4V.js → CreatedOnDcom-es-es-BZYhkONd.js} +3 -3
  11. package/lib/src/{CreatedOnDcom-fr-ca-BVw0KYxu.js → CreatedOnDcom-fr-ca-CIaBEp_9.js} +3 -3
  12. package/lib/src/{CreatedOnDcom-fr-fr-DaqNz1Er.js → CreatedOnDcom-fr-fr-dyF7hioJ.js} +3 -3
  13. package/lib/src/{CreatedOnDcom-pt-br-B4KsMI8W.js → CreatedOnDcom-pt-br-CUHjk2du.js} +3 -3
  14. package/lib/src/{CreatedOnDcom-pt-pt-CWoHEtOZ.js → CreatedOnDcom-pt-pt-CWDvQidv.js} +3 -3
  15. package/lib/src/brand-page/clients/brand-page.client.d.ts +9 -9
  16. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.d.ts +103 -0
  17. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.js +178 -0
  18. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +1 -2
  19. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.d.ts +4 -2
  20. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.js +1 -0
  21. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +4 -2
  22. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +11 -5
  23. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -1
  24. package/lib/src/brand-page/components/page/PageComponent.mixin.d.ts +1 -1
  25. package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +3 -3
  26. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +13 -13
  27. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +13 -13
  28. package/lib/src/brand-page/constants/sections/footer-display.constants.js +1 -1
  29. package/lib/src/brand-page/models/index.d.ts +2 -13
  30. package/lib/src/brand-page/models/index.js +3 -0
  31. package/lib/src/brand-page/models/payment.model.d.ts +1 -1
  32. package/lib/src/brand-page/utils/personalisation.util.js +72 -14
  33. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +21 -19
  34. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +1 -0
  35. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +16 -10
  36. package/lib/src/brand-page-maker/components/admin-background-settings/ShapePositionSlider.mixin.d.ts +1 -1
  37. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +3 -3
  38. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +181 -170
  39. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +3 -0
  40. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +1 -0
  41. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +12 -12
  42. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.js +2 -2
  43. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.js +0 -7
  44. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +148 -149
  45. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +21 -21
  46. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.js +1 -1
  47. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.d.ts +4 -2
  48. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.js +1 -0
  49. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.d.ts +4 -2
  50. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.js +1 -0
  51. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.d.ts +5 -2
  52. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.js +1 -0
  53. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.d.ts +4 -2
  54. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.js +1 -0
  55. package/lib/src/brand-page-maker/components/device/Device.mixin.d.ts +4 -2
  56. package/lib/src/brand-page-maker/components/device/Device.mixin.js +1 -0
  57. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +4 -2
  58. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +1 -0
  59. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +3 -3
  60. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +11 -11
  61. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +27 -25
  62. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +1 -0
  63. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +27 -27
  64. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.js +1 -1
  65. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +17 -12
  66. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +12 -12
  67. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +30 -32
  68. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +16 -5
  69. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +11 -11
  70. package/lib/src/brand-page-maker/composables/ai-chat/types.d.ts +3 -0
  71. package/lib/src/brand-page-maker/composables/ai-chat/ui-actions.d.ts +29 -0
  72. package/lib/src/brand-page-maker/composables/ai-chat/ui-actions.js +32 -0
  73. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +204 -177
  74. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  75. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +6 -6
  76. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +3 -2
  77. package/lib/src/brand-page-maker/composables/useEventTracker.js +1 -0
  78. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +6 -6
  79. package/lib/src/brand-page-maker/constants/config-settings-constant.js +3 -3
  80. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.d.ts +1 -1
  81. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.js +1 -1
  82. package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -1
  83. package/lib/src/brand-page-maker/models/navigation-style-configs.js +1 -1
  84. package/lib/src/brand-page-maker/routing/brand-page-maker-router.d.ts +1 -2
  85. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +366 -378
  86. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +5 -4
  87. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +8 -5
  88. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +3 -1
  89. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +7 -3
  90. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +15 -15
  91. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +6 -0
  92. package/lib/src/brand-page-maker/stores/ui/ui-store.js +8 -0
  93. package/lib/src/brand-page-maker/utils/content-settings.util.js +1 -1
  94. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +1 -1
  95. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +4 -4
  96. package/lib/src/clients/ai-assistant-client.d.ts +7 -0
  97. package/lib/src/clients/brand-page-client.d.ts +16 -15
  98. package/lib/src/clients/design-template-client.d.ts +3 -0
  99. package/lib/src/clients/media-client.d.ts +2 -2
  100. package/lib/src/clients/models.d.ts +2 -0
  101. package/lib/src/composables/useSnapshot.js +18 -18
  102. package/lib/src/css/library.brand-page-brandCrowd.min.css +371 -344
  103. package/lib/src/css/library.brand-page-brandPage.min.css +649 -344
  104. package/lib/src/css/library.brand-page-designCom.min.css +371 -344
  105. package/lib/src/css/library.brand-page-preview.min.css +627 -344
  106. package/lib/src/index.d.ts +4 -0
  107. package/lib/src/index.mjs +107 -104
  108. package/lib/src/{lib-BPI8E2Ui.js → lib-COw-Rz05.js} +37005 -33761
  109. package/lib/src/lib.js +10 -0
  110. package/lib/src/metadata-builder/builders/footer-builder.js +105 -62
  111. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +68 -57
  112. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +93 -58
  113. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +99 -66
  114. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +17 -57
  115. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +85 -51
  116. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +74 -49
  117. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +7 -0
  118. package/lib/src/metadata-builder/builders/section-field-utils.js +1 -1
  119. package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
  120. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +7 -16
  121. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +48 -66
  122. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.d.ts +1 -1
  123. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.js +8 -8
  124. package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +13 -13
  125. package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -3
  126. package/lib/src/shared/color-picker/components/ColorPicker.mixin.d.ts +4 -2
  127. package/lib/src/shared/color-picker/components/ColorPicker.mixin.js +2 -2
  128. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.d.ts +4 -2
  129. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.js +1 -0
  130. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.d.ts +5 -2
  131. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.js +1 -0
  132. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +0 -1
  133. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +131 -129
  134. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +2 -1
  135. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +111 -110
  136. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +84 -81
  137. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +5 -0
  138. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +117 -109
  139. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +1 -14
  140. package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +0 -1
  141. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +72 -70
  142. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +4 -3
  143. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.d.ts +4 -4
  144. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.d.ts +3 -1
  145. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.js +1 -0
  146. package/lib/src/shared/content-settings/components/images-field/ImagesField.mixin.d.ts +2 -2
  147. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +4 -3
  148. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -1
  149. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +40 -40
  150. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigOptionField.mixin.d.ts +5 -6
  151. package/lib/src/shared/content-settings/components/shape-field/ShapeField.mixin.d.ts +0 -1
  152. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +2 -2
  153. package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +0 -1
  154. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +1 -2
  155. package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +0 -1
  156. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
  157. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -1
  158. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +28 -28
  159. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +0 -1
  160. package/lib/src/shared/content-settings/components/toggle-field/ToggleField.mixin.d.ts +2 -2
  161. package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +0 -1
  162. package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +0 -1
  163. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +39 -39
  164. package/lib/src/shared/content-settings/utils.js +0 -1
  165. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.d.ts +6 -4
  166. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.js +1 -0
  167. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.d.ts +4 -2
  168. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.js +1 -0
  169. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +29 -21
  170. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +1 -1
  171. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +50 -51
  172. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.d.ts +6 -4
  173. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.js +1 -0
  174. package/lib/src/shared/logo-settings/store/editable-logo-store.js +1 -1
  175. package/lib/src/shared/logo-settings/store/logo-settings-store.d.ts +1 -1
  176. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +13 -5
  177. package/lib/src/shared/logo-versions/LogoVersions.mixin.js +1 -0
  178. package/lib/src/shared/models.d.ts +2 -0
  179. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +14 -6
  180. package/lib/src/shared/my-designs/MyDesigns.mixin.js +1 -0
  181. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +14 -5
  182. package/lib/src/shared/my-uploads/MyMedia.mixin.js +1 -0
  183. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +14 -5
  184. package/lib/src/shared/my-uploads/MyUploads.mixin.js +1 -0
  185. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.d.ts +5 -3
  186. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +1 -0
  187. package/lib/src/shared/navigation-style-settings/store/index.d.ts +2 -2
  188. package/lib/src/shared/page-navigation/store/page-navigation-store.d.ts +2 -2
  189. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +27 -28
  190. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.js +0 -2
  191. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +188 -179
  192. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +181 -177
  193. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +1 -1
  194. package/lib/src/shared/page-settings/store/page-settings-store.d.ts +9 -9
  195. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +39 -39
  196. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.js +0 -1
  197. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +18 -18
  198. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +6 -6
  199. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +66 -60
  200. package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -1
  201. package/lib/src/shared/style-settings/store/style-settings-store.js +1 -1
  202. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +20 -450
  203. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  204. package/lib/src/shared/template-settings/models.d.ts +1 -0
  205. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +4 -0
  206. package/lib/src/shared/template-settings/store/template-settings-store.js +79 -11
  207. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +9 -4
  208. package/lib/src/utils/build-asset-manifest.d.ts +4 -0
  209. package/lib/src/utils/build-asset-manifest.js +8 -0
  210. package/lib/src/utils/minify-brand-page-metadata.d.ts +0 -2
  211. package/lib/src/utils/minify-brand-page-metadata.js +2 -17
  212. package/package.json +60 -56
  213. package/src/brand-page/components/about-section/AboutSection.vue.test.ts +7 -5
  214. package/src/brand-page/components/banner-section/BannerSection.mixin.ts +210 -0
  215. package/src/brand-page/components/banner-section/BannerSection.vue +5 -1
  216. package/src/brand-page/components/brand-page-footer/BrandPageFooter.vue +1 -1
  217. package/src/brand-page/components/image/Image.mixin.ts +1 -1
  218. package/src/brand-page/components/image/Image.test.ts +1 -1
  219. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +1 -2
  220. package/src/brand-page/components/images-section/ImagesSection.vue +0 -1
  221. package/src/brand-page/components/logo/LogoRender.vue +188 -188
  222. package/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.ts +1 -0
  223. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +25 -8
  224. package/src/brand-page/components/page-footer/PageFooter.vue +1 -0
  225. package/src/brand-page/components/page-header/HeaderLayout.vue +12 -6
  226. package/src/brand-page/components/page-header/PageHeader.vue +1 -0
  227. package/src/brand-page/components/shapes-section/ShapesSection.vue +1 -1
  228. package/src/brand-page/components/shop/CartModal.vue +1 -3
  229. package/src/brand-page/components/shop/FeaturedDisplay.vue +2 -2
  230. package/src/brand-page/components/shop/PaymentModal.vue +1 -5
  231. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  232. package/src/brand-page/components/shop/Shop.vue +1 -5
  233. package/src/brand-page/components/shop/TextDisplay.vue +1 -1
  234. package/src/brand-page/components/shop/ThumbnailDisplay.vue +2 -2
  235. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +3 -3
  236. package/src/brand-page/components/text-wrapper/TextWrapper.vue +3 -1
  237. package/src/brand-page/constants/sections/footer-display.constants.ts +1 -1
  238. package/src/brand-page/models/index.ts +4 -12
  239. package/src/brand-page/models/payment.model.ts +2 -1
  240. package/src/brand-page/models/shop.model.ts +0 -2
  241. package/src/brand-page/models/user-personalisation.model.ts +1 -2
  242. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  243. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  244. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  245. package/src/brand-page/utils/migration/migration-01_1.ts +1 -1
  246. package/src/brand-page/utils/migration/migration-02.ts +0 -1
  247. package/src/brand-page/utils/migration/migration-03.ts +0 -1
  248. package/src/brand-page/utils/migration/migration-04.ts +0 -1
  249. package/src/brand-page/utils/migration/migration-05.ts +1 -5
  250. package/src/brand-page/utils/migration/migration-05_2.ts +1 -1
  251. package/src/brand-page/utils/migration/migration-08.test.ts +1 -1
  252. package/src/brand-page/utils/personalisation.util.test.ts +35 -0
  253. package/src/brand-page/utils/personalisation.util.ts +119 -23
  254. package/src/brand-page/view-models.ts +38 -56
  255. package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +6 -6
  256. package/src/brand-page-maker/assessors/color-replacement-icon-visibility.assessor.ts +2 -2
  257. package/src/brand-page-maker/assessors/color-replacement-profile-visibility.assessor.ts +2 -2
  258. package/src/brand-page-maker/assessors/color-replacement-visibility.assessor.ts +2 -2
  259. package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +14 -14
  260. package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +1 -0
  261. package/src/brand-page-maker/components/ai-text-edit/AiActionButtons.vue +27 -12
  262. package/src/brand-page-maker/components/ai-text-edit/AiChatbox.vue +3 -2
  263. package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +8 -7
  264. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +21 -1
  265. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +5 -1
  266. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +1 -0
  267. package/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.ts +2 -5
  268. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -5
  269. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.ts +0 -8
  270. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-site-template.examples.ts +0 -2
  271. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +1 -0
  272. package/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.ts +1 -1
  273. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +1 -2
  274. package/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.ts +1 -0
  275. package/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.ts +1 -0
  276. package/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.ts +1 -0
  277. package/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.ts +1 -0
  278. package/src/brand-page-maker/components/device/Device.mixin.ts +1 -0
  279. package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +1 -0
  280. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +3 -1
  281. package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +1 -4
  282. package/src/brand-page-maker/components/seo-settings/DeleteDomainModal.vue +1 -1
  283. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +1 -0
  284. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +1 -1
  285. package/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.ts +0 -1
  286. package/src/brand-page-maker/components/seo-settings/UrlSettings.vue +0 -1
  287. package/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.vue +1 -5
  288. package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -1
  289. package/src/brand-page-maker/components/shop/ReplaceImageSettingsForShop.vue +1 -1
  290. package/src/brand-page-maker/components/social-share/SocialShare.vue +1 -1
  291. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -8
  292. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +5 -10
  293. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +12 -0
  294. package/src/brand-page-maker/components/video-play/VideoPlayButton.vue +1 -1
  295. package/src/brand-page-maker/composables/ai-chat/types.ts +6 -0
  296. package/src/brand-page-maker/composables/ai-chat/ui-actions.test.ts +80 -0
  297. package/src/brand-page-maker/composables/ai-chat/ui-actions.ts +58 -0
  298. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +308 -262
  299. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
  300. package/src/brand-page-maker/composables/useEventTracker.ts +1 -0
  301. package/src/brand-page-maker/constants/config-settings-constant.ts +5 -5
  302. package/src/brand-page-maker/convertors/text-image-display-style.convertor.ts +1 -1
  303. package/src/brand-page-maker/models/button-styles-config.ts +4 -2
  304. package/src/brand-page-maker/models/content-settings-configs.ts +4 -2
  305. package/src/brand-page-maker/models/navigation-style-configs.ts +5 -6
  306. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +0 -1
  307. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +8 -5
  308. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +1 -3
  309. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +12 -4
  310. package/src/brand-page-maker/stores/ui/ui-store.ts +16 -0
  311. package/src/brand-page-maker/utils/content-settings.util.ts +1 -1
  312. package/src/brand-page-maker/utils/rich-text-editor.util.ts +4 -4
  313. package/src/clients/ai-assistant-client.ts +7 -0
  314. package/src/clients/design-template-client.ts +3 -0
  315. package/src/clients/models.ts +2 -0
  316. package/src/composables/useSnapshot.ts +19 -22
  317. package/src/lib.ts +12 -0
  318. package/src/metadata-builder/builders/footer-builder.test.ts +130 -229
  319. package/src/metadata-builder/builders/footer-builder.ts +155 -90
  320. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +88 -62
  321. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +129 -66
  322. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +160 -105
  323. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +20 -65
  324. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +146 -83
  325. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +122 -70
  326. package/src/metadata-builder/builders/section-field-utils.ts +1 -1
  327. package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
  328. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +7 -16
  329. package/src/metadata-builder/parsers/section-tool-arguments.ts +48 -66
  330. package/src/plugins/google-maps-plugin/google-maps-plugin.ts +8 -8
  331. package/src/shared/background-settings/components/BackgroundSettings.vue +1 -1
  332. package/src/shared/background-settings/components/background-color/BackgroundColorSettings.vue +1 -1
  333. package/src/shared/color-picker/components/ColorPicker.mixin.ts +2 -7
  334. package/src/shared/color-picker/components/ColorPickerSwatch.mixin.ts +1 -0
  335. package/src/shared/common/NumberInput.vue +1 -0
  336. package/src/shared/common/SideBarSettingsHeader.vue +2 -2
  337. package/src/shared/confirm-modal/ConfirmModal.mixin.ts +1 -0
  338. package/src/shared/content-settings/components/booking-url-field/BookingUrlField.vue +1 -0
  339. package/src/shared/content-settings/components/button-configuration-field/ButtonConfigurationField.vue +1 -0
  340. package/src/shared/content-settings/components/color-field/ColorField.vue +3 -10
  341. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -1
  342. package/src/shared/content-settings/components/content-settings/ContentSettingsLockedButton.vue +1 -0
  343. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +5 -0
  344. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +1 -14
  345. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +4 -6
  346. package/src/shared/content-settings/components/icon-library/IconLibrary.mixin.ts +1 -0
  347. package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -1
  348. package/src/shared/content-settings/components/logo-selection-field/LogoSelectionField.vue +1 -1
  349. package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -1
  350. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +1 -1
  351. package/src/shared/content-settings/components/personalisation-role-field/PersonalisationRoleField.vue +4 -4
  352. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +2 -8
  353. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -1
  354. package/src/shared/content-settings/models.ts +3 -2
  355. package/src/shared/content-settings/utils.ts +0 -1
  356. package/src/shared/dropzone-image-uploader/components/DropzoneImageUploader.vue +1 -0
  357. package/src/shared/ecommerce-settings/store/cart-store.test.ts +1 -1
  358. package/src/shared/font-family-selector/FontFamilySelector.mixin.ts +1 -0
  359. package/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.ts +1 -0
  360. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +1 -1
  361. package/src/shared/logo-settings/components/LogoSettings.mixin.ts +0 -1
  362. package/src/shared/logo-settings/components/LogoSettingsHeader.mixin.ts +1 -0
  363. package/src/shared/logo-settings/components/LogoStyleSettingsWithState.vue +2 -2
  364. package/src/shared/logo-settings/components/LogoTemplateSearch.vue +1 -1
  365. package/src/shared/logo-settings/store/editable-logo-store.ts +1 -1
  366. package/src/shared/logo-settings/store/logo-settings-store.test.ts +4 -4
  367. package/src/shared/logo-versions/LogoVersions.mixin.ts +1 -0
  368. package/src/shared/models.ts +6 -0
  369. package/src/shared/my-designs/MyDesigns.mixin.ts +1 -0
  370. package/src/shared/my-uploads/MyMedia.mixin.ts +1 -0
  371. package/src/shared/my-uploads/MyMediaSelectionItem.vue +2 -1
  372. package/src/shared/my-uploads/MyUploads.mixin.ts +1 -0
  373. package/src/shared/my-uploads/models.ts +1 -2
  374. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +1 -0
  375. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -1
  376. package/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.ts +0 -3
  377. package/src/shared/page-settings/components/page-settings/NestedDraggable.vue +1 -1
  378. package/src/shared/page-settings/components/page-settings/PageSettings.vue +1 -2
  379. package/src/shared/page-settings/components/page-settings-section-styles/HeaderDisplayStyle.vue +1 -1
  380. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +1 -1
  381. package/src/shared/page-settings/store/page-settings-store.test.ts +4 -8
  382. package/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.ts +0 -1
  383. package/src/shared/shape-library/ShapeLibrary.vue +2 -2
  384. package/src/shared/style-settings/store/style-settings-store.ts +1 -1
  385. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  386. package/src/shared/template-settings/models.ts +1 -0
  387. package/src/shared/template-settings/store/template-settings-store.ts +105 -18
  388. package/src/shared/unsplash-library/UnsplashLibrary.vue +2 -6
  389. package/src/shared/video-library/VideoLibrary.vue +1 -1
  390. package/src/utils/build-asset-manifest.ts +12 -0
  391. package/src/utils/minify-brand-page-metadata.ts +7 -27
  392. package/lib/src/metadata-builder/builders/item-id-utils.d.ts +0 -54
  393. package/lib/src/metadata-builder/builders/item-id-utils.js +0 -96
  394. package/src/metadata-builder/builders/item-id-utils.test.ts +0 -184
  395. package/src/metadata-builder/builders/item-id-utils.ts +0 -117
@@ -4,7 +4,6 @@ import { applyScalarFields, applyStyleFields, resolveGlobalPresetIntoStyle, } fr
4
4
  import { applyColorThemeToReplacements, resolveShapeColorReplacementsAsync, } from '../shape-color-utils';
5
5
  import { BaseSectionBuilder } from './base-section-builder';
6
6
  import { validateShapesSection } from '../section-rules/shapes-section.rules';
7
- import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
8
7
  const resolveItemColorsAsync = async (item, existing, prevImageUrl) => {
9
8
  let colors = existing ?? [];
10
9
  const newUrl = item.shape_url ?? item.icon_image_url;
@@ -16,13 +15,8 @@ const resolveItemColorsAsync = async (item, existing, prevImageUrl) => {
16
15
  }
17
16
  return colors;
18
17
  };
19
- /**
20
- * Full replacement: discard existing items and rebuild from the payload.
21
- * Used for create mode and _replace_items: true.
22
- */
23
18
  const applyShapeItemsAsync = async (content, items) => {
24
- content.items = await Promise.all(items.map(async (item) => ({
25
- id: item.item_id || generateItemId(),
19
+ content.items = await Promise.all(items.map(async (item, index) => ({
26
20
  imageUrl: item.shape_url || item.icon_image_url || '',
27
21
  imageTitle: '',
28
22
  width: 0,
@@ -31,36 +25,20 @@ const applyShapeItemsAsync = async (content, items) => {
31
25
  imageLink: '',
32
26
  title: item.heading || '',
33
27
  paragraph: item.text || '',
34
- itemsId: 0,
28
+ itemsId: index,
35
29
  colorReplacements: await resolveItemColorsAsync(item, [], undefined),
36
30
  })));
37
- // Re-index itemsId after build
38
- content.items.forEach((item, i) => {
39
- item.itemsId = i;
40
- });
41
31
  };
42
- /**
43
- * Apply a batch of item operations by id (BP-5603), mirroring the section-level
44
- * id-based contract one level deeper:
45
- * - item with `item_id` matching an existing item → update in place (and
46
- * reposition if `move_before_item_id` is set);
47
- * - item without `item_id` → add a new item,
48
- * positioned by `move_before_item_id`;
49
- * - `_remove_item_ids` → delete by id.
50
- *
51
- * Existing items are id-backfilled first so legacy sections become referenceable
52
- * the moment the metadata builder touches them. Order-independent: there are no
53
- * positional indices to shift between operations.
54
- */
55
- const mergeShapeItemsAsync = async (content, items, removeIds) => {
56
- ensureItemIds(content.items);
57
- content.items = removeItemsByIds(content.items, removeIds);
58
- for (const item of items) {
59
- if (item.item_id) {
60
- const existing = content.items.find((i) => i.id === item.item_id);
61
- // Unknown id — skip rather than guess at a position.
62
- if (!existing)
63
- continue;
32
+ const mergeShapeItemsAsync = async (content, items, replaceAll) => {
33
+ const hasIndexedItems = items.some((item) => item.item_index !== undefined);
34
+ if (hasIndexedItems) {
35
+ await Promise.all(items.map(async (item) => {
36
+ const targetIndex = item.item_index;
37
+ if (targetIndex === undefined ||
38
+ targetIndex < 0 ||
39
+ !content.items?.[targetIndex])
40
+ return;
41
+ const existing = content.items[targetIndex];
64
42
  const prevImageUrl = existing.imageUrl;
65
43
  if (item.shape_url !== undefined || item.icon_image_url !== undefined) {
66
44
  existing.imageUrl =
@@ -73,29 +51,34 @@ const mergeShapeItemsAsync = async (content, items, removeIds) => {
73
51
  if (item.shape_url !== undefined || item.color_theme !== undefined) {
74
52
  existing.colorReplacements = await resolveItemColorsAsync(item, existing.colorReplacements, prevImageUrl);
75
53
  }
76
- repositionItemByAnchor(content.items, existing, item.move_before_item_id);
77
- }
78
- else {
79
- const newItem = {
80
- id: generateItemId(),
81
- imageUrl: item.shape_url ?? item.icon_image_url ?? '',
82
- imageTitle: '',
83
- width: 0,
84
- height: 0,
85
- mediaType: 'shape',
86
- imageLink: '',
87
- title: item.heading ?? '',
88
- paragraph: item.text ?? '',
89
- itemsId: 0,
90
- colorReplacements: await resolveItemColorsAsync(item, [], undefined),
91
- };
92
- repositionItemByAnchor(content.items, newItem, item.move_before_item_id);
93
- }
54
+ }));
55
+ return;
56
+ }
57
+ const itemsToMerge = items.filter((item) => item.insert_at === undefined);
58
+ const updatedItems = await Promise.all(itemsToMerge.map(async (item, index) => {
59
+ const existing = content.items?.[index];
60
+ const imageUrl = item.shape_url ?? item.icon_image_url ?? existing?.imageUrl ?? '';
61
+ return {
62
+ ...(existing || {}),
63
+ imageUrl,
64
+ imageTitle: existing?.imageTitle ?? '',
65
+ width: existing?.width ?? 0,
66
+ height: existing?.height ?? 0,
67
+ mediaType: existing?.mediaType ?? 'shape',
68
+ imageLink: existing?.imageLink ?? '',
69
+ title: item.heading ?? existing?.title ?? '',
70
+ paragraph: item.text ?? existing?.paragraph ?? '',
71
+ itemsId: existing?.itemsId ?? index,
72
+ colorReplacements: await resolveItemColorsAsync(item, existing?.colorReplacements, existing?.imageUrl),
73
+ };
74
+ }));
75
+ if (!replaceAll &&
76
+ content.items &&
77
+ content.items.length > itemsToMerge.length) {
78
+ const remaining = content.items.slice(itemsToMerge.length);
79
+ updatedItems.push(...remaining);
94
80
  }
95
- // Re-index itemsId after all mutations
96
- content.items.forEach((item, i) => {
97
- item.itemsId = i;
98
- });
81
+ content.items = updatedItems;
99
82
  };
100
83
  export class ShapesSectionBuilder extends BaseSectionBuilder {
101
84
  get sectionValidate() {
@@ -153,19 +136,69 @@ export class ShapesSectionBuilder extends BaseSectionBuilder {
153
136
  ])),
154
137
  };
155
138
  }
156
- if (args._replace_items && args.items && Array.isArray(args.items)) {
157
- // Full replacement: discard existing items and rebuild from the payload.
158
- await applyShapeItemsAsync(content, args.items);
159
- }
160
- else if (this.mode === 'create') {
161
- if (args.items && Array.isArray(args.items)) {
139
+ if (args.items && Array.isArray(args.items)) {
140
+ if (this.mode === 'create') {
162
141
  await applyShapeItemsAsync(content, args.items);
163
142
  }
143
+ else {
144
+ await mergeShapeItemsAsync(content, args.items, !!args._replace_items);
145
+ }
146
+ }
147
+ // Phase 2: Item operations (remove, insert, reorder)
148
+ if (args._remove_item_indices?.length && content.items) {
149
+ const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
150
+ for (const idx of sorted) {
151
+ if (idx >= 0 && idx < content.items.length) {
152
+ content.items.splice(idx, 1);
153
+ }
154
+ }
155
+ }
156
+ if (args.items && Array.isArray(args.items)) {
157
+ const insertItems = args.items.filter((item) => item.insert_at !== undefined && item.item_index === undefined);
158
+ // Process inserts in reverse order of insert_at to preserve indices
159
+ const sortedInserts = [...insertItems].sort((a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0));
160
+ for (const item of sortedInserts) {
161
+ const insertUrl = item.shape_url ?? item.icon_image_url ?? '';
162
+ // Skip if this shape/icon already exists — defensive against duplicate
163
+ // tool call application
164
+ if (insertUrl &&
165
+ content.items?.some((existing) => existing.imageUrl === insertUrl)) {
166
+ continue;
167
+ }
168
+ const pos = Math.max(0, Math.min(item.insert_at ?? 0, content.items?.length ?? 0));
169
+ const newItem = {
170
+ imageUrl: insertUrl,
171
+ imageTitle: '',
172
+ width: 0,
173
+ height: 0,
174
+ mediaType: 'shape',
175
+ imageLink: '',
176
+ title: item.heading ?? '',
177
+ paragraph: item.text ?? '',
178
+ itemsId: pos,
179
+ colorReplacements: await resolveItemColorsAsync(item, [], undefined),
180
+ };
181
+ content.items = content.items ?? [];
182
+ content.items.splice(pos, 0, newItem);
183
+ }
184
+ }
185
+ if (args._reorder_items?.length && content.items) {
186
+ const newOrder = args._reorder_items;
187
+ const unique = new Set(newOrder);
188
+ if (unique.size === newOrder.length) {
189
+ const reordered = newOrder
190
+ .filter((idx) => idx >= 0 && idx < content.items.length)
191
+ .map((idx) => content.items[idx]);
192
+ if (reordered.length === content.items.length) {
193
+ content.items = reordered;
194
+ }
195
+ }
164
196
  }
165
- else if ((args.items && Array.isArray(args.items)) ||
166
- args._remove_item_ids?.length) {
167
- // Update: id-based add / edit / move / remove in a single pass.
168
- await mergeShapeItemsAsync(content, args.items ?? [], args._remove_item_ids);
197
+ // Re-index itemsId after any item operations
198
+ if (content.items) {
199
+ content.items.forEach((item, i) => {
200
+ item.itemsId = i;
201
+ });
169
202
  }
170
203
  return { request: this.request, model };
171
204
  }
@@ -1,15 +1,8 @@
1
1
  import { applyScalarFields, applyStyleFields } from '../section-field-utils';
2
2
  import { BaseSectionBuilder } from './base-section-builder';
3
3
  import { validateSocialLinks } from '../section-rules/social-links.rules';
4
- import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
5
- /**
6
- * Create path: build the links array from scratch, assigning stable ids.
7
- * `link.platform` is stored as `imageUrl` — the renderer resolves it to the
8
- * actual SVG at display time.
9
- */
10
4
  const applySocialLinks = (content, links) => {
11
5
  content.links = links.map((link) => ({
12
- id: link.item_id || generateItemId(),
13
6
  imageUrl: link.platform || '',
14
7
  imageTitle: '',
15
8
  width: 0,
@@ -18,46 +11,19 @@ const applySocialLinks = (content, links) => {
18
11
  url: link.url || '',
19
12
  }));
20
13
  };
21
- /**
22
- * Merge path: id-based add / edit / move / remove in a single pass (BP-5603).
23
- *
24
- * - Existing items are id-backfilled first so legacy sections gain stable ids
25
- * the moment the metadata builder touches them.
26
- * - `_remove_item_ids` deletes by id before the edit/add loop.
27
- * - An item with `item_id` matching an existing link is updated in place and
28
- * optionally repositioned via `move_before_item_id`.
29
- * - An item without `item_id` is added as a new link, positioned by
30
- * `move_before_item_id` (or appended when omitted).
31
- * - An item with an unknown `item_id` is skipped rather than guessing position.
32
- */
33
- const mergeSocialLinks = (content, links, removeIds) => {
34
- ensureItemIds(content.links);
35
- content.links = removeItemsByIds(content.links, removeIds);
36
- for (const link of links) {
37
- if (link.item_id) {
38
- const existing = content.links.find((l) => l.id === link.item_id);
39
- // Unknown id — skip rather than guess at a position.
40
- if (!existing)
41
- continue;
42
- if (link.platform !== undefined)
43
- existing.imageUrl = link.platform;
44
- if (link.url !== undefined)
45
- existing.url = link.url;
46
- repositionItemByAnchor(content.links, existing, link.move_before_item_id);
47
- }
48
- else {
49
- const newLink = {
50
- id: generateItemId(),
51
- imageUrl: link.platform ?? '',
52
- imageTitle: '',
53
- width: 0,
54
- height: 0,
55
- imageLink: '',
56
- url: link.url ?? '',
57
- };
58
- repositionItemByAnchor(content.links, newLink, link.move_before_item_id);
59
- }
14
+ const mergeSocialLinks = (content, links, replaceAll) => {
15
+ const updatedLinks = links.map((link, index) => {
16
+ const existing = content.links?.[index];
17
+ return {
18
+ ...(existing || {}),
19
+ imageUrl: link.platform ?? existing?.imageUrl ?? '',
20
+ url: link.url ?? existing?.url ?? '',
21
+ };
22
+ });
23
+ if (!replaceAll && content.links && content.links.length > links.length) {
24
+ updatedLinks.push(...content.links.slice(links.length));
60
25
  }
26
+ content.links = updatedLinks;
61
27
  };
62
28
  export class SocialLinksBuilder extends BaseSectionBuilder {
63
29
  get sectionValidate() {
@@ -76,19 +42,13 @@ export class SocialLinksBuilder extends BaseSectionBuilder {
76
42
  applyScalarFields(content, this.args, this.sectionType);
77
43
  applyStyleFields(content, this.args, this.sectionType, this.getGlobalTextStyles(model));
78
44
  const args = this.args;
79
- if (args._replace_items && args.links && Array.isArray(args.links)) {
80
- // Full replacement: discard existing links and rebuild from the payload.
81
- applySocialLinks(content, args.links);
82
- }
83
- else if (this.mode === 'create') {
84
- if (args.links && Array.isArray(args.links)) {
45
+ if (args.links && Array.isArray(args.links)) {
46
+ if (this.mode === 'create') {
85
47
  applySocialLinks(content, args.links);
86
48
  }
87
- }
88
- else if ((args.links && Array.isArray(args.links)) ||
89
- args._remove_item_ids?.length) {
90
- // Update: id-based add / edit / move / remove in a single pass.
91
- mergeSocialLinks(content, args.links ?? [], args._remove_item_ids);
49
+ else {
50
+ mergeSocialLinks(content, args.links, !!args._replace_items);
51
+ }
92
52
  }
93
53
  return { request: this.request, model };
94
54
  }
@@ -4,7 +4,6 @@ import { applyScalarFields, applyStyleFields, resolveGlobalPresetIntoStyle, } fr
4
4
  import { applyColorThemeToReplacements, resolveShapeColorReplacementsAsync, } from '../shape-color-utils';
5
5
  import { BaseSectionBuilder } from './base-section-builder';
6
6
  import { validateTestimonialSection, TESTIMONIAL_ITEM_CAP, } from '../section-rules/testimonial-section.rules';
7
- import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
8
7
  const resolveItemColorsAsync = async (item, existing, prevImageUrl) => {
9
8
  let colors = existing ?? [];
10
9
  if (item.avatar_shape_url && item.avatar_shape_url !== prevImageUrl) {
@@ -17,7 +16,6 @@ const resolveItemColorsAsync = async (item, existing, prevImageUrl) => {
17
16
  };
18
17
  const applyTestimonialItemsAsync = async (content, items) => {
19
18
  content.items = await Promise.all(items.map(async (item) => ({
20
- id: item.item_id || generateItemId(),
21
19
  imageUrl: item.avatar_shape_url || item.avatar_image_url || '',
22
20
  name: item.name || '',
23
21
  position: item.position || '',
@@ -26,28 +24,16 @@ const applyTestimonialItemsAsync = async (content, items) => {
26
24
  mediaType: item.avatar_shape_url ? 'shape' : 'image',
27
25
  })));
28
26
  };
29
- /**
30
- * Apply a batch of item operations by id (BP-5603), mirroring the section-level
31
- * id-based contract one level deeper:
32
- * - item with `item_id` matching an existing item → update in place (and
33
- * reposition if `move_before_item_id` is set);
34
- * - item without `item_id` → add a new item,
35
- * positioned by `move_before_item_id`;
36
- * - `_remove_item_ids` → delete by id.
37
- *
38
- * Existing items are id-backfilled first so legacy sections become referenceable
39
- * the moment the metadata builder touches them. Order-independent: there are no
40
- * positional indices to shift between operations.
41
- */
42
- const mergeTestimonialItemsAsync = async (content, items, removeIds) => {
43
- ensureItemIds(content.items);
44
- content.items = removeItemsByIds(content.items, removeIds);
45
- for (const item of items) {
46
- if (item.item_id) {
47
- const existing = content.items.find((i) => i.id === item.item_id);
48
- // Unknown id — skip rather than guess at a position.
49
- if (!existing)
50
- continue;
27
+ const mergeTestimonialItemsAsync = async (content, items, replaceAll) => {
28
+ const hasIndexedItems = items.some((item) => item.item_index !== undefined);
29
+ if (hasIndexedItems) {
30
+ await Promise.all(items.map(async (item) => {
31
+ const targetIndex = item.item_index;
32
+ if (targetIndex === undefined ||
33
+ targetIndex < 0 ||
34
+ !content.items?.[targetIndex])
35
+ return;
36
+ const existing = content.items[targetIndex];
51
37
  const prevImageUrl = existing.imageUrl;
52
38
  if (item.avatar_shape_url !== undefined) {
53
39
  existing.imageUrl = item.avatar_shape_url;
@@ -67,21 +53,37 @@ const mergeTestimonialItemsAsync = async (content, items, removeIds) => {
67
53
  item.color_theme !== undefined) {
68
54
  existing.colorReplacements = await resolveItemColorsAsync(item, existing.colorReplacements, prevImageUrl);
69
55
  }
70
- repositionItemByAnchor(content.items, existing, item.move_before_item_id);
71
- }
72
- else {
73
- const newItem = {
74
- id: generateItemId(),
75
- imageUrl: item.avatar_shape_url ?? item.avatar_image_url ?? '',
76
- name: item.name ?? '',
77
- position: item.position ?? '',
78
- testimonials: item.testimonial ?? '',
79
- colorReplacements: await resolveItemColorsAsync(item, [], undefined),
80
- mediaType: item.avatar_shape_url ? 'shape' : 'image',
81
- };
82
- repositionItemByAnchor(content.items, newItem, item.move_before_item_id);
83
- }
56
+ }));
57
+ return;
84
58
  }
59
+ const itemsToMerge = items.filter((item) => item.insert_at === undefined);
60
+ const updatedItems = await Promise.all(itemsToMerge.map(async (item, index) => {
61
+ const existing = content.items?.[index];
62
+ const imageUrl = item.avatar_shape_url ??
63
+ item.avatar_image_url ??
64
+ existing?.imageUrl ??
65
+ '';
66
+ const mediaType = item.avatar_shape_url
67
+ ? 'shape'
68
+ : item.avatar_image_url
69
+ ? 'image'
70
+ : (existing?.mediaType ?? 'image');
71
+ return {
72
+ ...(existing || {}),
73
+ imageUrl,
74
+ name: item.name ?? existing?.name ?? '',
75
+ position: item.position ?? existing?.position ?? '',
76
+ testimonials: item.testimonial ?? existing?.testimonials ?? '',
77
+ colorReplacements: await resolveItemColorsAsync(item, existing?.colorReplacements, existing?.imageUrl),
78
+ mediaType,
79
+ };
80
+ }));
81
+ if (!replaceAll &&
82
+ content.items &&
83
+ content.items.length > itemsToMerge.length) {
84
+ updatedItems.push(...content.items.slice(itemsToMerge.length));
85
+ }
86
+ content.items = updatedItems;
85
87
  };
86
88
  export class TestimonialSectionBuilder extends BaseSectionBuilder {
87
89
  get sectionValidate() {
@@ -130,24 +132,56 @@ export class TestimonialSectionBuilder extends BaseSectionBuilder {
130
132
  ])),
131
133
  };
132
134
  }
133
- if (args._replace_items && args.items && Array.isArray(args.items)) {
134
- // Full replacement: discard existing items and rebuild from the payload.
135
- await applyTestimonialItemsAsync(content, args.items);
136
- }
137
- else if (this.mode === 'create') {
138
- if (args.items && Array.isArray(args.items)) {
135
+ if (args.items && Array.isArray(args.items)) {
136
+ if (this.mode === 'create') {
139
137
  await applyTestimonialItemsAsync(content, args.items);
140
138
  }
139
+ else {
140
+ await mergeTestimonialItemsAsync(content, args.items, !!args._replace_items);
141
+ }
142
+ }
143
+ // Phase 2: Item operations (remove, insert, reorder)
144
+ if (args._remove_item_indices?.length && content.items) {
145
+ const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
146
+ for (const idx of sorted) {
147
+ if (idx >= 0 && idx < content.items.length) {
148
+ content.items.splice(idx, 1);
149
+ }
150
+ }
141
151
  }
142
- else if ((args.items && Array.isArray(args.items)) ||
143
- args._remove_item_ids?.length) {
144
- // Update: id-based add / edit / move / remove in a single pass.
145
- await mergeTestimonialItemsAsync(content, args.items ?? [], args._remove_item_ids);
152
+ if (args.items && Array.isArray(args.items)) {
153
+ const insertItems = args.items.filter((item) => item.insert_at !== undefined && item.item_index === undefined);
154
+ const sortedInserts = [...insertItems].sort((a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0));
155
+ for (const item of sortedInserts) {
156
+ const pos = Math.max(0, Math.min(item.insert_at ?? 0, content.items?.length ?? 0));
157
+ const newItem = {
158
+ imageUrl: item.avatar_shape_url ?? item.avatar_image_url ?? '',
159
+ name: item.name ?? '',
160
+ position: item.position ?? '',
161
+ testimonials: item.testimonial ?? '',
162
+ colorReplacements: await resolveItemColorsAsync(item, [], undefined),
163
+ mediaType: item.avatar_shape_url ? 'shape' : 'image',
164
+ };
165
+ content.items = content.items ?? [];
166
+ content.items.splice(pos, 0, newItem);
167
+ }
168
+ }
169
+ if (args._reorder_items?.length && content.items) {
170
+ const newOrder = args._reorder_items;
171
+ const unique = new Set(newOrder);
172
+ if (unique.size === newOrder.length) {
173
+ const reordered = newOrder
174
+ .filter((idx) => idx >= 0 && idx < content.items.length)
175
+ .map((idx) => content.items[idx]);
176
+ if (reordered.length === content.items.length) {
177
+ content.items = reordered;
178
+ }
179
+ }
146
180
  }
147
181
  // Post-merge cap check. itemCapCheck only fires for create / update with
148
- // _replace_items, so adding new items to an already-full section silently
149
- // bloats the array. Surface as an error so the AI retry loop gets a signal
150
- // and can reissue with _remove_item_ids or fewer additions.
182
+ // _replace_items, so insert_at on an already-full section silently bloats
183
+ // the array. Surface as an error so the AI retry loop gets a signal and
184
+ // can reissue with _remove_item_indices or fewer inserts.
151
185
  // brandSite key mirrors base-section-builder's hardcoded brandPageType.
152
186
  const cap = TESTIMONIAL_ITEM_CAP.brandSite;
153
187
  if (content.items && content.items.length > cap) {
@@ -3,7 +3,6 @@ import { isTiptapDocument, } from '../../parsers/section-tool-arguments';
3
3
  import { applyScalarFields, applyStyleFields, resolveGlobalPresetIntoStyle, } from '../section-field-utils';
4
4
  import { BaseSectionBuilder } from './base-section-builder';
5
5
  import { validateTextSection } from '../section-rules/text-section.rules';
6
- import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
7
6
  /** Resolve a RichTextField (string or TiptapDocument) to a plain HTML string. */
8
7
  const resolveText = (value) => {
9
8
  if (isTiptapDocument(value))
@@ -17,58 +16,55 @@ const createTextItem = (item, baseStyle, textStyleOptions) => {
17
16
  const textStyle = (item.text_style ? { ...baseStyle, ...item.text_style } : { ...baseStyle });
18
17
  const { html, wasTiptap } = resolveText(item.text);
19
18
  return {
20
- id: item.item_id || generateItemId(),
21
19
  text: html,
22
20
  textStyle: clearTextStyleTypeIfTiptap(textStyle, wasTiptap, textStyleOptions),
23
21
  };
24
22
  };
25
- /**
26
- * Full replacement: discard existing items and rebuild from the payload,
27
- * assigning a stable id to each new item.
28
- */
29
23
  const applyTextItems = (content, items, textStyleOptions) => {
30
24
  content.textItems = items.map((item) => createTextItem(item, content.textStyle || {}, textStyleOptions));
31
25
  };
32
- /**
33
- * Id-based merge (BP-5603): mirrors the section-level id contract one level
34
- * deeper.
35
- * - item with `item_id` matching an existing item → update in place and
36
- * reposition if `move_before_item_id` is set; unknown id is skipped.
37
- * - item without `item_id` → add a new item,
38
- * positioned by `move_before_item_id`.
39
- * - `removeIds` → delete by id.
40
- *
41
- * Existing items are id-backfilled first so legacy sections without ids
42
- * become referenceable the moment this builder processes them.
43
- */
44
- const mergeTextItems = (content, items, removeIds, textStyleOptions) => {
45
- ensureItemIds(content.textItems);
46
- content.textItems = removeItemsByIds(content.textItems, removeIds);
47
- for (const item of items) {
48
- if (item.item_id) {
49
- const existing = content.textItems?.find((i) => i.id === item.item_id);
50
- // Unknown id — skip rather than guess at a position.
51
- if (!existing)
26
+ const mergeTextItems = (content, items, replaceAll, textStyleOptions) => {
27
+ const hasIndexedItems = items.some((item) => item.item_index !== undefined);
28
+ if (hasIndexedItems) {
29
+ for (const item of items) {
30
+ const targetIndex = item.item_index;
31
+ if (targetIndex === undefined ||
32
+ targetIndex < 0 ||
33
+ !content.textItems?.[targetIndex])
52
34
  continue;
35
+ const existing = content.textItems[targetIndex];
53
36
  if (item.text !== undefined) {
54
37
  const { html, wasTiptap } = resolveText(item.text);
55
38
  existing.text = html;
56
39
  existing.textStyle = clearTextStyleTypeIfTiptap(existing.textStyle || {}, wasTiptap, textStyleOptions);
57
40
  }
58
41
  if (item.text_style && typeof item.text_style === 'object') {
59
- existing.textStyle = {
60
- ...(existing.textStyle || {}),
61
- ...item.text_style,
62
- };
42
+ const mergedStyle = (item.text_style
43
+ ? { ...(existing.textStyle || {}), ...item.text_style }
44
+ : existing.textStyle || {});
45
+ existing.textStyle = mergedStyle;
63
46
  }
64
- repositionItemByAnchor(content.textItems, existing, item.move_before_item_id);
65
- }
66
- else {
67
- const newItem = createTextItem(item, content.textStyle || {}, textStyleOptions);
68
- content.textItems = content.textItems ?? [];
69
- repositionItemByAnchor(content.textItems, newItem, item.move_before_item_id);
70
47
  }
48
+ return;
71
49
  }
50
+ const itemsToMerge = items.filter((item) => item.insert_at === undefined);
51
+ const updatedItems = itemsToMerge.map((item, index) => {
52
+ const existing = content.textItems?.[index];
53
+ const baseStyle = existing?.textStyle || content.textStyle || {};
54
+ const mergedStyle = (item.text_style ? { ...baseStyle, ...item.text_style } : baseStyle);
55
+ const resolved = item.text !== undefined ? resolveText(item.text) : null;
56
+ const text = resolved ? resolved.html : (existing?.text ?? '');
57
+ return {
58
+ text,
59
+ textStyle: clearTextStyleTypeIfTiptap(mergedStyle, resolved?.wasTiptap ?? false, textStyleOptions),
60
+ };
61
+ });
62
+ if (!replaceAll &&
63
+ content.textItems &&
64
+ content.textItems.length > itemsToMerge.length) {
65
+ updatedItems.push(...content.textItems.slice(itemsToMerge.length));
66
+ }
67
+ content.textItems = updatedItems;
72
68
  };
73
69
  /**
74
70
  * Handles the single `text` + `text_style` fields (BrandPage/BrandContact
@@ -125,27 +121,56 @@ export class TextSectionBuilder extends BaseSectionBuilder {
125
121
  applyScalarFields(content, this.args, this.sectionType);
126
122
  applyStyleFields(content, this.args, this.sectionType, this.getGlobalTextStyles(model));
127
123
  const args = this.args;
128
- if (args._replace_items && args.items && Array.isArray(args.items)) {
129
- // Full replacement: discard existing items and rebuild from the payload.
130
- applyTextItems(content, args.items, textStyleOptions);
131
- }
132
- else if (this.mode === 'create') {
133
- if (args.items && Array.isArray(args.items)) {
124
+ if (args.items && Array.isArray(args.items)) {
125
+ if (this.mode === 'create') {
134
126
  applyTextItems(content, args.items, textStyleOptions);
135
127
  }
136
128
  else {
137
- applySingleTextField(content, args, textStyleOptions);
129
+ mergeTextItems(content, args.items, !!args._replace_items, textStyleOptions);
138
130
  }
139
131
  }
140
- else if ((args.items && Array.isArray(args.items)) ||
141
- args._remove_item_ids?.length) {
142
- // Update: id-based add / edit / move / remove in a single pass.
143
- mergeTextItems(content, args.items ?? [], args._remove_item_ids, textStyleOptions);
144
- }
145
132
  else {
146
- // No items array: apply the single text/text_style shorthand fields.
147
133
  applySingleTextField(content, args, textStyleOptions);
148
134
  }
135
+ // Phase 2: Item operations (remove, insert, reorder)
136
+ if (args._remove_item_indices?.length && content.textItems) {
137
+ const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
138
+ for (const idx of sorted) {
139
+ if (idx >= 0 && idx < content.textItems.length) {
140
+ content.textItems.splice(idx, 1);
141
+ }
142
+ }
143
+ }
144
+ if (args.items && Array.isArray(args.items)) {
145
+ const insertItems = args.items.filter((item) => item.insert_at !== undefined && item.item_index === undefined);
146
+ const sortedInserts = [...insertItems].sort((a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0));
147
+ for (const item of sortedInserts) {
148
+ const pos = Math.max(0, Math.min(item.insert_at ?? 0, content.textItems?.length ?? 0));
149
+ const baseStyle = content.textStyle || {};
150
+ const textStyle = (item.text_style
151
+ ? { ...baseStyle, ...item.text_style }
152
+ : { ...baseStyle });
153
+ const { html, wasTiptap } = resolveText(item.text);
154
+ const newItem = {
155
+ text: html,
156
+ textStyle: clearTextStyleTypeIfTiptap(textStyle, wasTiptap, textStyleOptions),
157
+ };
158
+ content.textItems = content.textItems ?? [];
159
+ content.textItems.splice(pos, 0, newItem);
160
+ }
161
+ }
162
+ if (args._reorder_items?.length && content.textItems) {
163
+ const newOrder = args._reorder_items;
164
+ const unique = new Set(newOrder);
165
+ if (unique.size === newOrder.length) {
166
+ const reordered = newOrder
167
+ .filter((idx) => idx >= 0 && idx < content.textItems.length)
168
+ .map((idx) => content.textItems[idx]);
169
+ if (reordered.length === content.textItems.length) {
170
+ content.textItems = reordered;
171
+ }
172
+ }
173
+ }
149
174
  if (args.background_color !== undefined) {
150
175
  content.backgroundColor = {
151
176
  ...content.backgroundColor,