@salla.sa/twilight-components 3.0.16 → 3.0.18

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/dist/cjs/{Helper-BV6HUQzI.js → Helper-D2VNt6eb.js} +1 -1
  2. package/dist/cjs/{filepond-hJcaHnfM.js → filepond-DkCudLhG.js} +1 -1
  3. package/dist/cjs/{filepond-plugin-file-poster-DDkDXFOe.js → filepond-plugin-file-poster-C-uxFWfW.js} +1 -1
  4. package/dist/cjs/{filepond-plugin-file-validate-size-BBZimb8J.js → filepond-plugin-file-validate-size-BikXTQW2.js} +1 -1
  5. package/dist/cjs/{filepond-plugin-file-validate-type-B5VDnf33.js → filepond-plugin-file-validate-type-Drs7PouU.js} +1 -1
  6. package/dist/cjs/{filepond-plugin-image-edit-Cmuqwdn1.js → filepond-plugin-image-edit-hxr0h9kt.js} +1 -1
  7. package/dist/cjs/{filepond-plugin-image-exif-orientation-BFjHgWMS.js → filepond-plugin-image-exif-orientation-CVZmWU_4.js} +1 -1
  8. package/dist/cjs/{filepond-plugin-image-preview-C7Ow81pR.js → filepond-plugin-image-preview-CBjPKx-d.js} +1 -1
  9. package/dist/cjs/free-shipping-timer-6QBe5BNS.js +156 -0
  10. package/dist/cjs/{index-PB4iLztN.js → index-CTYg2zC6.js} +8 -8
  11. package/dist/cjs/{intlTelInput-Ds-AW6H6.js → intlTelInput-C9X0hKXV.js} +1 -1
  12. package/dist/cjs/loader.cjs.js +2 -2
  13. package/dist/cjs/salla-accordion-body_2.cjs.entry.js +1 -1
  14. package/dist/cjs/salla-accordion_6.cjs.entry.js +2 -2
  15. package/dist/cjs/salla-add-product-button_5.cjs.entry.js +2 -2
  16. package/dist/cjs/salla-advertisement.cjs.entry.js +1 -1
  17. package/dist/cjs/salla-alert_2.cjs.entry.js +1 -1
  18. package/dist/cjs/salla-app-install-alert.cjs.entry.js +1 -1
  19. package/dist/cjs/salla-applied-filters.cjs.entry.js +2 -2
  20. package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
  21. package/dist/cjs/salla-attachment-view_9.cjs.entry.js +11 -11
  22. package/dist/cjs/salla-badge.cjs.entry.js +1 -1
  23. package/dist/cjs/salla-basket-gap.cjs.entry.js +1 -1
  24. package/dist/cjs/salla-bullet-delivery_3.cjs.entry.js +166 -16
  25. package/dist/cjs/salla-cart-coupons.cjs.entry.js +1 -1
  26. package/dist/cjs/salla-cart-item-offers_2.cjs.entry.js +1 -1
  27. package/dist/cjs/salla-cart-summary-card.cjs.entry.js +1 -1
  28. package/dist/cjs/salla-cashback-banner.cjs.entry.js +1 -1
  29. package/dist/cjs/salla-comment-factors.cjs.entry.js +1 -1
  30. package/dist/cjs/salla-comment-form_9.cjs.entry.js +2 -2
  31. package/dist/cjs/salla-conditional-offer.cjs.entry.js +1 -1
  32. package/dist/cjs/salla-contacts.cjs.entry.js +1 -1
  33. package/dist/cjs/salla-cookies-bar.cjs.entry.js +1 -1
  34. package/dist/cjs/salla-count-down.cjs.entry.js +1 -1
  35. package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
  36. package/dist/cjs/salla-delivery-promise.cjs.entry.js +1 -1
  37. package/dist/cjs/salla-edit-order-button.cjs.entry.js +1 -1
  38. package/dist/cjs/salla-filters-widget.cjs.entry.js +2 -2
  39. package/dist/cjs/salla-filters.cjs.entry.js +2 -2
  40. package/dist/cjs/salla-free-shipping-banner.cjs.entry.js +95 -9
  41. package/dist/cjs/salla-free-shipping-tag.cjs.entry.js +18 -5
  42. package/dist/cjs/salla-fulfillment-methods.cjs.entry.js +1 -1
  43. package/dist/cjs/salla-gift-card-redeem_2.cjs.entry.js +1 -1
  44. package/dist/cjs/salla-gifting.cjs.entry.js +13 -6
  45. package/dist/cjs/salla-hook.cjs.entry.js +1 -1
  46. package/dist/cjs/salla-infinite-scroll.cjs.entry.js +2 -2
  47. package/dist/cjs/salla-installment.cjs.entry.js +1 -1
  48. package/dist/cjs/salla-list-tile.cjs.entry.js +1 -1
  49. package/dist/cjs/salla-localization-modal.cjs.entry.js +1 -1
  50. package/dist/cjs/salla-login-modal.cjs.entry.js +1 -1
  51. package/dist/cjs/salla-loyalty-banner_10.cjs.entry.js +1 -1
  52. package/dist/cjs/salla-loyalty-exchange-product-card.cjs.entry.js +1 -1
  53. package/dist/cjs/salla-loyalty-points-banner.cjs.entry.js +1 -1
  54. package/dist/cjs/salla-loyalty-points-history.cjs.entry.js +1 -1
  55. package/dist/cjs/salla-loyalty-prize-item.cjs.entry.js +1 -1
  56. package/dist/cjs/salla-loyalty.cjs.entry.js +1 -1
  57. package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
  58. package/dist/cjs/salla-map_3.cjs.entry.js +1 -1
  59. package/dist/cjs/salla-menu.cjs.entry.js +1 -1
  60. package/dist/cjs/salla-metadata.cjs.entry.js +1 -1
  61. package/dist/cjs/salla-multiple-bundle-product-cart_2.cjs.entry.js +1 -1
  62. package/dist/cjs/salla-multiple-bundle-product-options-modal_2.cjs.entry.js +1 -1
  63. package/dist/cjs/salla-multiple-bundle-product.cjs.entry.js +1 -1
  64. package/dist/cjs/salla-next-order-coupon.cjs.entry.js +1 -1
  65. package/dist/cjs/salla-notification-item_2.cjs.entry.js +2 -2
  66. package/dist/cjs/salla-offer-modal.cjs.entry.js +8 -4
  67. package/dist/cjs/salla-offer.cjs.entry.js +7 -3
  68. package/dist/cjs/salla-order-branch.cjs.entry.js +1 -1
  69. package/dist/cjs/salla-order-cancel.cjs.entry.js +1 -1
  70. package/dist/cjs/salla-order-details-multiple-bundle-product.cjs.entry.js +1 -1
  71. package/dist/cjs/salla-order-details-options.cjs.entry.js +1 -1
  72. package/dist/cjs/salla-order-details.cjs.entry.js +1 -1
  73. package/dist/cjs/salla-order-edit-item.cjs.entry.js +1 -1
  74. package/dist/cjs/salla-order-edit-product-card.cjs.entry.js +1 -1
  75. package/dist/cjs/salla-order-edit.cjs.entry.js +1 -1
  76. package/dist/cjs/salla-order-items.cjs.entry.js +1 -1
  77. package/dist/cjs/salla-order-options-modal.cjs.entry.js +1 -1
  78. package/dist/cjs/salla-order-payment.cjs.entry.js +1 -1
  79. package/dist/cjs/salla-order-rewards.cjs.entry.js +1 -1
  80. package/dist/cjs/salla-order-shipments.cjs.entry.js +1 -1
  81. package/dist/cjs/salla-order-summary.cjs.entry.js +1 -1
  82. package/dist/cjs/salla-order-totals-card.cjs.entry.js +1 -1
  83. package/dist/cjs/salla-orders.cjs.entry.js +2 -2
  84. package/dist/cjs/salla-payments.cjs.entry.js +1 -1
  85. package/dist/cjs/salla-placeholder.cjs.entry.js +1 -1
  86. package/dist/cjs/salla-price-range.cjs.entry.js +1 -1
  87. package/dist/cjs/salla-product-card-embed.cjs.entry.js +1 -1
  88. package/dist/cjs/salla-product-card.cjs.entry.js +1 -1
  89. package/dist/cjs/salla-product-size-guide.cjs.entry.js +1 -1
  90. package/dist/cjs/salla-products-list.cjs.entry.js +6 -5
  91. package/dist/cjs/salla-products-slider.cjs.entry.js +2 -2
  92. package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
  93. package/dist/cjs/salla-rating-modal-v2.cjs.entry.js +7 -4
  94. package/dist/cjs/salla-rating-modal.cjs.entry.js +2 -2
  95. package/dist/cjs/salla-review-factors-tags.cjs.entry.js +1 -1
  96. package/dist/cjs/salla-review-order-item.cjs.entry.js +1 -1
  97. package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
  98. package/dist/cjs/salla-search-product-card.cjs.entry.js +1 -1
  99. package/dist/cjs/salla-search.cjs.entry.js +2 -2
  100. package/dist/cjs/salla-skeleton.cjs.entry.js +1 -1
  101. package/dist/cjs/salla-social-share.cjs.entry.js +1 -1
  102. package/dist/cjs/salla-social.cjs.entry.js +1 -1
  103. package/dist/cjs/salla-tab-content_3.cjs.entry.js +1 -1
  104. package/dist/cjs/salla-thank-you-header.cjs.entry.js +1 -1
  105. package/dist/cjs/salla-thank-you-page.cjs.entry.js +1 -1
  106. package/dist/cjs/salla-tiered-offer.cjs.entry.js +1 -1
  107. package/dist/cjs/salla-trust-badges.cjs.entry.js +1 -1
  108. package/dist/cjs/salla-user-menu.cjs.entry.js +1 -1
  109. package/dist/cjs/salla-user-profile.cjs.entry.js +1 -1
  110. package/dist/cjs/salla-user-settings.cjs.entry.js +1 -1
  111. package/dist/cjs/salla-verify.cjs.entry.js +1 -1
  112. package/dist/cjs/salla-wallet.cjs.entry.js +1 -1
  113. package/dist/cjs/salla-wishlist-actions.cjs.entry.js +1 -1
  114. package/dist/cjs/salla-wishlist-summary.cjs.entry.js +2 -2
  115. package/dist/cjs/twilight.cjs.js +2 -2
  116. package/dist/cjs/{vanilla-picker-ZsewI4gd.js → vanilla-picker-BsLm8rHT.js} +1 -1
  117. package/dist/collection/components/salla-bullet-delivery/salla-bullet-delivery.js +72 -16
  118. package/dist/collection/components/salla-bullet-delivery/selector-tracker.js +106 -0
  119. package/dist/collection/components/salla-free-shipping-banner/salla-free-shipping-banner.css +18 -4
  120. package/dist/collection/components/salla-free-shipping-banner/salla-free-shipping-banner.js +94 -11
  121. package/dist/collection/components/salla-free-shipping-tag/salla-free-shipping-tag.css +6 -0
  122. package/dist/collection/components/salla-free-shipping-tag/salla-free-shipping-tag.js +18 -2
  123. package/dist/collection/components/salla-gifting/salla-gifting.css +16 -1
  124. package/dist/collection/components/salla-gifting/salla-gifting.js +11 -4
  125. package/dist/collection/components/salla-offer/salla-offer.js +6 -2
  126. package/dist/collection/components/salla-offer-modal/salla-offer-modal.js +7 -3
  127. package/dist/collection/components/salla-products-list/salla-products-list.js +4 -3
  128. package/dist/collection/components/salla-rating-modal/salla-rating-modal-v2.js +5 -2
  129. package/dist/collection/shared/free-shipping-timer.js +130 -0
  130. package/dist/components/free-shipping-timer.js +150 -0
  131. package/dist/components/index.js +8 -8
  132. package/dist/components/salla-bullet-delivery.js +165 -15
  133. package/dist/components/salla-free-shipping-banner.js +95 -8
  134. package/dist/components/salla-free-shipping-tag.js +17 -3
  135. package/dist/components/salla-gifting.js +12 -5
  136. package/dist/components/salla-offer-modal.js +7 -3
  137. package/dist/components/salla-offer.js +6 -2
  138. package/dist/components/salla-products-list2.js +4 -3
  139. package/dist/components/salla-rating-modal-v22.js +5 -2
  140. package/dist/docs.json +25 -5
  141. package/dist/esm/{Helper-CsyfMJLx.js → Helper-C1T-oD4J.js} +1 -1
  142. package/dist/esm/{filepond-Cla3ae_2.js → filepond-BoWJzHeN.js} +1 -1
  143. package/dist/esm/{filepond-plugin-file-poster-BO0nARSu.js → filepond-plugin-file-poster-B6MkMtuC.js} +1 -1
  144. package/dist/esm/{filepond-plugin-file-validate-size-CrcZ7P5c.js → filepond-plugin-file-validate-size-Dds_462B.js} +1 -1
  145. package/dist/esm/{filepond-plugin-file-validate-type-Cci8f5e3.js → filepond-plugin-file-validate-type-DrfGXNay.js} +1 -1
  146. package/dist/esm/{filepond-plugin-image-edit-y0q-Gkyo.js → filepond-plugin-image-edit-CN7eGg-7.js} +1 -1
  147. package/dist/esm/{filepond-plugin-image-exif-orientation-WYrkP26J.js → filepond-plugin-image-exif-orientation-CyhxK_6R.js} +1 -1
  148. package/dist/esm/{filepond-plugin-image-preview-Bz0ZRBQp.js → filepond-plugin-image-preview-DdKqAzT9.js} +1 -1
  149. package/dist/esm/free-shipping-timer-CnTwkF6y.js +150 -0
  150. package/dist/esm/{index-DJuBNP7w.js → index-DgUQRYr2.js} +8 -8
  151. package/dist/esm/{intlTelInput-Dcl0COqn.js → intlTelInput-SwlavcFB.js} +1 -1
  152. package/dist/esm/loader.js +3 -3
  153. package/dist/esm/salla-accordion-body_2.entry.js +1 -1
  154. package/dist/esm/salla-accordion_6.entry.js +2 -2
  155. package/dist/esm/salla-add-product-button_5.entry.js +2 -2
  156. package/dist/esm/salla-advertisement.entry.js +1 -1
  157. package/dist/esm/salla-alert_2.entry.js +1 -1
  158. package/dist/esm/salla-app-install-alert.entry.js +1 -1
  159. package/dist/esm/salla-applied-filters.entry.js +2 -2
  160. package/dist/esm/salla-apps-icons.entry.js +1 -1
  161. package/dist/esm/salla-attachment-view_9.entry.js +11 -11
  162. package/dist/esm/salla-badge.entry.js +1 -1
  163. package/dist/esm/salla-basket-gap.entry.js +1 -1
  164. package/dist/esm/salla-bullet-delivery_3.entry.js +166 -16
  165. package/dist/esm/salla-cart-coupons.entry.js +1 -1
  166. package/dist/esm/salla-cart-item-offers_2.entry.js +1 -1
  167. package/dist/esm/salla-cart-summary-card.entry.js +1 -1
  168. package/dist/esm/salla-cashback-banner.entry.js +1 -1
  169. package/dist/esm/salla-comment-factors.entry.js +1 -1
  170. package/dist/esm/salla-comment-form_9.entry.js +2 -2
  171. package/dist/esm/salla-conditional-offer.entry.js +1 -1
  172. package/dist/esm/salla-contacts.entry.js +1 -1
  173. package/dist/esm/salla-cookies-bar.entry.js +1 -1
  174. package/dist/esm/salla-count-down.entry.js +1 -1
  175. package/dist/esm/salla-custom-fields.entry.js +1 -1
  176. package/dist/esm/salla-delivery-promise.entry.js +1 -1
  177. package/dist/esm/salla-edit-order-button.entry.js +1 -1
  178. package/dist/esm/salla-filters-widget.entry.js +2 -2
  179. package/dist/esm/salla-filters.entry.js +2 -2
  180. package/dist/esm/salla-free-shipping-banner.entry.js +94 -8
  181. package/dist/esm/salla-free-shipping-tag.entry.js +17 -4
  182. package/dist/esm/salla-fulfillment-methods.entry.js +1 -1
  183. package/dist/esm/salla-gift-card-redeem_2.entry.js +1 -1
  184. package/dist/esm/salla-gifting.entry.js +13 -6
  185. package/dist/esm/salla-hook.entry.js +1 -1
  186. package/dist/esm/salla-infinite-scroll.entry.js +2 -2
  187. package/dist/esm/salla-installment.entry.js +1 -1
  188. package/dist/esm/salla-list-tile.entry.js +1 -1
  189. package/dist/esm/salla-localization-modal.entry.js +1 -1
  190. package/dist/esm/salla-login-modal.entry.js +1 -1
  191. package/dist/esm/salla-loyalty-banner_10.entry.js +1 -1
  192. package/dist/esm/salla-loyalty-exchange-product-card.entry.js +1 -1
  193. package/dist/esm/salla-loyalty-points-banner.entry.js +1 -1
  194. package/dist/esm/salla-loyalty-points-history.entry.js +1 -1
  195. package/dist/esm/salla-loyalty-prize-item.entry.js +1 -1
  196. package/dist/esm/salla-loyalty.entry.js +1 -1
  197. package/dist/esm/salla-maintenance-alert.entry.js +1 -1
  198. package/dist/esm/salla-map_3.entry.js +1 -1
  199. package/dist/esm/salla-menu.entry.js +1 -1
  200. package/dist/esm/salla-metadata.entry.js +1 -1
  201. package/dist/esm/salla-multiple-bundle-product-cart_2.entry.js +1 -1
  202. package/dist/esm/salla-multiple-bundle-product-options-modal_2.entry.js +1 -1
  203. package/dist/esm/salla-multiple-bundle-product.entry.js +1 -1
  204. package/dist/esm/salla-next-order-coupon.entry.js +1 -1
  205. package/dist/esm/salla-notification-item_2.entry.js +2 -2
  206. package/dist/esm/salla-offer-modal.entry.js +8 -4
  207. package/dist/esm/salla-offer.entry.js +7 -3
  208. package/dist/esm/salla-order-branch.entry.js +1 -1
  209. package/dist/esm/salla-order-cancel.entry.js +1 -1
  210. package/dist/esm/salla-order-details-multiple-bundle-product.entry.js +1 -1
  211. package/dist/esm/salla-order-details-options.entry.js +1 -1
  212. package/dist/esm/salla-order-details.entry.js +1 -1
  213. package/dist/esm/salla-order-edit-item.entry.js +1 -1
  214. package/dist/esm/salla-order-edit-product-card.entry.js +1 -1
  215. package/dist/esm/salla-order-edit.entry.js +1 -1
  216. package/dist/esm/salla-order-items.entry.js +1 -1
  217. package/dist/esm/salla-order-options-modal.entry.js +1 -1
  218. package/dist/esm/salla-order-payment.entry.js +1 -1
  219. package/dist/esm/salla-order-rewards.entry.js +1 -1
  220. package/dist/esm/salla-order-shipments.entry.js +1 -1
  221. package/dist/esm/salla-order-summary.entry.js +1 -1
  222. package/dist/esm/salla-order-totals-card.entry.js +1 -1
  223. package/dist/esm/salla-orders.entry.js +2 -2
  224. package/dist/esm/salla-payments.entry.js +1 -1
  225. package/dist/esm/salla-placeholder.entry.js +1 -1
  226. package/dist/esm/salla-price-range.entry.js +1 -1
  227. package/dist/esm/salla-product-card-embed.entry.js +1 -1
  228. package/dist/esm/salla-product-card.entry.js +1 -1
  229. package/dist/esm/salla-product-size-guide.entry.js +1 -1
  230. package/dist/esm/salla-products-list.entry.js +6 -5
  231. package/dist/esm/salla-products-slider.entry.js +2 -2
  232. package/dist/esm/salla-quick-order.entry.js +1 -1
  233. package/dist/esm/salla-rating-modal-v2.entry.js +7 -4
  234. package/dist/esm/salla-rating-modal.entry.js +2 -2
  235. package/dist/esm/salla-review-factors-tags.entry.js +1 -1
  236. package/dist/esm/salla-review-order-item.entry.js +1 -1
  237. package/dist/esm/salla-scopes.entry.js +1 -1
  238. package/dist/esm/salla-search-product-card.entry.js +1 -1
  239. package/dist/esm/salla-search.entry.js +2 -2
  240. package/dist/esm/salla-skeleton.entry.js +1 -1
  241. package/dist/esm/salla-social-share.entry.js +1 -1
  242. package/dist/esm/salla-social.entry.js +1 -1
  243. package/dist/esm/salla-tab-content_3.entry.js +1 -1
  244. package/dist/esm/salla-thank-you-header.entry.js +1 -1
  245. package/dist/esm/salla-thank-you-page.entry.js +1 -1
  246. package/dist/esm/salla-tiered-offer.entry.js +1 -1
  247. package/dist/esm/salla-trust-badges.entry.js +1 -1
  248. package/dist/esm/salla-user-menu.entry.js +1 -1
  249. package/dist/esm/salla-user-profile.entry.js +1 -1
  250. package/dist/esm/salla-user-settings.entry.js +1 -1
  251. package/dist/esm/salla-verify.entry.js +1 -1
  252. package/dist/esm/salla-wallet.entry.js +1 -1
  253. package/dist/esm/salla-wishlist-actions.entry.js +1 -1
  254. package/dist/esm/salla-wishlist-summary.entry.js +2 -2
  255. package/dist/esm/twilight.js +3 -3
  256. package/dist/esm/{vanilla-picker-DPvEywPm.js → vanilla-picker-Buy50D7t.js} +1 -1
  257. package/dist/twilight/{p-134692f5.entry.js → p-027cbda6.entry.js} +1 -1
  258. package/dist/twilight/{p-48fb615e.entry.js → p-0418c2df.entry.js} +1 -1
  259. package/dist/twilight/{p-792f1e05.entry.js → p-071aa0e7.entry.js} +1 -1
  260. package/dist/twilight/{p-be203bd9.entry.js → p-08a15c81.entry.js} +1 -1
  261. package/dist/twilight/{p-5f5c4f3c.entry.js → p-0ba159db.entry.js} +1 -1
  262. package/dist/twilight/{p-c657883d.entry.js → p-0d795b58.entry.js} +1 -1
  263. package/dist/twilight/{p-9f9ab89c.entry.js → p-0f25fedd.entry.js} +1 -1
  264. package/dist/twilight/{p-15098cb1.entry.js → p-12a25415.entry.js} +1 -1
  265. package/dist/twilight/p-1960020c.entry.js +4 -0
  266. package/dist/twilight/{p-f1037da9.entry.js → p-1af9db24.entry.js} +1 -1
  267. package/dist/twilight/p-23772523.entry.js +4 -0
  268. package/dist/twilight/{p-67bb5e0c.entry.js → p-254cff9a.entry.js} +1 -1
  269. package/dist/twilight/{p-a8f88ea6.entry.js → p-259c995a.entry.js} +1 -1
  270. package/dist/twilight/{p-3f701181.entry.js → p-26d2b28a.entry.js} +1 -1
  271. package/dist/twilight/{p-8a7bce99.entry.js → p-34148827.entry.js} +1 -1
  272. package/dist/twilight/{p-8e6bc10e.entry.js → p-361f6033.entry.js} +1 -1
  273. package/dist/twilight/{p-43700093.entry.js → p-37192614.entry.js} +1 -1
  274. package/dist/twilight/{p-1e7a0a4f.entry.js → p-3a632c69.entry.js} +1 -1
  275. package/dist/twilight/{p-b90d0e51.entry.js → p-3d8b77f7.entry.js} +1 -1
  276. package/dist/twilight/{p-615edf90.entry.js → p-3f842f32.entry.js} +1 -1
  277. package/dist/twilight/{p-788c0264.entry.js → p-419d6d71.entry.js} +1 -1
  278. package/dist/twilight/{p-b891f863.entry.js → p-481f52b1.entry.js} +1 -1
  279. package/dist/twilight/{p-343f57ea.entry.js → p-487b4411.entry.js} +1 -1
  280. package/dist/twilight/{p-19bf11c5.entry.js → p-4891c565.entry.js} +1 -1
  281. package/dist/twilight/{p-cfe523ab.entry.js → p-4a3fa153.entry.js} +1 -1
  282. package/dist/twilight/{p-33689489.entry.js → p-4ab5ee99.entry.js} +1 -1
  283. package/dist/twilight/{p-558f8ee0.entry.js → p-4b70e6c4.entry.js} +1 -1
  284. package/dist/twilight/{p-96be66eb.entry.js → p-516e4edc.entry.js} +1 -1
  285. package/dist/twilight/{p-9f920812.entry.js → p-53735934.entry.js} +1 -1
  286. package/dist/twilight/{p-e66f1b70.entry.js → p-5694edf1.entry.js} +1 -1
  287. package/dist/twilight/{p-9e8c583a.entry.js → p-5bbf17dd.entry.js} +1 -1
  288. package/dist/twilight/{p-43a4e000.entry.js → p-5e8d019e.entry.js} +1 -1
  289. package/dist/twilight/{p-8278e31a.entry.js → p-5f6fee0e.entry.js} +1 -1
  290. package/dist/twilight/{p-1436b465.entry.js → p-66ad7a30.entry.js} +1 -1
  291. package/dist/twilight/p-6af8a7b6.entry.js +4 -0
  292. package/dist/twilight/{p-96e16a6b.entry.js → p-6b5de500.entry.js} +1 -1
  293. package/dist/twilight/{p-951f1af4.entry.js → p-6ba3808a.entry.js} +1 -1
  294. package/dist/twilight/{p-ebb756bc.entry.js → p-6c3084c9.entry.js} +1 -1
  295. package/dist/twilight/{p-72092eff.entry.js → p-6dccd40f.entry.js} +1 -1
  296. package/dist/twilight/{p-70d5d802.entry.js → p-6e52b649.entry.js} +1 -1
  297. package/dist/twilight/{p-caac5694.entry.js → p-70dfb2b4.entry.js} +1 -1
  298. package/dist/twilight/{p-75015061.entry.js → p-76584a5b.entry.js} +1 -1
  299. package/dist/twilight/{p-f46da712.entry.js → p-78a56dc6.entry.js} +1 -1
  300. package/dist/twilight/{p-aa210c8a.entry.js → p-79822d99.entry.js} +1 -1
  301. package/dist/twilight/{p-5aa8ec0a.entry.js → p-7b5f97e7.entry.js} +1 -1
  302. package/dist/twilight/{p-9e24dec9.entry.js → p-7f97335a.entry.js} +1 -1
  303. package/dist/twilight/{p-3cbcec7c.entry.js → p-7fd9dc36.entry.js} +1 -1
  304. package/dist/twilight/p-84b0e7a9.entry.js +4 -0
  305. package/dist/twilight/p-8766e236.entry.js +4 -0
  306. package/dist/twilight/{p-a9a8a819.entry.js → p-8c1d14f0.entry.js} +1 -1
  307. package/dist/twilight/{p-a92e5068.entry.js → p-8c40278d.entry.js} +1 -1
  308. package/dist/twilight/{p-5b52ef24.entry.js → p-92fd20a0.entry.js} +1 -1
  309. package/dist/twilight/{p-f24a477c.entry.js → p-9cf1cfd4.entry.js} +1 -1
  310. package/dist/twilight/{p-f2062f34.entry.js → p-9d15f22d.entry.js} +1 -1
  311. package/dist/twilight/{p-8907ef61.entry.js → p-9e042cce.entry.js} +1 -1
  312. package/dist/twilight/{p-74238c01.entry.js → p-9e0a9a5a.entry.js} +1 -1
  313. package/dist/twilight/{p-8cb6dfd9.entry.js → p-9e65451e.entry.js} +1 -1
  314. package/dist/twilight/{p-BgGU8BXX.js → p-BK9YeXWp.js} +1 -1
  315. package/dist/twilight/{p-Do-w5Os8.js → p-BxQMWsr9.js} +1 -1
  316. package/dist/twilight/{p-DCUZjQXX.js → p-CBLWEyM9.js} +1 -1
  317. package/dist/twilight/{p-pOFi82Pb.js → p-CCwsxMbZ.js} +1 -1
  318. package/dist/twilight/{p-DliR9Sp1.js → p-Ca_SZn0u.js} +1 -1
  319. package/dist/twilight/{p-CqENl4Wm.js → p-CgNJWeaK.js} +1 -1
  320. package/dist/twilight/p-CnTwkF6y.js +4 -0
  321. package/dist/twilight/{p-DHk7-wXk.js → p-DMvhNbgN.js} +1 -1
  322. package/dist/twilight/{p-BPjqOy84.js → p-De1tLqQF.js} +1 -1
  323. package/dist/twilight/p-DgUQRYr2.js +5 -0
  324. package/dist/twilight/{p-CRYD9K0S.js → p-NqQdbGu6.js} +1 -1
  325. package/dist/twilight/{p-C9eNuCn7.js → p-Y2ZIN9Ok.js} +1 -1
  326. package/dist/twilight/{p-3b3f1838.entry.js → p-a44670a9.entry.js} +1 -1
  327. package/dist/twilight/{p-2ce991e8.entry.js → p-a5b732b3.entry.js} +1 -1
  328. package/dist/twilight/{p-5e8b7483.entry.js → p-a95b0dc1.entry.js} +1 -1
  329. package/dist/twilight/{p-20642013.entry.js → p-aa35cf98.entry.js} +1 -1
  330. package/dist/twilight/{p-1267d95a.entry.js → p-ac736b30.entry.js} +1 -1
  331. package/dist/twilight/{p-e651c3ee.entry.js → p-af49191f.entry.js} +1 -1
  332. package/dist/twilight/{p-82d50064.entry.js → p-b0d2e31f.entry.js} +1 -1
  333. package/dist/twilight/{p-8b72b7a2.entry.js → p-b1f808f5.entry.js} +1 -1
  334. package/dist/twilight/{p-b798788b.entry.js → p-b3ada3d0.entry.js} +1 -1
  335. package/dist/twilight/{p-03e6d42b.entry.js → p-b5a45f87.entry.js} +1 -1
  336. package/dist/twilight/p-b9d67694.entry.js +4 -0
  337. package/dist/twilight/{p-dcfd3688.entry.js → p-ba6dd59c.entry.js} +1 -1
  338. package/dist/twilight/p-bac25e34.entry.js +4 -0
  339. package/dist/twilight/{p-05e1fc6a.entry.js → p-bb8b2c85.entry.js} +1 -1
  340. package/dist/twilight/{p-b1aa33f3.entry.js → p-be6f8551.entry.js} +1 -1
  341. package/dist/twilight/{p-91ef7c89.entry.js → p-bed54154.entry.js} +1 -1
  342. package/dist/twilight/{p-4a3d4c28.entry.js → p-bed68e52.entry.js} +1 -1
  343. package/dist/twilight/{p-a7d2613b.entry.js → p-bfd5e263.entry.js} +1 -1
  344. package/dist/twilight/{p-63053048.entry.js → p-c4cf0b4d.entry.js} +1 -1
  345. package/dist/twilight/{p-189fa3c4.entry.js → p-cb48a5ef.entry.js} +1 -1
  346. package/dist/twilight/{p-370924c0.entry.js → p-cdeb9bcc.entry.js} +1 -1
  347. package/dist/twilight/{p-9b46c1ab.entry.js → p-d0aeeb7f.entry.js} +1 -1
  348. package/dist/twilight/{p-537748de.entry.js → p-d0ff9a3e.entry.js} +1 -1
  349. package/dist/twilight/{p-86db3fe8.entry.js → p-d1093a59.entry.js} +1 -1
  350. package/dist/twilight/{p-4be6e307.entry.js → p-d1121b3f.entry.js} +1 -1
  351. package/dist/twilight/{p-be84879f.entry.js → p-d1204965.entry.js} +1 -1
  352. package/dist/twilight/p-d346dabd.entry.js +4 -0
  353. package/dist/twilight/{p-3b6efc6e.entry.js → p-d4fb9921.entry.js} +1 -1
  354. package/dist/twilight/{p-52749db7.entry.js → p-d8955835.entry.js} +1 -1
  355. package/dist/twilight/{p-1c2d9885.entry.js → p-d9a1bf08.entry.js} +1 -1
  356. package/dist/twilight/{p-e67fdc9d.entry.js → p-da0df10b.entry.js} +1 -1
  357. package/dist/twilight/p-e24fbbb4.entry.js +4 -0
  358. package/dist/twilight/{p-a16f2376.entry.js → p-e38a6793.entry.js} +1 -1
  359. package/dist/twilight/{p-4a843e15.entry.js → p-e457e68f.entry.js} +1 -1
  360. package/dist/twilight/{p-382dc313.entry.js → p-e9b03e9c.entry.js} +1 -1
  361. package/dist/twilight/{p-c33be542.entry.js → p-eaf0c514.entry.js} +1 -1
  362. package/dist/twilight/{p-5b60ebdf.entry.js → p-ee479819.entry.js} +1 -1
  363. package/dist/twilight/p-ee65c489.entry.js +4 -0
  364. package/dist/twilight/{p-a6ba5168.entry.js → p-eefced26.entry.js} +1 -1
  365. package/dist/twilight/{p-a36e2dcf.entry.js → p-f7a58656.entry.js} +1 -1
  366. package/dist/twilight/{p-4a07e070.entry.js → p-f7ab5825.entry.js} +1 -1
  367. package/dist/twilight/{p-927d1967.entry.js → p-f9587127.entry.js} +1 -1
  368. package/dist/twilight/{p-09c651a2.entry.js → p-f9e5ed10.entry.js} +1 -1
  369. package/dist/twilight/{p-5f1b28e3.entry.js → p-fcb1009f.entry.js} +1 -1
  370. package/dist/twilight/{p-de458068.entry.js → p-fddf1997.entry.js} +1 -1
  371. package/dist/twilight/twilight.esm.js +1 -1
  372. package/dist/types/components/salla-bullet-delivery/salla-bullet-delivery.d.ts +9 -1
  373. package/dist/types/components/salla-bullet-delivery/selector-tracker.d.ts +30 -0
  374. package/dist/types/components/salla-free-shipping-banner/salla-free-shipping-banner.d.ts +19 -5
  375. package/dist/types/components/salla-free-shipping-tag/salla-free-shipping-tag.d.ts +6 -1
  376. package/dist/types/components/salla-gifting/salla-gifting.d.ts +1 -0
  377. package/dist/types/components/salla-rating-modal/salla-rating-modal-v2.d.ts +1 -0
  378. package/dist/types/components.d.ts +11 -25
  379. package/dist/types/shared/free-shipping-timer.d.ts +36 -0
  380. package/package.json +5 -5
  381. package/dist/cjs/free-shipping-DkIKD6ch.js +0 -31
  382. package/dist/components/free-shipping.js +0 -29
  383. package/dist/esm/free-shipping-Brg4wsgg.js +0 -29
  384. package/dist/twilight/p-0c292c9a.entry.js +0 -4
  385. package/dist/twilight/p-1a7b0a2b.entry.js +0 -4
  386. package/dist/twilight/p-3b4aa865.entry.js +0 -4
  387. package/dist/twilight/p-3f713fc0.entry.js +0 -4
  388. package/dist/twilight/p-6a8d04d9.entry.js +0 -4
  389. package/dist/twilight/p-86ade991.entry.js +0 -4
  390. package/dist/twilight/p-9b02e779.entry.js +0 -4
  391. package/dist/twilight/p-Brg4wsgg.js +0 -4
  392. package/dist/twilight/p-DJuBNP7w.js +0 -5
  393. package/dist/twilight/p-bf12f616.entry.js +0 -4
  394. package/dist/twilight/p-d5b394c9.entry.js +0 -4
  395. package/dist/twilight/p-def7b9c4.entry.js +0 -4
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { h, Host, } from "@stencil/core";
5
5
  import { bulletDeliveryAPI, clearApiCache, isSaudiArabia } from "./api-service";
