@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
@@ -18,24 +18,12 @@ 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
- 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
- */
21
+
33
22
  const applyImageItems = (
34
23
  content: ImagesSectionContent,
35
24
  items: ImagesSectionItem[],
36
25
  ): void => {
37
26
  content.items = items.map((item, index) => ({
38
- id: item.item_id || generateItemId(),
39
27
  imageUrl: isValidUrl(item.image_url) ? item.image_url! : '',
40
28
  imageTitle: '',
41
29
  width: 0,
@@ -50,33 +38,25 @@ const applyImageItems = (
50
38
  }));
51
39
  };
52
40
 
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
- */
66
41
  const mergeImageItems = (
67
42
  content: ImagesSectionContent,
68
43
  items: ImagesSectionItem[],
69
- removeIds: string[] | undefined,
44
+ replaceAll: boolean,
70
45
  ): void => {
71
- ensureItemIds(content.items);
72
- content.items = removeItemsByIds(content.items, removeIds);
46
+ const hasIndexedItems = items.some((item) => item.item_index !== undefined);
73
47
 
74
- for (const item of items) {
75
- if (item.item_id) {
76
- const existing = content.items.find((i) => i.id === item.item_id);
48
+ if (hasIndexedItems) {
49
+ for (const item of items) {
50
+ const targetIndex = item.item_index;
77
51
 
78
- // Unknown id — skip rather than guess at a position.
79
- if (!existing) continue;
52
+ if (
53
+ targetIndex === undefined ||
54
+ targetIndex < 0 ||
55
+ !content.items?.[targetIndex]
56
+ )
57
+ continue;
58
+
59
+ const existing = content.items[targetIndex];
80
60
 
81
61
  if (isValidUrl(item.image_url)) existing.imageUrl = item.image_url!;
82
62
 
@@ -86,27 +66,47 @@ const mergeImageItems = (
86
66
 
87
67
  if (item.button_text !== undefined)
88
68
  existing.buttonText = item.button_text || false;
89
-
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
69
  }
70
+
71
+ return;
109
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
+
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);
107
+ }
108
+
109
+ content.items = updatedItems;
110
110
  };
111
111
 
112
112
  export class ImagesSectionBuilder extends BaseSectionBuilder<ImagesSectionContent> {
@@ -192,23 +192,86 @@ export class ImagesSectionBuilder extends BaseSectionBuilder<ImagesSectionConten
192
192
  };
193
193
  }
194
194
 
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)) {
195
+ if (args.items && Array.isArray(args.items)) {
196
+ if (this.mode === 'create') {
200
197
  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
+ }
201
271
  }
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);
208
272
  }
209
273
 
210
- // Re-index itemsId after all id-based item operations (render concern —
211
- // separate from the stable `id` used for targeting).
274
+ // Re-index itemsId after any item operations
212
275
  if (content.items) {
213
276
  content.items.forEach((item, i) => {
214
277
  item.itemsId = i;
@@ -23,12 +23,6 @@ import {
23
23
  } from '../shape-color-utils';
24
24
  import { BaseSectionBuilder } from './base-section-builder';
25
25
  import { validateShapesSection } from '../section-rules/shapes-section.rules';
26
- import {
27
- ensureItemIds,
28
- generateItemId,
29
- removeItemsByIds,
30
- repositionItemByAnchor,
31
- } from '../item-id-utils';
32
26
 
33
27
  const resolveItemColorsAsync = async (
34
28
  item: ShapesSectionItem,
@@ -49,117 +43,111 @@ const resolveItemColorsAsync = async (
49
43
  return colors;
50
44
  };
51
45
 
52
- /**
53
- * Full replacement: discard existing items and rebuild from the payload.
54
- * Used for create mode and _replace_items: true.
55
- */
56
46
  const applyShapeItemsAsync = async (
57
47
  content: ShapesSectionContent,
58
48
  items: ShapesSectionItem[],
59
49
  ): Promise<void> => {
60
50
  content.items = await Promise.all(
61
- items.map(async (item) => ({
62
- id: item.item_id || generateItemId(),
51
+ items.map(async (item, index) => ({
63
52
  imageUrl: item.shape_url || item.icon_image_url || '',
64
53
  imageTitle: '',
65
54
  width: 0,
66
55
  height: 0,
67
- mediaType: 'shape' as const,
68
- imageLink: '' as const,
56
+ mediaType: 'shape',
57
+ imageLink: '',
69
58
  title: item.heading || '',
70
59
  paragraph: item.text || '',
71
- itemsId: 0,
60
+ itemsId: index,
72
61
  colorReplacements: await resolveItemColorsAsync(item, [], undefined),
73
62
  })),
74
63
  );
75
-
76
- // Re-index itemsId after build
77
- content.items.forEach((item, i) => {
78
- (item as TextShapeItem).itemsId = i;
79
- });
80
64
  };
81
65
 
82
- /**
83
- * Apply a batch of item operations by id (BP-5603), mirroring the section-level
84
- * id-based contract one level deeper:
85
- * - item with `item_id` matching an existing item → update in place (and
86
- * reposition if `move_before_item_id` is set);
87
- * - item without `item_id` → add a new item,
88
- * positioned by `move_before_item_id`;
89
- * - `_remove_item_ids` → delete by id.
90
- *
91
- * Existing items are id-backfilled first so legacy sections become referenceable
92
- * the moment the metadata builder touches them. Order-independent: there are no
93
- * positional indices to shift between operations.
94
- */
95
66
  const mergeShapeItemsAsync = async (
96
67
  content: ShapesSectionContent,
97
68
  items: ShapesSectionItem[],
98
- removeIds: string[] | undefined,
69
+ replaceAll: boolean,
99
70
  ): Promise<void> => {
100
- ensureItemIds(content.items as TextShapeItem[]);
101
- content.items = removeItemsByIds(content.items as TextShapeItem[], removeIds);
102
-
103
- for (const item of items) {
104
- if (item.item_id) {
105
- const existing = (content.items as TextShapeItem[]).find(
106
- (i) => i.id === item.item_id,
107
- );
108
-
109
- // Unknown id — skip rather than guess at a position.
110
- if (!existing) continue;
111
-
112
- const prevImageUrl = existing.imageUrl;
113
-
114
- if (item.shape_url !== undefined || item.icon_image_url !== undefined) {
115
- existing.imageUrl =
116
- item.shape_url ?? item.icon_image_url ?? existing.imageUrl;
117
- }
118
-
119
- if (item.heading !== undefined) existing.title = item.heading;
71
+ const hasIndexedItems = items.some((item) => item.item_index !== undefined);
72
+
73
+ if (hasIndexedItems) {
74
+ await Promise.all(
75
+ items.map(async (item) => {
76
+ const targetIndex = item.item_index;
77
+
78
+ if (
79
+ targetIndex === undefined ||
80
+ targetIndex < 0 ||
81
+ !content.items?.[targetIndex]
82
+ )
83
+ return;
84
+
85
+ const existing = content.items[targetIndex] as TextShapeItem;
86
+ const prevImageUrl = existing.imageUrl;
87
+
88
+ if (item.shape_url !== undefined || item.icon_image_url !== undefined) {
89
+ existing.imageUrl =
90
+ item.shape_url ?? item.icon_image_url ?? existing.imageUrl;
91
+ }
92
+
93
+ if (item.heading !== undefined) existing.title = item.heading;
94
+
95
+ if (item.text !== undefined) existing.paragraph = item.text;
96
+
97
+ if (item.shape_url !== undefined || item.color_theme !== undefined) {
98
+ existing.colorReplacements = await resolveItemColorsAsync(
99
+ item,
100
+ existing.colorReplacements,
101
+ prevImageUrl,
102
+ );
103
+ }
104
+ }),
105
+ );
120
106
 
121
- if (item.text !== undefined) existing.paragraph = item.text;
107
+ return;
108
+ }
122
109
 
123
- if (item.shape_url !== undefined || item.color_theme !== undefined) {
124
- existing.colorReplacements = await resolveItemColorsAsync(
110
+ const itemsToMerge = items.filter((item) => item.insert_at === undefined);
111
+
112
+ const updatedItems = await Promise.all(
113
+ itemsToMerge.map(async (item, index) => {
114
+ const existing = content.items?.[index];
115
+ const imageUrl =
116
+ item.shape_url ?? item.icon_image_url ?? existing?.imageUrl ?? '';
117
+
118
+ return {
119
+ ...(existing || {}),
120
+ imageUrl,
121
+ imageTitle: existing?.imageTitle ?? '',
122
+ width: existing?.width ?? 0,
123
+ height: existing?.height ?? 0,
124
+ mediaType: existing?.mediaType ?? 'shape',
125
+ imageLink: existing?.imageLink ?? '',
126
+ title: item.heading ?? existing?.title ?? '',
127
+ paragraph: item.text ?? existing?.paragraph ?? '',
128
+ itemsId: existing?.itemsId ?? index,
129
+ colorReplacements: await resolveItemColorsAsync(
125
130
  item,
126
- existing.colorReplacements,
127
- prevImageUrl,
128
- );
129
- }
131
+ existing?.colorReplacements,
132
+ existing?.imageUrl,
133
+ ),
134
+ };
135
+ }),
136
+ );
130
137
 
131
- repositionItemByAnchor(
132
- content.items as TextShapeItem[],
133
- existing,
134
- item.move_before_item_id,
135
- );
136
- } else {
137
- const newItem = {
138
- id: generateItemId(),
139
- imageUrl: item.shape_url ?? item.icon_image_url ?? '',
140
- imageTitle: '',
141
- width: 0,
142
- height: 0,
143
- mediaType: 'shape' as const,
144
- imageLink: '' as const,
145
- title: item.heading ?? '',
146
- paragraph: item.text ?? '',
147
- itemsId: 0,
148
- colorReplacements: await resolveItemColorsAsync(item, [], undefined),
149
- } as TextShapeItem;
150
-
151
- repositionItemByAnchor(
152
- content.items as TextShapeItem[],
153
- newItem,
154
- item.move_before_item_id,
155
- );
156
- }
138
+ if (
139
+ !replaceAll &&
140
+ content.items &&
141
+ content.items.length > itemsToMerge.length
142
+ ) {
143
+ const remaining = content.items.slice(
144
+ itemsToMerge.length,
145
+ ) as typeof updatedItems;
146
+
147
+ updatedItems.push(...remaining);
157
148
  }
158
149
 
159
- // Re-index itemsId after all mutations
160
- (content.items as TextShapeItem[]).forEach((item, i) => {
161
- item.itemsId = i;
162
- });
150
+ content.items = updatedItems;
163
151
  };
164
152
 
165
153
  export class ShapesSectionBuilder extends BaseSectionBuilder<ShapesSectionContent> {
@@ -245,23 +233,90 @@ export class ShapesSectionBuilder extends BaseSectionBuilder<ShapesSectionConten
245
233
  };
246
234
  }
247
235
 
248
- if (args._replace_items && args.items && Array.isArray(args.items)) {
249
- // Full replacement: discard existing items and rebuild from the payload.
250
- await applyShapeItemsAsync(content, args.items);
251
- } else if (this.mode === 'create') {
252
- if (args.items && Array.isArray(args.items)) {
236
+ if (args.items && Array.isArray(args.items)) {
237
+ if (this.mode === 'create') {
253
238
  await applyShapeItemsAsync(content, args.items);
239
+ } else {
240
+ await mergeShapeItemsAsync(content, args.items, !!args._replace_items);
241
+ }
242
+ }
243
+
244
+ // Phase 2: Item operations (remove, insert, reorder)
245
+ if (args._remove_item_indices?.length && content.items) {
246
+ const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
247
+
248
+ for (const idx of sorted) {
249
+ if (idx >= 0 && idx < content.items.length) {
250
+ content.items.splice(idx, 1);
251
+ }
254
252
  }
255
- } else if (
256
- (args.items && Array.isArray(args.items)) ||
257
- args._remove_item_ids?.length
258
- ) {
259
- // Update: id-based add / edit / move / remove in a single pass.
260
- await mergeShapeItemsAsync(
261
- content,
262
- args.items ?? [],
263
- args._remove_item_ids,
253
+ }
254
+
255
+ if (args.items && Array.isArray(args.items)) {
256
+ const insertItems = args.items.filter(
257
+ (item) => item.insert_at !== undefined && item.item_index === undefined,
264
258
  );
259
+ // Process inserts in reverse order of insert_at to preserve indices
260
+ const sortedInserts = [...insertItems].sort(
261
+ (a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0),
262
+ );
263
+
264
+ for (const item of sortedInserts) {
265
+ const insertUrl = item.shape_url ?? item.icon_image_url ?? '';
266
+
267
+ // Skip if this shape/icon already exists — defensive against duplicate
268
+ // tool call application
269
+ if (
270
+ insertUrl &&
271
+ content.items?.some(
272
+ (existing: any) => existing.imageUrl === insertUrl,
273
+ )
274
+ ) {
275
+ continue;
276
+ }
277
+
278
+ const pos = Math.max(
279
+ 0,
280
+ Math.min(item.insert_at ?? 0, content.items?.length ?? 0),
281
+ );
282
+ const newItem = {
283
+ imageUrl: insertUrl,
284
+ imageTitle: '',
285
+ width: 0,
286
+ height: 0,
287
+ mediaType: 'shape',
288
+ imageLink: '',
289
+ title: item.heading ?? '',
290
+ paragraph: item.text ?? '',
291
+ itemsId: pos,
292
+ colorReplacements: await resolveItemColorsAsync(item, [], undefined),
293
+ };
294
+
295
+ content.items = content.items ?? [];
296
+ content.items.splice(pos, 0, newItem as any);
297
+ }
298
+ }
299
+
300
+ if (args._reorder_items?.length && content.items) {
301
+ const newOrder = args._reorder_items;
302
+ const unique = new Set(newOrder);
303
+
304
+ if (unique.size === newOrder.length) {
305
+ const reordered = newOrder
306
+ .filter((idx) => idx >= 0 && idx < content.items!.length)
307
+ .map((idx) => content.items![idx]);
308
+
309
+ if (reordered.length === content.items.length) {
310
+ content.items = reordered;
311
+ }
312
+ }
313
+ }
314
+
315
+ // Re-index itemsId after any item operations
316
+ if (content.items) {
317
+ content.items.forEach((item, i) => {
318
+ item.itemsId = i;
319
+ });
265
320
  }
266
321
 
267
322
  return { request: this.request, model };
@@ -10,24 +10,12 @@ import type { BuilderResult } from '../../models';
10
10
  import { applyScalarFields, applyStyleFields } from '../section-field-utils';
11
11
  import { BaseSectionBuilder } from './base-section-builder';
12
12
  import { validateSocialLinks } from '../section-rules/social-links.rules';
13
- import {
14
- ensureItemIds,
15
- generateItemId,
16
- removeItemsByIds,
17
- repositionItemByAnchor,
18
- } from '../item-id-utils';
19
-
20
- /**
21
- * Create path: build the links array from scratch, assigning stable ids.
22
- * `link.platform` is stored as `imageUrl` — the renderer resolves it to the
23
- * actual SVG at display time.
24
- */
13
+
25
14
  const applySocialLinks = (
26
15
  content: SocialLinksContent,
27
16
  links: SocialLink[],
28
17
  ): void => {
29
18
  content.links = links.map((link) => ({
30
- id: link.item_id || generateItemId(),
31
19
  imageUrl: link.platform || '',
32
20
  imageTitle: '',
33
21
  width: 0,
@@ -37,52 +25,26 @@ const applySocialLinks = (
37
25
  }));
38
26
  };
39
27
 
40
- /**
41
- * Merge path: id-based add / edit / move / remove in a single pass (BP-5603).
42
- *
43
- * - Existing items are id-backfilled first so legacy sections gain stable ids
44
- * the moment the metadata builder touches them.
45
- * - `_remove_item_ids` deletes by id before the edit/add loop.
46
- * - An item with `item_id` matching an existing link is updated in place and
47
- * optionally repositioned via `move_before_item_id`.
48
- * - An item without `item_id` is added as a new link, positioned by
49
- * `move_before_item_id` (or appended when omitted).
50
- * - An item with an unknown `item_id` is skipped rather than guessing position.
51
- */
52
28
  const mergeSocialLinks = (
53
29
  content: SocialLinksContent,
54
30
  links: SocialLink[],
55
- removeIds: string[] | undefined,
31
+ replaceAll: boolean,
56
32
  ): void => {
57
- ensureItemIds(content.links);
58
- content.links = removeItemsByIds(content.links, removeIds);
59
-
60
- for (const link of links) {
61
- if (link.item_id) {
62
- const existing = content.links.find((l) => l.id === link.item_id);
63
-
64
- // Unknown id — skip rather than guess at a position.
65
- if (!existing) continue;
66
-
67
- if (link.platform !== undefined) existing.imageUrl = link.platform;
68
-
69
- if (link.url !== undefined) existing.url = link.url;
70
-
71
- repositionItemByAnchor(content.links, existing, link.move_before_item_id);
72
- } else {
73
- const newLink = {
74
- id: generateItemId(),
75
- imageUrl: link.platform ?? '',
76
- imageTitle: '',
77
- width: 0,
78
- height: 0,
79
- imageLink: '' as const,
80
- url: link.url ?? '',
81
- };
82
-
83
- repositionItemByAnchor(content.links, newLink, link.move_before_item_id);
84
- }
33
+ const updatedLinks = links.map((link, index) => {
34
+ const existing = content.links?.[index];
35
+
36
+ return {
37
+ ...(existing || {}),
38
+ imageUrl: link.platform ?? existing?.imageUrl ?? '',
39
+ url: link.url ?? existing?.url ?? '',
40
+ };
41
+ });
42
+
43
+ if (!replaceAll && content.links && content.links.length > links.length) {
44
+ updatedLinks.push(...content.links.slice(links.length));
85
45
  }
46
+
47
+ content.links = updatedLinks;
86
48
  };
87
49
 
88
50
  export class SocialLinksBuilder extends BaseSectionBuilder<SocialLinksContent> {
@@ -115,19 +77,12 @@ export class SocialLinksBuilder extends BaseSectionBuilder<SocialLinksContent> {
115
77
 
116
78
  const args = this.args as SocialLinksSectionArguments;
117
79
 
118
- if (args._replace_items && args.links && Array.isArray(args.links)) {
119
- // Full replacement: discard existing links and rebuild from the payload.
120
- applySocialLinks(content, args.links);
121
- } else if (this.mode === 'create') {
122
- if (args.links && Array.isArray(args.links)) {
80
+ if (args.links && Array.isArray(args.links)) {
81
+ if (this.mode === 'create') {
123
82
  applySocialLinks(content, args.links);
83
+ } else {
84
+ mergeSocialLinks(content, args.links, !!args._replace_items);
124
85
  }
125
- } else if (
126
- (args.links && Array.isArray(args.links)) ||
127
- args._remove_item_ids?.length
128
- ) {
129
- // Update: id-based add / edit / move / remove in a single pass.
130
- mergeSocialLinks(content, args.links ?? [], args._remove_item_ids);
131
86
  }
132
87
 
133
88
  return { request: this.request, model };