6
+ import { SelectorTracker, allocatedBranchIds, toCloseReason, } from "./selector-tracker";
6
7
  import { filterBranches, findNearestBranch, getGeolocationErrorMessage, getIntentBranchId, getIntentCityId, getIntentCountryCode, getIntentCountryId, getIntentDistrictId, getIntentLatitude, getIntentLongitude, getIntentRegionId, getIntentSubtitle, hasSessionAddressIntent, isBranchSelectable, isMapOriginIntent, requireRegionAndDistrictForSA, } from "./helpers";
7
8
  /* Location permission notice */
8
9
  import { isLocationPermissionMissing, LocationPermissionNotice, requestLocationPermission, watchLocationPermission, } from "./location-permission-notice";
@@ -63,6 +64,13 @@ export class SallaBulletDelivery {
63
64
  this.open();
64
65
  };
65
66
  this.closeHandler = null;
67
+ this.selectorTracker = new SelectorTracker();
68
+ this.openTrigger = "customer_requested";
69
+ this.pendingDismissReason = null;
70
+ this.modalCloseHandler = (detail) => {
71
+ this.pendingDismissReason = toCloseReason(detail?.reason);
72
+ queueMicrotask(() => (this.pendingDismissReason = null));
73
+ };
66
74
  this.bulletDeliveryMobileSelectHandler = null;
67
75
  /** True after saved addresses have been loaded (lazy: only when address tab is shown). */
68
76
  this.savedAddressesLoaded = false;
@@ -329,6 +337,7 @@ export class SallaBulletDelivery {
329
337
  const details = this.buildIntentAddress();
330
338
  if (!details)
331
339
  return;
340
+ const previousIntent = this.getStoredIntent();
332
341
  this.setStoredIntent({
333
342
  type: "address",
334
343
  country_id: Number(this.selectedCountry?.id) || 0,
@@ -337,7 +346,7 @@ export class SallaBulletDelivery {
337
346
  });
338
347
  this.selectedSavedAddress = null;
339
348
  this.selectedSessionAddress = true;
340
- await this.handleConfirm();
349
+ await this.handleConfirm(previousIntent);
341
350
  };
342
351
  this.handleCountrySelected = (item) => {
343
352
  const country = this.countries.find(c => String(c.id) === String(item.id)) || item;
@@ -422,9 +431,10 @@ export class SallaBulletDelivery {
422
431
  * successful auto-confirm never flashes the saved-addresses list; the caller is
423
432
  * responsible for revealing the modal itself if it still needs the customer's input.
424
433
  */
425
- async open(silent = false) {
434
+ async open(silent = false, trigger = "customer_requested") {
426
435
  if (!this.isEnabled)
427
436
  return; // feature disabled — never open
437
+ this.openTrigger = trigger;
428
438
  // If mobile app, open the sheet
429
439
  if (this.isMobileApp) {
430
440
  Salla.event.dispatch('salla::bullet-delivery.open-sheet');
@@ -526,6 +536,33 @@ export class SallaBulletDelivery {
526
536
  this.bulletDeliveryClosed.emit();
527
537
  return this.modal?.close();
528
538
  }
539
+ selectorContext() {
540
+ return {
541
+ configured_required: this.isRequired,
542
+ effective_nonclosable: this.isRequired || this.shouldForceNonClosable(),
543
+ trigger_configured: this.openingType ?? null,
544
+ trigger_actual: this.openTrigger,
545
+ };
546
+ }
547
+ handleModalVisibility(visible) {
548
+ if (visible) {
549
+ this.selectorTracker.viewed(this.selectorContext());
550
+ return;
551
+ }
552
+ if (!this.pendingDismissReason)
553
+ return;
554
+ this.selectorTracker.dismissed(this.selectorContext(), this.pendingDismissReason, !!this.getStoredIntent()?.scope_allocated);
555
+ this.pendingDismissReason = null;
556
+ }
557
+ trackSelectorResult(outcome, previousIntent, newBranchIds, scopeId) {
558
+ this.selectorTracker.result(this.selectorContext(), {
559
+ outcome,
560
+ fulfilment_method: this.activeTab === "branch" ? "pickup" : "delivery",
561
+ previous_branch_ids: previousIntent?.scope_allocated ? allocatedBranchIds(previousIntent) : [],
562
+ new_branch_ids: newBranchIds,
563
+ scope_id: scopeId ?? null,
564
+ });
565
+ }
529
566
  resetState() {
530
567
  this.viewMode = "main";
531
568
  this.mapLocationData = null;
@@ -665,7 +702,7 @@ export class SallaBulletDelivery {
665
702
  if (!wasVisible) {
666
703
  // Load silently — a successful auto-confirm should never flash the
667
704
  // saved-addresses list; only reveal the modal below if it can't finish on its own.
668
- await this.open(true);
705
+ await this.open(true, "after_login");
669
706
  }
670
707
  // open() -> loadSavedAddresses() already sets selectedSessionAddress when a
671
708
  // session intent exists; bail if that didn't happen (e.g. address_id already set).
@@ -1728,7 +1765,7 @@ export class SallaBulletDelivery {
1728
1765
  if (await this.tryAutoConfirmAfterLogin())
1729
1766
  return;
1730
1767
  if (!this.modal?.hasAttribute?.("visible") || !this.isLoggedIn) {
1731
- this.open();
1768
+ this.open(false, "after_login");
1732
1769
  }
1733
1770
  }
1734
1771
  buildIntentAddress() {
@@ -2007,13 +2044,14 @@ export class SallaBulletDelivery {
2007
2044
  }
2008
2045
  return raw;
2009
2046
  }
2010
- async handleConfirm() {
2047
+ async handleConfirm(intentBeforeDraft) {
2011
2048
  if (this.isConfirmDisabled() || this.confirming)
2012
2049
  return;
2013
2050
  this.allocationOutOfCoverageMessage = null;
2014
2051
  this.confirming = true;
2015
2052
  this.confirmBtn?.load();
2016
2053
  let scheduledRedirect = false;
2054
+ const previousIntent = intentBeforeDraft === undefined ? this.getStoredIntent() : intentBeforeDraft;
2017
2055
  try {
2018
2056
  // A guest map pin uses the pin's own country; the IP/selected country may differ from it.
2019
2057
  const country = this.activeTab === "address" && this.isGuestMapPick
@@ -2031,6 +2069,7 @@ export class SallaBulletDelivery {
2031
2069
  const savedAddress = await this.saveSessionAddressToProfile();
2032
2070
  if (!savedAddress) {
2033
2071
  Salla.notify?.error(Salla.lang.get("common.errors.error_occurred"));
2072
+ this.trackSelectorResult("failed", previousIntent, []);
2034
2073
  this.confirmBtn?.stop();
2035
2074
  return;
2036
2075
  }
@@ -2105,6 +2144,7 @@ export class SallaBulletDelivery {
2105
2144
  ? Salla.lang.get("pages.checkout.address_out_of_coverage")
2106
2145
  : Salla.lang.get("pages.checkout.failed_to_set_pickup"));
2107
2146
  this.allocationOutOfCoverageMessage = `${errorMessage}.`;
2147
+ this.trackSelectorResult("failed", previousIntent, []);
2108
2148
  this.confirmBtn?.stop();
2109
2149
  this.confirming = false;
2110
2150
  return;
@@ -2141,6 +2181,7 @@ export class SallaBulletDelivery {
2141
2181
  const scopeApplied = await bulletDeliveryAPI.setDeliveryScope(allocatedScopeId);
2142
2182
  if (!scopeApplied) {
2143
2183
  this.allocationOutOfCoverageMessage = `${Salla.lang.get("common.errors.error_occurred")}.`;
2184
+ this.trackSelectorResult("failed", previousIntent, [], allocatedScopeId);
2144
2185
  this.confirmBtn?.stop();
2145
2186
  this.confirming = false;
2146
2187
  return;
@@ -2160,6 +2201,7 @@ export class SallaBulletDelivery {
2160
2201
  // After allocation success: persist latest intent so switch UI can always reflect
2161
2202
  // the selected address/branch once confirmed.
2162
2203
  this.setStoredIntent({ ...result, scope_allocated: true });
2204
+ this.trackSelectorResult("accepted", previousIntent, allocatedBranchIds(result), allocatedScopeId);
2163
2205
  const allocationConfirmedPayload = {
2164
2206
  ...result,
2165
2207
  address: this.buildAllocationConfirmedAddressData(selectedAddress),
@@ -2679,7 +2721,7 @@ export class SallaBulletDelivery {
2679
2721
  if (canOpenForIncompleteIntent) {
2680
2722
  this.markIncompleteIntentPrompted();
2681
2723
  }
2682
- this.open();
2724
+ this.open(false, canOpenForIncompleteIntent ? "incomplete_intent" : "after_add_to_cart");
2683
2725
  }
2684
2726
  overrideScopeSwitchUI() {
2685
2727
  const intent = this.getStoredIntent();
@@ -2732,7 +2774,7 @@ export class SallaBulletDelivery {
2732
2774
  // silently awaiting with nothing visible.
2733
2775
  if (!this.isGuestUser()) {
2734
2776
  if (!this.modal?.hasAttribute?.("visible")) {
2735
- this.open();
2777
+ this.open(false, "checkout_gate");
2736
2778
  }
2737
2779
  await this.pendingCartSubmitPromise;
2738
2780
  return;
@@ -2761,7 +2803,7 @@ export class SallaBulletDelivery {
2761
2803
  this.openGuestLogin();
2762
2804
  return;
2763
2805
  }
2764
- this.open();
2806
+ this.open(false, "checkout_gate");
2765
2807
  });
2766
2808
  await this.pendingCartSubmitPromise;
2767
2809
  };
@@ -2777,6 +2819,7 @@ export class SallaBulletDelivery {
2777
2819
  Salla.event.on("salla::bullet-delivery.modal.open.requested", this.bulletDeliveryOpenHandler);
2778
2820
  this.closeHandler = this.close.bind(this);
2779
2821
  Salla.event.on("salla::bullet-delivery.modal.close.requested", this.closeHandler);
2822
+ Salla.event.on("modal::close", this.modalCloseHandler);
2780
2823
  this.isRTL = Salla.config.get("theme.is_rtl");
2781
2824
  // Reading the permission never prompts, so it's safe to watch from here — the map view then
2782
2825
  // renders the notice (or not) on its first paint instead of a frame later.
@@ -2801,7 +2844,7 @@ export class SallaBulletDelivery {
2801
2844
  return;
2802
2845
  if (this.modal?.hasAttribute?.("visible"))
2803
2846
  return;
2804
- this.open();
2847
+ this.open(false, "after_login");
2805
2848
  };
2806
2849
  Salla.event.on("auth::logged.in", this.authLoggedInHandler);
2807
2850
  this.authLoggedOutHandler = () => {
@@ -2833,7 +2876,10 @@ export class SallaBulletDelivery {
2833
2876
  return null; // no-op when disabled
2834
2877
  return (h(Host, { class: "s-bullet-delivery" }, h("salla-modal", { ref: modal => {
2835
2878
  this.modal = modal;
2836
- }, isClosable: !this.isRequired && !this.shouldForceNonClosable(), class: "s-bullet-delivery-modal", width: "sm", "data-testid": "salla-bullet-delivery-modal" }, h("div", { class: "s-bullet-delivery-inner" }, h("div", { class: "s-bullet-delivery-header" }, h("h2", { class: "s-bullet-delivery-title" }, this.activeTab === 'address'
2879
+ }, isClosable: !this.isRequired && !this.shouldForceNonClosable(), onModalVisibilityChanged: (event) => {
2880
+ if (event.target === this.modal)
2881
+ this.handleModalVisibility(Boolean(event.detail));
2882
+ }, class: "s-bullet-delivery-modal", width: "sm", "data-testid": "salla-bullet-delivery-modal" }, h("div", { class: "s-bullet-delivery-inner" }, h("div", { class: "s-bullet-delivery-header" }, h("h2", { class: "s-bullet-delivery-title" }, this.activeTab === 'address'
2837
2883
  ? Salla.lang.get('blocks.home.add_address_for_order_delivery')
2838
2884
  : Salla.lang.get('blocks.home.choose_branch_for_order_pickup')), h("p", { class: "s-bullet-delivery-subtitle" }, this.activeTab === 'address'
2839
2885
  ? Salla.lang.get('blocks.home.products_available_for_delivery_shown_while_shopping')
@@ -2869,7 +2915,7 @@ export class SallaBulletDelivery {
2869
2915
  // Handle pending open request (if event was emitted before component was ready)
2870
2916
  if (this.pendingOpen) {
2871
2917
  this.pendingOpen = false;
2872
- this.open();
2918
+ this.open(false, this.openTrigger);
2873
2919
  return;
2874
2920
  }
2875
2921
  // Strategy-based auto-open logic
@@ -2877,11 +2923,11 @@ export class SallaBulletDelivery {
2877
2923
  case "first_visit":
2878
2924
  // Open once per session when component mounts (per-session behaviour)
2879
2925
  if (!this.hasBeenShownThisSession()) {
2880
- this.open();
2926
+ this.open(false, "first_visit");
2881
2927
  }
2882
2928
  else if (this.shouldPromptIncompleteIntentThisSession()) {
2883
2929
  this.markIncompleteIntentPrompted();
2884
- this.open();
2930
+ this.open(false, "incomplete_intent");
2885
2931
  }
2886
2932
  break;
2887
2933
  case "on_cart_click":
@@ -2889,11 +2935,11 @@ export class SallaBulletDelivery {
2889
2935
  if (Salla.url.is_page("cart")) {
2890
2936
  const shown = this.getShownStorage().get(this.sessionShownKey) === true;
2891
2937
  if (!shown) {
2892
- this.open();
2938
+ this.open(false, "on_cart_click");
2893
2939
  }
2894
2940
  else if (this.shouldPromptIncompleteIntentThisSession()) {
2895
2941
  this.markIncompleteIntentPrompted();
2896
- this.open();
2942
+ this.open(false, "incomplete_intent");
2897
2943
  }
2898
2944
  }
2899
2945
  break;
@@ -2918,6 +2964,7 @@ export class SallaBulletDelivery {
2918
2964
  this.stopWatchingLocationPermission = null;
2919
2965
  }
2920
2966
  Salla.event.off("salla::bullet-delivery.modal.open.requested", this.bulletDeliveryOpenHandler);
2967
+ Salla.event.off("modal::close", this.modalCloseHandler);
2921
2968
  if (this.closeHandler) {
2922
2969
  Salla.event.off("salla::bullet-delivery.modal.close.requested", this.closeHandler);
2923
2970
  this.closeHandler = null;
@@ -3116,16 +3163,25 @@ export class SallaBulletDelivery {
3116
3163
  return {
3117
3164
  "open": {
3118
3165
  "complexType": {
3119
- "signature": "(silent?: boolean) => Promise<void>",
3166
+ "signature": "(silent?: boolean, trigger?: SelectorTrigger) => Promise<void>",
3120
3167
  "parameters": [{
3121
3168
  "name": "silent",
3122
3169
  "type": "boolean",
3123
3170
  "docs": ""
3171
+ }, {
3172
+ "name": "trigger",
3173
+ "type": "\"first_visit\" | \"after_add_to_cart\" | \"on_cart_click\" | \"incomplete_intent\" | \"checkout_gate\" | \"after_login\" | \"customer_requested\"",
3174
+ "docs": ""
3124
3175
  }],
3125
3176
  "references": {
3126
3177
  "Promise": {
3127
3178
  "location": "global",
3128
3179
  "id": "global::Promise"
3180
+ },
3181
+ "SelectorTrigger": {
3182
+ "location": "import",
3183
+ "path": "./selector-tracker",
3184
+ "id": "src/components/salla-bullet-delivery/selector-tracker.ts::SelectorTrigger"
3129
3185
  }
3130
3186
  },
3131
3187
  "return": "Promise<void>"
@@ -0,0 +1,106 @@
1
+ /*!
2
+ * Crafted with ❤ by Salla
3
+ */
4
+ const SESSION_STORAGE_NAME = "sc_selector_session";
5
+ const TRACKING_TIMEOUT_MS = 5000;
6
+ const CLOSE_REASONS = {
7
+ closeButtonClick: "close_button",
8
+ backdropClick: "backdrop",
9
+ };
10
+ export const toCloseReason = (reason) => CLOSE_REASONS[reason ?? ""] ?? "escape";
11
+ const uuid = () => typeof crypto.randomUUID === "function"
12
+ ? crypto.randomUUID()
13
+ : "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => (Number(c) ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (Number(c) / 4)))).toString(16));
14
+ export const allocatedBranchIds = (intent) => {
15
+ const value = intent?.allocation_headers?.["s-scope-allocation-id"] ?? intent?.branch_id;
16
+ const ids = String(value ?? "")
17
+ .split(",")
18
+ .map(Number)
19
+ .filter((id) => Number.isSafeInteger(id) && id > 0);
20
+ return [...new Set(ids)].sort((a, b) => a - b);
21
+ };
22
+ const sameIds = (a, b) => a.length === b.length && a.every((id) => b.includes(id));
23
+ export class SelectorTracker {
24
+ constructor() {
25
+ this.impressionId = null;
26
+ this.visibleAt = 0;
27
+ }
28
+ viewed(context) {
29
+ this.guarded(() => {
30
+ this.impressionId = uuid();
31
+ this.visibleAt = Date.now();
32
+ this.send("Branch Selector Viewed", { ...context });
33
+ });
34
+ }
35
+ dismissed(context, reason, hadAcceptedSelection) {
36
+ this.guarded(() => this.send("Branch Selector Dismissed", {
37
+ ...context,
38
+ close_reason: reason,
39
+ had_accepted_selection: hadAcceptedSelection,
40
+ elapsed_ms: this.visibleAt ? Date.now() - this.visibleAt : 0,
41
+ }));
42
+ }
43
+ result(context, result) {
44
+ this.guarded(() => {
45
+ const session = this.session();
46
+ const seq = session.seq + 1;
47
+ const accepted = result.outcome === "accepted";
48
+ const firstAccepted = session.first_accepted_branch_ids ?? (accepted ? result.new_branch_ids : null);
49
+ // A draft or a failed attempt replaces the stored intent, so the last accepted branches live here.
50
+ const previous = session.last_accepted_branch_ids ?? result.previous_branch_ids;
51
+ this.save({
52
+ ...session,
53
+ seq,
54
+ first_accepted_branch_ids: firstAccepted,
55
+ last_accepted_branch_ids: accepted ? result.new_branch_ids : previous,
56
+ });
57
+ this.send("Branch Selector Completed", {
58
+ ...context,
59
+ ...result,
60
+ previous_branch_ids: previous,
61
+ selection_attempt_id: uuid(),
62
+ selection_seq: seq,
63
+ first_accepted_branch_ids: firstAccepted,
64
+ changed: accepted && previous.length > 0 && !sameIds(previous, result.new_branch_ids),
65
+ });
66
+ });
67
+ }
68
+ guarded(track) {
69
+ try {
70
+ track();
71
+ }
72
+ catch {
73
+ // Tracking must never break the selector.
74
+ }
75
+ }
76
+ send(event, properties) {
77
+ const body = {
78
+ event,
79
+ session_id: this.session().id,
80
+ impression_id: this.impressionId,
81
+ ...properties,
82
+ };
83
+ // Use the configured transport without the SDK's shared notification suppression.
84
+ // Tracking failures stay silent while concurrent customer requests keep their alerts.
85
+ // keepalive lets the request outlive the reload that follows a confirmed selection.
86
+ Promise.resolve(salla.api.axios.post("selector-events", body, {
87
+ timeout: TRACKING_TIMEOUT_MS,
88
+ adapter: ["fetch", "xhr"],
89
+ fetchOptions: { keepalive: true },
90
+ })).catch(() => undefined);
91
+ }
92
+ session() {
93
+ const stored = Salla.storage.session.get(this.storageName());
94
+ if (stored?.id)
95
+ return stored;
96
+ const fresh = { id: uuid(), seq: 0, first_accepted_branch_ids: null };
97
+ this.save(fresh);
98
+ return fresh;
99
+ }
100
+ storageName() {
101
+ return `${SESSION_STORAGE_NAME}:${Salla.config.get("store.id")}`;
102
+ }
103
+ save(session) {
104
+ Salla.storage.session.set(this.storageName(), session);
105
+ }
106
+ }
@@ -93,7 +93,7 @@
93
93
  overflow: hidden;
94
94
  text-overflow: ellipsis;
95
95
  }
96
- .s-free-shipping-banner__chip {
96
+ .s-free-shipping-banner__timer {
97
97
  position: relative;
98
98
  overflow: hidden;
99
99
  flex: none;
@@ -108,11 +108,11 @@
108
108
  white-space: nowrap;
109
109
  background: var(--s-fsb-tint-2);
110
110
  }
111
- .s-free-shipping-banner__chip svg {
111
+ .s-free-shipping-banner__timer svg {
112
112
  inline-size: 15px;
113
113
  block-size: 15px;
114
114
  }
115
- .s-free-shipping-banner__chip::after {
115
+ .s-free-shipping-banner__timer::after {
116
116
  content: "";
117
117
  position: absolute;
118
118
  top: 0;
@@ -124,6 +124,17 @@
124
124
  animation: s-fsb-shine 5s ease-in-out infinite;
125
125
  pointer-events: none;
126
126
  }
127
+ .s-free-shipping-banner__clock {
128
+ font-size: 13.5px;
129
+ font-variant-numeric: tabular-nums;
130
+ font-feature-settings: "tnum";
131
+ direction: ltr;
132
+ unicode-bidi: isolate;
133
+ }
134
+ .s-free-shipping-banner.has-paper .s-free-shipping-banner__timer {
135
+ background: var(--s-fsb-ink);
136
+ color: var(--s-fsb-paper);
137
+ }
127
138
  @media (prefers-reduced-motion: reduce) {
128
139
  .s-free-shipping-banner *, .s-free-shipping-banner *::after {
129
140
  animation: none !important;
@@ -136,7 +147,10 @@
136
147
  -webkit-line-clamp: 2;
137
148
  -webkit-box-orient: vertical;
138
149
  }
139
- .s-free-shipping-banner__chip {
150
+ .s-free-shipping-banner__label {
151
+ display: none;
152
+ }
153
+ .s-free-shipping-banner__timer {
140
154
  padding-inline: 9px;
141
155
  }
142
156
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { isEligibleForFreeShipping } from "../../shared/free-shipping";
6
+ import { getFreeShippingTimerState, isTimerEnabled, startTimerIfNeeded, subscribeToFreeShippingTimer, } from "../../shared/free-shipping-timer";
6
7
  const LABELS = {
7
8
  title: {
8
9
  ar: 'الشحن علينا!',
@@ -12,22 +13,45 @@ const LABELS = {
12
13
  ar: 'لفترة محدودة! تسوّق واستفد من الشحن المجاني',
13
14
  en: 'Shop now and save on delivery for a limited time.',
14
15
  },
15
- limited: {
16
- ar: 'عرض لفترة محدودة',
17
- en: 'Limited-time offer',
16
+ ends_in: {
17
+ ar: 'ينتهي خلال',
18
+ en: 'Ends in',
18
19
  },
19
20
  };
20
- /**
21
- * Non-dismissible banner announcing the store's free shipping offer.
22
- * Where it is rendered (`placement`) decides which banner data is requested, and the
23
- * response decides whether it is shown.
24
- */
21
+ const pad = (n) => (n < 10 ? '0' : '') + n;
22
+ function formatClock(ms) {
23
+ const seconds = Math.max(0, Math.floor(ms / 1000));
24
+ return `${pad(Math.floor(seconds / 3600))}:${pad(Math.floor((seconds % 3600) / 60))}:${pad(seconds % 60)}`;
25
+ }
26
+ function luminance(rgb) {
27
+ const m = /rgba?\((\d+),\s*(\d+),\s*(\d+)/.exec(rgb || '');
28
+ if (!m)
29
+ return null;
30
+ const f = (c) => {
31
+ c /= 255;
32
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
33
+ };
34
+ return 0.2126 * f(+m[1]) + 0.7152 * f(+m[2]) + 0.0722 * f(+m[3]);
35
+ }
36
+ const isTransparent = (bg) => !bg || bg === 'transparent' || /rgba\(\d+,\s*\d+,\s*\d+,\s*0\)/.test(bg);
25
37
  export class SallaFreeShippingBanner {
26
38
  constructor() {
27
39
  /** Where the banner is rendered: the home page or the product page. */
28
40
  this.placement = 'home';
29
41
  this.locale = 'ar';
42
+ /** Whether free shipping applies here (feature on and the eligibility check passed). */
30
43
  this.visible = false;
44
+ this.timer = null;
45
+ this.onColorSchemeChange = () => this.measureInkAndPaper();
46
+ }
47
+ connectedCallback() {
48
+ this.colorScheme = window.matchMedia?.('(prefers-color-scheme: dark)');
49
+ this.colorScheme?.addEventListener?.('change', this.onColorSchemeChange);
50
+ }
51
+ disconnectedCallback() {
52
+ this.unsubscribe?.();
53
+ this.stopTick();
54
+ this.colorScheme?.removeEventListener?.('change', this.onColorSchemeChange);
31
55
  }
32
56
  async componentWillLoad() {
33
57
  try {
@@ -43,21 +67,78 @@ export class SallaFreeShippingBanner {
43
67
  // home: is the store offering free shipping; product page: is this product eligible
44
68
  const productId = this.placement === 'product' ? salla.config.get('page.id') : undefined;
45
69
  this.visible = await isEligibleForFreeShipping(productId);
70
+ if (this.visible) {
71
+ // The visitor sees the banner now: remember when, the first time only.
72
+ startTimerIfNeeded();
73
+ // Only a banner that can show, and has a timer, follows it (to hide at the end and come back after).
74
+ if (isTimerEnabled()) {
75
+ this.unsubscribe = subscribeToFreeShippingTimer(() => this.refreshTimer());
76
+ }
77
+ }
78
+ this.refreshTimer();
46
79
  }
47
80
  catch (e) {
48
81
  salla?.logger?.warn?.('salla-free-shipping-banner: init failed', e);
49
82
  }
50
83
  }
84
+ refreshTimer() {
85
+ this.timer = getFreeShippingTimerState();
86
+ if (this.visible && this.timer?.visible) {
87
+ this.tick = this.tick ?? setInterval(() => this.refreshTimer(), 1000);
88
+ }
89
+ else {
90
+ this.stopTick();
91
+ }
92
+ }
93
+ stopTick() {
94
+ clearInterval(this.tick);
95
+ this.tick = undefined;
96
+ }
97
+ /**
98
+ * The timer chip is drawn from the theme's own colours: solid in the text colour ("ink")
99
+ * with the nearest opaque background behind the banner ("paper") as its text colour.
100
+ */
101
+ measureInkAndPaper() {
102
+ const bar = this.host?.querySelector('.s-free-shipping-banner');
103
+ if (!bar)
104
+ return;
105
+ this.measuredBar = bar;
106
+ const ink = getComputedStyle(bar.parentElement || bar).color;
107
+ let paper = null;
108
+ for (let node = bar.parentElement; node; node = node.parentElement) {
109
+ const bg = getComputedStyle(node).backgroundColor;
110
+ if (!isTransparent(bg)) {
111
+ paper = bg;
112
+ break;
113
+ }
114
+ }
115
+ if (!paper) {
116
+ const l = luminance(ink);
117
+ paper = l != null && l > 0.5 ? '#111418' : '#ffffff';
118
+ }
119
+ bar.style.setProperty('--s-fsb-ink', ink);
120
+ bar.style.setProperty('--s-fsb-paper', paper);
121
+ bar.classList.add('has-paper');
122
+ }
123
+ componentDidRender() {
124
+ // The colours do not change with the countdown: measure once per banner element (it is a new
125
+ // element each time the banner comes back), and again on a colour scheme change.
126
+ const bar = this.host?.querySelector('.s-free-shipping-banner');
127
+ if (bar && bar !== this.measuredBar) {
128
+ this.measureInkAndPaper();
129
+ }
130
+ }
51
131
  /** Store translation wins, the built-in label is the fallback for the current language. */
52
132
  label(name) {
53
133
  const label = LABELS?.[name]?.[this.locale];
54
134
  return salla.lang.getWithDefault?.(`blocks.free_shipping_banner.${name}`, label) || label;
55
135
  }
56
136
  render() {
57
- if (!this.visible) {
137
+ const timer = this.timer;
138
+ if (!this.visible || !timer?.visible) {
58
139
  return null;
59
140
  }
60
- return (h(Host, null, h("div", { class: "container" }, h("section", { class: "s-free-shipping-banner", "aria-label": this.label('title') }, h("div", { class: "s-free-shipping-banner__inner" }, h("svg", { class: "s-free-shipping-banner__icon", viewBox: "0 0 48 32", "aria-hidden": "true" }, h("g", { class: "s-fsb-speed" }, h("path", { class: "s-fsb-line", d: "M3 11h7" }), h("path", { class: "s-fsb-line", d: "M1 16h5" }), h("path", { class: "s-fsb-line", d: "M4 21h6" })), h("g", { class: "s-fsb-body" }, h("rect", { class: "s-fsb-fill", x: "12", y: "5", width: "21", height: "16", rx: "2.5" }), h("path", { class: "s-fsb-fill", d: "M33 10h6.5a2 2 0 0 1 1.6.8l4.1 5.5c.5.7.8 1.5.8 2.4V21H33z" }), h("rect", { class: "s-fsb-fill", x: "12", y: "20", width: "34", height: "3.5", rx: "1.2" }), h("rect", { class: "s-fsb-window", x: "35", y: "12", width: "5.5", height: "4", rx: "1" })), h("circle", { class: "s-fsb-wheel", cx: "19.5", cy: "25.5", r: "3" }), h("circle", { class: "s-fsb-wheel", cx: "38", cy: "25.5", r: "3" })), h("p", { class: "s-free-shipping-banner__text" }, h("strong", null, this.label('title')), h("span", { class: "s-free-shipping-banner__desc" }, this.label('description'))), h("span", { class: "s-free-shipping-banner__chip" }, h("svg", { viewBox: "0 0 24 24", "aria-hidden": "true" }, h("circle", { cx: "12", cy: "13.5", r: "7" }), h("path", { d: "M10 2.5h4M12 2.5v4M12 13.5V9.5M18 7.5l1.5-1.5" })), h("span", null, this.label('limited'))))))));
141
+ return (h(Host, null, h("div", { class: "container" }, h("section", { class: "s-free-shipping-banner", "aria-label": this.label('title') }, h("div", { class: "s-free-shipping-banner__inner" }, h("svg", { class: "s-free-shipping-banner__icon", viewBox: "0 0 48 32", "aria-hidden": "true" }, h("g", { class: "s-fsb-speed" }, h("path", { class: "s-fsb-line", d: "M3 11h7" }), h("path", { class: "s-fsb-line", d: "M1 16h5" }), h("path", { class: "s-fsb-line", d: "M4 21h6" })), h("g", { class: "s-fsb-body" }, h("rect", { class: "s-fsb-fill", x: "12", y: "5", width: "21", height: "16", rx: "2.5" }), h("path", { class: "s-fsb-fill", d: "M33 10h6.5a2 2 0 0 1 1.6.8l4.1 5.5c.5.7.8 1.5.8 2.4V21H33z" }), h("rect", { class: "s-fsb-fill", x: "12", y: "20", width: "34", height: "3.5", rx: "1.2" }), h("rect", { class: "s-fsb-window", x: "35", y: "12", width: "5.5", height: "4", rx: "1" })), h("circle", { class: "s-fsb-wheel", cx: "19.5", cy: "25.5", r: "3" }), h("circle", { class: "s-fsb-wheel", cx: "38", cy: "25.5", r: "3" })), h("p", { class: "s-free-shipping-banner__text" }, h("strong", null, this.label('title')), h("span", { class: "s-free-shipping-banner__desc" }, this.label('description'))), h("span", { class: "s-free-shipping-banner__timer" }, h("svg", { viewBox: "0 0 24 24", "aria-hidden": "true" }, h("circle", { cx: "12", cy: "12", r: "8" }), h("path", { d: "M12 8v4l3 2" })), h("span", { class: "s-free-shipping-banner__label" }, this.label('ends_in')), h("span", { class: "s-free-shipping-banner__clock", role: "timer" }, formatClock(timer.remainingMs))))))));
61
142
  }
62
143
  static get is() { return "salla-free-shipping-banner"; }
63
144
  static get originalStyleUrls() {
@@ -103,7 +184,9 @@ export class SallaFreeShippingBanner {
103
184
  static get states() {
104
185
  return {
105
186
  "locale": {},
106
- "visible": {}
187
+ "visible": {},
188
+ "timer": {}
107
189
  };
108
190
  }
191
+ static get elementRef() { return "host"; }
109
192
  }
@@ -25,3 +25,9 @@
25
25
  stroke-linecap: round;
26
26
  stroke-linejoin: round;
27
27
  }
28
+ .visible {
29
+ visibility: visible;
30
+ }
31
+ .hidden {
32
+ display: none;
33
+ }
@@ -3,9 +3,11 @@
3
3
  */
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { isEligibleForFreeShipping } from "../../shared/free-shipping";
6
+ import { getFreeShippingTimerState, isTimerEnabled, subscribeToFreeShippingTimer } from "../../shared/free-shipping-timer";
6
7
  /**
7
8
  * Small "free shipping" tag for a product. Meant to be placed below the price in any
8
- * product card.
9
+ * product card. It follows the free shipping banner: while the banner's countdown is over and the
10
+ * banner is hidden, the tag is hidden too.
9
11
  */
10
12
  export class SallaFreeShippingTag {
11
13
  constructor() {
@@ -14,13 +16,26 @@ export class SallaFreeShippingTag {
14
16
  /** With `fromProductCard`, whether the tag is shown. */
15
17
  this.showFreeShipping = false;
16
18
  this.isFree = false;
19
+ this.timerHidden = false;
17
20
  this.label = '';
18
21
  }
22
+ disconnectedCallback() {
23
+ this.unsubscribe?.();
24
+ }
25
+ // The banner records when the visitor first saw it. Until then, or with the feature off, nothing hides the tag.
26
+ refreshTimer() {
27
+ this.timerHidden = getFreeShippingTimerState()?.visible === false;
28
+ }
19
29
  async componentWillLoad() {
20
30
  try {
21
31
  await salla.onReady();
22
32
  await salla.lang.onLoaded();
23
33
  const fallback = salla.lang.getLocale?.() === 'en' ? 'Free shipping' : 'شحن مجاني';
34
+ // Only follow the timer when there is one (feature on and timer settings present).
35
+ if (isTimerEnabled()) {
36
+ this.unsubscribe = subscribeToFreeShippingTimer(() => this.refreshTimer());
37
+ }
38
+ this.refreshTimer();
24
39
  this.label =
25
40
  salla.lang.getWithDefault?.('pages.products.free_shipping', fallback) || fallback;
26
41
  if (this.fromProductCard) {
@@ -35,7 +50,7 @@ export class SallaFreeShippingTag {
35
50
  }
36
51
  }
37
52
  render() {
38
- if (!this.isFree) {
53
+ if (!this.isFree || this.timerHidden) {
39
54
  return null;
40
55
  }
41
56
  return (h(Host, null, h("div", { class: "s-free-shipping-tag" }, h("svg", { viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { d: "M3 6.5h11v9H3zM14 9.5h3.6l2.9 3.2v2.8H14" }), h("circle", { cx: "7.5", cy: "17", r: "1.8" }), h("circle", { cx: "17", cy: "17", r: "1.8" })), h("span", { class: "s-free-shipping-tag-label" }, this.label))));
@@ -117,6 +132,7 @@ export class SallaFreeShippingTag {
117
132
  static get states() {
118
133
  return {
119
134
  "isFree": {},
135
+ "timerHidden": {},
120
136
  "label": {}
121
137
  };
122
138
  }