@vtex/faststore 0.0.8 → 0.0.11

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 (568) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +0 -1
  3. package/dist/actions.json +48 -1
  4. package/dist/catalog.json +1397 -1594
  5. package/dist/cli/index.d.ts +66 -28
  6. package/dist/cli/index.js +7371 -512
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/server-runtime.js +41 -60
  9. package/dist/cli/server-runtime.js.map +1 -1
  10. package/dist/client.d.ts +3 -3
  11. package/dist/client.js +2 -2
  12. package/dist/components.d.ts +67 -56
  13. package/dist/components.js +64 -53
  14. package/dist/content-types.json +5886 -555
  15. package/dist/core/dist/define-component.d.ts +7 -2
  16. package/dist/core/dist/define-content-type.d.ts +50 -2
  17. package/dist/core/dist/define-content-type.js +107 -3
  18. package/dist/core/dist/define-content-type.js.map +1 -1
  19. package/dist/core/dist/index.d.ts +2 -2
  20. package/dist/docs/access-code-field.md +1 -1
  21. package/dist/docs/access-code-sign-in.md +126 -77
  22. package/dist/docs/account-address-book.md +210 -95
  23. package/dist/docs/account-entry-point.md +4 -4
  24. package/dist/docs/account-menu.md +16 -17
  25. package/dist/docs/account-saved-cards.md +306 -0
  26. package/dist/docs/alert-dialog.md +3 -1
  27. package/dist/docs/avatar.md +4 -2
  28. package/dist/docs/billing-address.md +99 -30
  29. package/dist/docs/binding-switcher.md +157 -0
  30. package/dist/docs/buy-button.md +7 -8
  31. package/dist/docs/card-entry.md +42 -29
  32. package/dist/docs/card-summary.md +185 -0
  33. package/dist/docs/cardholder-document.md +5 -3
  34. package/dist/docs/carousel.md +5 -4
  35. package/dist/docs/cart-destination.md +251 -0
  36. package/dist/docs/cart-item.md +48 -15
  37. package/dist/docs/cart-totalizer.md +8 -6
  38. package/dist/docs/cart.md +240 -39
  39. package/dist/docs/challenge-return.md +135 -0
  40. package/dist/docs/client-preferences-fieldset.md +10 -5
  41. package/dist/docs/client-preferences.md +31 -8
  42. package/dist/docs/client-profile-fieldset.md +20 -6
  43. package/dist/docs/client-profile.md +12 -3
  44. package/dist/docs/copy-text.md +9 -7
  45. package/dist/docs/document-field.md +1 -1
  46. package/dist/docs/email-field.md +2 -1
  47. package/dist/docs/email-identification.md +12 -2
  48. package/dist/docs/footer-copyright.md +4 -2
  49. package/dist/docs/footer-social.md +1 -1
  50. package/dist/docs/form.md +54 -18
  51. package/dist/docs/free-shipping-progress.md +18 -13
  52. package/dist/docs/identity-edit.md +8 -2
  53. package/dist/docs/identity-summary.md +18 -5
  54. package/dist/docs/incentives.md +2 -2
  55. package/dist/docs/installments.md +46 -32
  56. package/dist/docs/logo.md +1 -1
  57. package/dist/docs/my-account-profile.md +16 -11
  58. package/dist/docs/navigation-link.md +5 -3
  59. package/dist/docs/order-cancel.md +3 -1
  60. package/dist/docs/order-delivery-address.md +7 -5
  61. package/dist/docs/order-delivery-group.md +1 -3
  62. package/dist/docs/order-details-back.md +1 -1
  63. package/dist/docs/order-details-header.md +1 -4
  64. package/dist/docs/order-invoice-download.md +60 -0
  65. package/dist/docs/order-list-row.md +1 -1
  66. package/dist/docs/order-list-search.md +13 -20
  67. package/dist/docs/order-list-views.md +11 -17
  68. package/dist/docs/order-list.md +12 -5
  69. package/dist/docs/order-payment.md +9 -7
  70. package/dist/docs/order-placed-date.md +1 -1
  71. package/dist/docs/order-placed-payment-summary.md +28 -15
  72. package/dist/docs/order-placed.md +49 -14
  73. package/dist/docs/order-progress.md +1 -1
  74. package/dist/docs/order-status-badge.md +20 -9
  75. package/dist/docs/order-summary.md +2 -2
  76. package/dist/docs/order-tracking-link.md +58 -0
  77. package/dist/docs/payment-method-badges.md +32 -6
  78. package/dist/docs/payment-methods.md +2 -2
  79. package/dist/docs/payment.md +36 -17
  80. package/dist/docs/phone-field.md +4 -4
  81. package/dist/docs/place-order.md +84 -36
  82. package/dist/docs/postal-code-field.md +3 -1
  83. package/dist/docs/pricing.md +21 -23
  84. package/dist/docs/product-gallery.md +19 -20
  85. package/dist/docs/product-information.md +14 -10
  86. package/dist/docs/product-list.md +7 -6
  87. package/dist/docs/product-shelf.md +7 -1
  88. package/dist/docs/promotion.md +4 -2
  89. package/dist/docs/region.md +23 -15
  90. package/dist/docs/save-card.md +7 -6
  91. package/dist/docs/saved-cards.md +65 -36
  92. package/dist/docs/select.md +3 -4
  93. package/dist/docs/shipping-address.md +57 -21
  94. package/dist/docs/shipping-simulator.md +53 -15
  95. package/dist/docs/sign-in-disclosure.md +176 -0
  96. package/dist/docs/sign-in-form.md +78 -47
  97. package/dist/docs/sign-in-redirect.md +5 -3
  98. package/dist/docs/sign-in.md +173 -0
  99. package/dist/docs/toast.md +45 -16
  100. package/dist/docs/variant-selector.md +15 -11
  101. package/dist/graphql/types.d.ts +4 -14
  102. package/dist/index.d.ts +3 -2
  103. package/dist/internal/client.d.ts +4 -3
  104. package/dist/internal/client.js +5 -2
  105. package/dist/internal/server.d.ts +10 -5
  106. package/dist/internal/server.js +9 -4
  107. package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +250 -66
  108. package/dist/matter/access-code-sign-in/access-code-sign-in.js +459 -188
  109. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  110. package/dist/matter/account-address-book/account-address-book-delete.d.ts +78 -40
  111. package/dist/matter/account-address-book/account-address-book-delete.js +86 -50
  112. package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -1
  113. package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +21 -4
  114. package/dist/matter/account-address-book/account-address-book-deliverability.js +45 -17
  115. package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -1
  116. package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +74 -19
  117. package/dist/matter/account-address-book/account-address-book-form-parts.js +77 -26
  118. package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -1
  119. package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +27 -6
  120. package/dist/matter/account-address-book/account-address-book-profile-notice.js +55 -28
  121. package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -1
  122. package/dist/matter/account-address-book/account-address-book.d.ts +67 -14
  123. package/dist/matter/account-address-book/account-address-book.js +74 -33
  124. package/dist/matter/account-address-book/account-address-book.js.map +1 -1
  125. package/dist/matter/account-address-book/account-address-country-switch.js +3 -3
  126. package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -1
  127. package/dist/matter/account-address-book/account-address-country.d.ts +66 -20
  128. package/dist/matter/account-address-book/account-address-country.js +83 -49
  129. package/dist/matter/account-address-book/account-address-country.js.map +1 -1
  130. package/dist/matter/account-address-book/account-address-form-context.d.ts +8 -4
  131. package/dist/matter/account-address-book/account-address-form-context.js.map +1 -1
  132. package/dist/matter/account-address-book/account-address-form.d.ts +468 -45
  133. package/dist/matter/account-address-book/account-address-form.js +518 -155
  134. package/dist/matter/account-address-book/account-address-form.js.map +1 -1
  135. package/dist/matter/account-address-book/account-address-record.d.ts +27 -6
  136. package/dist/matter/account-address-book/account-address-record.js +32 -17
  137. package/dist/matter/account-address-book/account-address-record.js.map +1 -1
  138. package/dist/matter/account-menu/account-menu.d.ts +34 -17
  139. package/dist/matter/account-menu/account-menu.js +46 -54
  140. package/dist/matter/account-menu/account-menu.js.map +1 -1
  141. package/dist/matter/account-menu-identity/account-menu-identity.js +1 -1
  142. package/dist/matter/account-saved-cards/account-saved-cards.d.ts +463 -0
  143. package/dist/matter/account-saved-cards/account-saved-cards.js +1011 -0
  144. package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
  145. package/dist/matter/billing-address/billing-address.d.ts +156 -74
  146. package/dist/matter/billing-address/billing-address.js +227 -156
  147. package/dist/matter/billing-address/billing-address.js.map +1 -1
  148. package/dist/matter/breadcrumb/breadcrumb.d.ts +21 -3
  149. package/dist/matter/breadcrumb/breadcrumb.js +24 -9
  150. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
  151. package/dist/matter/buy-button/buy-button.d.ts +8 -11
  152. package/dist/matter/buy-button/buy-button.js +10 -19
  153. package/dist/matter/buy-button/buy-button.js.map +1 -1
  154. package/dist/matter/card-entry/card-capture.js +12 -4
  155. package/dist/matter/card-entry/card-capture.js.map +1 -1
  156. package/dist/matter/card-entry/card-entry.d.ts +123 -32
  157. package/dist/matter/card-entry/card-entry.js +348 -221
  158. package/dist/matter/card-entry/card-entry.js.map +1 -1
  159. package/dist/matter/cart/cart-namespace.d.ts +11 -1
  160. package/dist/matter/cart/cart-namespace.js +11 -1
  161. package/dist/matter/cart/cart-namespace.js.map +1 -1
  162. package/dist/matter/cart/cart.d.ts +416 -45
  163. package/dist/matter/cart/cart.js +782 -101
  164. package/dist/matter/cart/cart.js.map +1 -1
  165. package/dist/matter/cart-destination/cart-destination.d.ts +233 -0
  166. package/dist/matter/cart-destination/cart-destination.js +703 -0
  167. package/dist/matter/cart-destination/cart-destination.js.map +1 -0
  168. package/dist/matter/cart-item/cart-item.d.ts +145 -16
  169. package/dist/matter/cart-item/cart-item.js +230 -54
  170. package/dist/matter/cart-item/cart-item.js.map +1 -1
  171. package/dist/matter/cart-item-compositions/cart-item-compositions.js +1 -1
  172. package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -1
  173. package/dist/matter/cart-item-customizations/cart-item-customizations.js +1 -1
  174. package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -1
  175. package/dist/matter/cart-item-discounts/cart-item-discounts.js +1 -1
  176. package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -1
  177. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +1 -1
  178. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -1
  179. package/dist/matter/cart-item-variations/cart-item-variations.js +1 -1
  180. package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -1
  181. package/dist/matter/cart-totalizer/cart-totalizer.d.ts +43 -9
  182. package/dist/matter/cart-totalizer/cart-totalizer.js +49 -19
  183. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
  184. package/dist/matter/challenge-return/challenge-return.d.ts +62 -0
  185. package/dist/matter/challenge-return/challenge-return.js +241 -0
  186. package/dist/matter/challenge-return/challenge-return.js.map +1 -0
  187. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +86 -17
  188. package/dist/matter/client-preferences/client-preferences-fieldset.js +126 -54
  189. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -1
  190. package/dist/matter/client-preferences/client-preferences.d.ts +50 -7
  191. package/dist/matter/client-preferences/client-preferences.js +84 -15
  192. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  193. package/dist/matter/client-profile/client-profile.d.ts +44 -9
  194. package/dist/matter/client-profile/client-profile.js +64 -24
  195. package/dist/matter/client-profile/client-profile.js.map +1 -1
  196. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -22
  197. package/dist/matter/client-profile-form/client-profile-fieldset.js +161 -73
  198. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
  199. package/dist/matter/delivery-options/delivery-options-accordion.d.ts +49 -4
  200. package/dist/matter/delivery-options/delivery-options-accordion.js +67 -14
  201. package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -1
  202. package/dist/matter/delivery-options/delivery-options-controller.d.ts +69 -9
  203. package/dist/matter/delivery-options/delivery-options-controller.js +80 -14
  204. package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -1
  205. package/dist/matter/delivery-options/delivery-options.d.ts +37 -2
  206. package/dist/matter/delivery-options/delivery-options.js +75 -12
  207. package/dist/matter/delivery-options/delivery-options.js.map +1 -1
  208. package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +1 -0
  209. package/dist/matter/delivery-options/use-delivery-option-selection.js +1 -1
  210. package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -1
  211. package/dist/matter/email-identification/email-identification.d.ts +25 -3
  212. package/dist/matter/email-identification/email-identification.js +49 -12
  213. package/dist/matter/email-identification/email-identification.js.map +1 -1
  214. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +85 -10
  215. package/dist/matter/free-shipping-progress/free-shipping-progress.js +153 -53
  216. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
  217. package/dist/matter/identity-edit/identity-edit.d.ts +52 -10
  218. package/dist/matter/identity-edit/identity-edit.js +47 -19
  219. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  220. package/dist/matter/identity-summary/identity-summary.d.ts +76 -22
  221. package/dist/matter/identity-summary/identity-summary.js +95 -45
  222. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  223. package/dist/matter/installments/installments-select.d.ts +98 -16
  224. package/dist/matter/installments/installments-select.js +156 -48
  225. package/dist/matter/installments/installments-select.js.map +1 -1
  226. package/dist/matter/installments/installments.d.ts +96 -16
  227. package/dist/matter/installments/installments.js +115 -40
  228. package/dist/matter/installments/installments.js.map +1 -1
  229. package/dist/matter/installments/use-installments-selection.d.ts +1 -0
  230. package/dist/matter/installments/use-installments-selection.js +8 -3
  231. package/dist/matter/installments/use-installments-selection.js.map +1 -1
  232. package/dist/matter/my-account-profile/my-account-profile.d.ts +358 -103
  233. package/dist/matter/my-account-profile/my-account-profile.js +370 -174
  234. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  235. package/dist/matter/order-cancel/order-cancel.d.ts +65 -19
  236. package/dist/matter/order-cancel/order-cancel.js +118 -51
  237. package/dist/matter/order-cancel/order-cancel.js.map +1 -1
  238. package/dist/matter/order-delivery-address/order-delivery-address.d.ts +8 -18
  239. package/dist/matter/order-delivery-address/order-delivery-address.js +14 -23
  240. package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -1
  241. package/dist/matter/order-delivery-group/order-delivery-group.d.ts +40 -24
  242. package/dist/matter/order-delivery-group/order-delivery-group.js +64 -74
  243. package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -1
  244. package/dist/matter/order-details-header/order-details-header.d.ts +32 -15
  245. package/dist/matter/order-details-header/order-details-header.js +66 -58
  246. package/dist/matter/order-details-header/order-details-header.js.map +1 -1
  247. package/dist/matter/order-invoice-download/order-invoice-download.d.ts +78 -0
  248. package/dist/matter/order-invoice-download/order-invoice-download.js +173 -0
  249. package/dist/matter/order-invoice-download/order-invoice-download.js.map +1 -0
  250. package/dist/matter/order-list/order-list.d.ts +164 -19
  251. package/dist/matter/order-list/order-list.js +229 -87
  252. package/dist/matter/order-list/order-list.js.map +1 -1
  253. package/dist/matter/order-list-row/order-list-row.d.ts +6 -1
  254. package/dist/matter/order-list-row/order-list-row.js +3 -2
  255. package/dist/matter/order-list-row/order-list-row.js.map +1 -1
  256. package/dist/matter/order-list-search/order-list-search.d.ts +18 -26
  257. package/dist/matter/order-list-search/order-list-search.js +30 -69
  258. package/dist/matter/order-list-search/order-list-search.js.map +1 -1
  259. package/dist/matter/order-list-views/order-list-views.d.ts +15 -22
  260. package/dist/matter/order-list-views/order-list-views.js +22 -68
  261. package/dist/matter/order-list-views/order-list-views.js.map +1 -1
  262. package/dist/matter/order-payment/order-payment.d.ts +33 -10
  263. package/dist/matter/order-payment/order-payment.js +44 -39
  264. package/dist/matter/order-payment/order-payment.js.map +1 -1
  265. package/dist/matter/order-placed/order-placed-deliveries.d.ts +144 -12
  266. package/dist/matter/order-placed/order-placed-deliveries.js +115 -40
  267. package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -1
  268. package/dist/matter/order-placed/order-placed.d.ts +198 -31
  269. package/dist/matter/order-placed/order-placed.js +230 -139
  270. package/dist/matter/order-placed/order-placed.js.map +1 -1
  271. package/dist/matter/order-placed-date/order-placed-date.d.ts +5 -8
  272. package/dist/matter/order-placed-date/order-placed-date.js +7 -8
  273. package/dist/matter/order-placed-date/order-placed-date.js.map +1 -1
  274. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +90 -17
  275. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +93 -117
  276. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
  277. package/dist/matter/order-progress/order-progress.d.ts +19 -8
  278. package/dist/matter/order-progress/order-progress.js +37 -45
  279. package/dist/matter/order-progress/order-progress.js.map +1 -1
  280. package/dist/matter/order-summary/order-summary.d.ts +19 -9
  281. package/dist/matter/order-summary/order-summary.js +38 -44
  282. package/dist/matter/order-summary/order-summary.js.map +1 -1
  283. package/dist/matter/order-tracking-link/order-tracking-link.d.ts +43 -0
  284. package/dist/matter/order-tracking-link/order-tracking-link.js +107 -0
  285. package/dist/matter/order-tracking-link/order-tracking-link.js.map +1 -0
  286. package/dist/matter/payment/payment-card-capture.js +17 -10
  287. package/dist/matter/payment/payment-card-capture.js.map +1 -1
  288. package/dist/matter/payment/payment-controller.d.ts +4 -2
  289. package/dist/matter/payment/payment-controller.js +30 -9
  290. package/dist/matter/payment/payment-controller.js.map +1 -1
  291. package/dist/matter/payment/payment-method-badges.js +1 -1
  292. package/dist/matter/payment/payment.d.ts +69 -19
  293. package/dist/matter/payment/payment.js +101 -35
  294. package/dist/matter/payment/payment.js.map +1 -1
  295. package/dist/matter/payment/use-payment-method-selection.d.ts +25 -4
  296. package/dist/matter/payment/use-payment-method-selection.js +94 -32
  297. package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
  298. package/dist/matter/payment/use-payment-submit-gate.d.ts +14 -3
  299. package/dist/matter/payment/use-payment-submit-gate.js +47 -8
  300. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
  301. package/dist/matter/place-order/place-order.d.ts +171 -57
  302. package/dist/matter/place-order/place-order.js +376 -185
  303. package/dist/matter/place-order/place-order.js.map +1 -1
  304. package/dist/matter/pricing/pricing.d.ts +152 -13
  305. package/dist/matter/pricing/pricing.js +153 -52
  306. package/dist/matter/pricing/pricing.js.map +1 -1
  307. package/dist/matter/product-information/product-information.d.ts +27 -4
  308. package/dist/matter/product-information/product-information.js +32 -15
  309. package/dist/matter/product-information/product-information.js.map +1 -1
  310. package/dist/matter/product-list/product-list.d.ts +24 -6
  311. package/dist/matter/product-list/product-list.js +32 -26
  312. package/dist/matter/product-list/product-list.js.map +1 -1
  313. package/dist/matter/product-shelf/product-shelf.d.ts +8 -3
  314. package/dist/matter/product-shelf/product-shelf.js +111 -10
  315. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  316. package/dist/matter/region/region.d.ts +33 -16
  317. package/dist/matter/region/region.js +59 -52
  318. package/dist/matter/region/region.js.map +1 -1
  319. package/dist/matter/save-card/save-card.d.ts +43 -8
  320. package/dist/matter/save-card/save-card.js +61 -23
  321. package/dist/matter/save-card/save-card.js.map +1 -1
  322. package/dist/matter/saved-cards/saved-cards.d.ts +113 -21
  323. package/dist/matter/saved-cards/saved-cards.js +349 -77
  324. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  325. package/dist/matter/shipping-address/address-payload.js +25 -0
  326. package/dist/matter/shipping-address/address-payload.js.map +1 -0
  327. package/dist/matter/shipping-address/country-descriptors.js +71 -71
  328. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  329. package/dist/matter/shipping-address/library-country-descriptors.js +136 -0
  330. package/dist/matter/shipping-address/library-country-descriptors.js.map +1 -0
  331. package/dist/matter/shipping-address/shipping-address.d.ts +312 -45
  332. package/dist/matter/shipping-address/shipping-address.js +443 -188
  333. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  334. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +251 -25
  335. package/dist/matter/shipping-simulator/shipping-simulator.js +261 -51
  336. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  337. package/dist/matter/sign-in/sign-in.d.ts +108 -0
  338. package/dist/matter/sign-in/sign-in.js +285 -0
  339. package/dist/matter/sign-in/sign-in.js.map +1 -0
  340. package/dist/matter/sign-in-disclosure/sign-in-disclosure.d.ts +81 -0
  341. package/dist/matter/sign-in-disclosure/sign-in-disclosure.js +232 -0
  342. package/dist/matter/sign-in-disclosure/sign-in-disclosure.js.map +1 -0
  343. package/dist/matter/sign-in-form/sign-in-form.d.ts +93 -62
  344. package/dist/matter/sign-in-form/sign-in-form.js +134 -144
  345. package/dist/matter/sign-in-form/sign-in-form.js.map +1 -1
  346. package/dist/particles/binding-switcher/binding-switcher.d.ts +59 -0
  347. package/dist/particles/binding-switcher/binding-switcher.js +194 -0
  348. package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
  349. package/dist/particles/card-summary/card-network.d.ts +17 -0
  350. package/dist/particles/card-summary/card-network.js +25 -0
  351. package/dist/particles/card-summary/card-network.js.map +1 -0
  352. package/dist/particles/card-summary/card-summary.d.ts +113 -0
  353. package/dist/particles/card-summary/card-summary.js +221 -0
  354. package/dist/particles/card-summary/card-summary.js.map +1 -0
  355. package/dist/particles/carousel/carousel.d.ts +99 -11
  356. package/dist/particles/carousel/carousel.js +103 -35
  357. package/dist/particles/carousel/carousel.js.map +1 -1
  358. package/dist/particles/copy-text/copy-text.js +5 -15
  359. package/dist/particles/copy-text/copy-text.js.map +1 -1
  360. package/dist/particles/dialog/dialog.d.ts +14 -6
  361. package/dist/particles/dialog/dialog.js +6 -3
  362. package/dist/particles/dialog/dialog.js.map +1 -1
  363. package/dist/particles/drawer/drawer.js +1 -1
  364. package/dist/particles/drawer/drawer.js.map +1 -1
  365. package/dist/particles/email-field/email-field.d.ts +2 -1
  366. package/dist/particles/email-field/email-field.js +2 -1
  367. package/dist/particles/email-field/email-field.js.map +1 -1
  368. package/dist/particles/footer-link-group/footer-link-group.js +1 -0
  369. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
  370. package/dist/particles/footer-social/footer-social.d.ts +1 -1
  371. package/dist/particles/footer-social/footer-social.js +1 -1
  372. package/dist/particles/footer-social/footer-social.js.map +1 -1
  373. package/dist/particles/form/form.d.ts +85 -13
  374. package/dist/particles/form/form.js +91 -42
  375. package/dist/particles/form/form.js.map +1 -1
  376. package/dist/particles/gallery/gallery.d.ts +129 -12
  377. package/dist/particles/gallery/gallery.js +121 -34
  378. package/dist/particles/gallery/gallery.js.map +1 -1
  379. package/dist/particles/incentives/incentives.d.ts +1 -1
  380. package/dist/particles/incentives/incentives.js +1 -1
  381. package/dist/particles/incentives/incentives.js.map +1 -1
  382. package/dist/particles/order-details-back/order-details-back.d.ts +5 -3
  383. package/dist/particles/order-details-back/order-details-back.js +8 -10
  384. package/dist/particles/order-details-back/order-details-back.js.map +1 -1
  385. package/dist/particles/order-status-badge/order-status-badge.d.ts +3 -3
  386. package/dist/particles/order-status-badge/order-status-badge.js +4 -20
  387. package/dist/particles/order-status-badge/order-status-badge.js.map +1 -1
  388. package/dist/particles/password-field/password-field.d.ts +1 -1
  389. package/dist/particles/password-field/password-field.js +2 -4
  390. package/dist/particles/password-field/password-field.js.map +1 -1
  391. package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
  392. package/dist/particles/payment-methods/payment-methods.js +1 -1
  393. package/dist/particles/payment-methods/payment-methods.js.map +1 -1
  394. package/dist/particles/phone-field/phone-field.d.ts +4 -4
  395. package/dist/particles/phone-field/phone-field.js +8 -11
  396. package/dist/particles/phone-field/phone-field.js.map +1 -1
  397. package/dist/particles/spinner/spinner.d.ts +24 -4
  398. package/dist/particles/spinner/spinner.js +25 -9
  399. package/dist/particles/spinner/spinner.js.map +1 -1
  400. package/dist/particles/switch/switch.d.ts +4 -1
  401. package/dist/particles/switch/switch.js +3 -1
  402. package/dist/particles/switch/switch.js.map +1 -1
  403. package/dist/particles/toast/toast.d.ts +49 -9
  404. package/dist/particles/toast/toast.js +81 -15
  405. package/dist/particles/toast/toast.js.map +1 -1
  406. package/dist/schema.graphql +461 -89
  407. package/dist/sdk/actions/index.d.ts +3 -1
  408. package/dist/sdk/actions/index.js +3 -1
  409. package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
  410. package/dist/sdk/actions/locale-action-provider.js +20 -0
  411. package/dist/sdk/actions/locale-action-provider.js.map +1 -0
  412. package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
  413. package/dist/sdk/actions/saved-card-action-provider.js +16 -0
  414. package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
  415. package/dist/sdk/actions/types.d.ts +6 -2
  416. package/dist/sdk/address/address-fields.js +4 -4
  417. package/dist/sdk/address/address-fields.js.map +1 -1
  418. package/dist/sdk/address/constants.js +1 -6
  419. package/dist/sdk/address/constants.js.map +1 -1
  420. package/dist/sdk/address/messages.js +44 -44
  421. package/dist/sdk/address/messages.js.map +1 -1
  422. package/dist/sdk/address/postal-code.js +15 -2
  423. package/dist/sdk/address/postal-code.js.map +1 -1
  424. package/dist/sdk/address/types.d.ts +5 -3
  425. package/dist/sdk/address/validate-address.js +3 -3
  426. package/dist/sdk/address/validate-address.js.map +1 -1
  427. package/dist/sdk/analytics/use-analytics-actions.d.ts +1 -1
  428. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
  429. package/dist/sdk/cache/storefront-cache.js +2 -1
  430. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  431. package/dist/sdk/cart/operations.d.ts +2 -1
  432. package/dist/sdk/cart/operations.js +55 -1
  433. package/dist/sdk/cart/operations.js.map +1 -1
  434. package/dist/sdk/cart/optimistic.d.ts +30 -7
  435. package/dist/sdk/cart/optimistic.js +78 -41
  436. package/dist/sdk/cart/optimistic.js.map +1 -1
  437. package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
  438. package/dist/sdk/cart/use-cart-actions.js +61 -15
  439. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  440. package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
  441. package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
  442. package/dist/sdk/data/index.js +2 -2
  443. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  444. package/dist/sdk/generated/gql.js +16 -12
  445. package/dist/sdk/generated/gql.js.map +1 -1
  446. package/dist/sdk/generated/graphql.d.ts +197 -51
  447. package/dist/sdk/generated/graphql.js +2318 -91
  448. package/dist/sdk/generated/graphql.js.map +1 -1
  449. package/dist/sdk/i18n/format-error-code.js +23 -0
  450. package/dist/sdk/i18n/format-error-code.js.map +1 -0
  451. package/dist/sdk/i18n/message-formatter.d.ts +22 -0
  452. package/dist/sdk/i18n/message-formatter.js +140 -0
  453. package/dist/sdk/i18n/message-formatter.js.map +1 -0
  454. package/dist/sdk/i18n/use-message-formatter.d.ts +8 -0
  455. package/dist/sdk/i18n/use-message-formatter.js +18 -0
  456. package/dist/sdk/i18n/use-message-formatter.js.map +1 -0
  457. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  458. package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
  459. package/dist/sdk/locale/binding-switch-provider.js +20 -0
  460. package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
  461. package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
  462. package/dist/sdk/locale/use-locale-actions.js +70 -0
  463. package/dist/sdk/locale/use-locale-actions.js.map +1 -0
  464. package/dist/sdk/navigation/binding-switch.d.ts +39 -0
  465. package/dist/sdk/navigation/binding-switch.js +129 -0
  466. package/dist/sdk/navigation/binding-switch.js.map +1 -0
  467. package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
  468. package/dist/sdk/navigation/decode-route-params.js +32 -0
  469. package/dist/sdk/navigation/decode-route-params.js.map +1 -0
  470. package/dist/sdk/navigation/redirect.d.ts +2 -0
  471. package/dist/sdk/navigation/redirect.js +19 -1
  472. package/dist/sdk/navigation/redirect.js.map +1 -1
  473. package/dist/sdk/navigation/types.d.ts +13 -0
  474. package/dist/sdk/payment/bin-format.js +20 -0
  475. package/dist/sdk/payment/bin-format.js.map +1 -0
  476. package/dist/sdk/payment/challenge-return.js +37 -0
  477. package/dist/sdk/payment/challenge-return.js.map +1 -0
  478. package/dist/sdk/payment/confirmation-last-four.js +39 -0
  479. package/dist/sdk/payment/confirmation-last-four.js.map +1 -0
  480. package/dist/sdk/payment/gateway.d.ts +1 -1
  481. package/dist/sdk/payment/gateway.js +8 -2
  482. package/dist/sdk/payment/gateway.js.map +1 -1
  483. package/dist/sdk/payment/operations.d.ts +1 -0
  484. package/dist/sdk/payment/operations.js +28 -6
  485. package/dist/sdk/payment/operations.js.map +1 -1
  486. package/dist/sdk/payment/resumed-purchase.d.ts +1 -0
  487. package/dist/sdk/payment/resumed-purchase.js +119 -0
  488. package/dist/sdk/payment/resumed-purchase.js.map +1 -0
  489. package/dist/sdk/payment/security-code-mask.js +16 -23
  490. package/dist/sdk/payment/security-code-mask.js.map +1 -1
  491. package/dist/sdk/payment/submission-registry.js +6 -2
  492. package/dist/sdk/payment/submission-registry.js.map +1 -1
  493. package/dist/sdk/payment/use-payment-actions.d.ts +18 -3
  494. package/dist/sdk/payment/use-payment-actions.js +23 -3
  495. package/dist/sdk/payment/use-payment-actions.js.map +1 -1
  496. package/dist/sdk/payment/use-place-order.d.ts +10 -2
  497. package/dist/sdk/payment/use-place-order.js +138 -76
  498. package/dist/sdk/payment/use-place-order.js.map +1 -1
  499. package/dist/sdk/provider/storefront-provider.d.ts +1 -7
  500. package/dist/sdk/provider/storefront-provider.js +4 -11
  501. package/dist/sdk/provider/storefront-provider.js.map +1 -1
  502. package/dist/sdk/saved-cards/operations.d.ts +16 -0
  503. package/dist/sdk/saved-cards/operations.js +41 -0
  504. package/dist/sdk/saved-cards/operations.js.map +1 -0
  505. package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
  506. package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
  507. package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
  508. package/dist/sdk/seo/entity-landing.d.ts +24 -0
  509. package/dist/sdk/seo/entity-landing.js +30 -0
  510. package/dist/sdk/seo/entity-landing.js.map +1 -0
  511. package/dist/sdk/seo/page-alternates.d.ts +8 -5
  512. package/dist/sdk/seo/page-alternates.js +11 -14
  513. package/dist/sdk/seo/page-alternates.js.map +1 -1
  514. package/dist/sdk/seo/search-landing.d.ts +42 -0
  515. package/dist/sdk/seo/search-landing.js +85 -0
  516. package/dist/sdk/seo/search-landing.js.map +1 -0
  517. package/dist/sdk/session/mock-session.d.ts +9 -0
  518. package/dist/sdk/session/mock-session.js +31 -0
  519. package/dist/sdk/session/mock-session.js.map +1 -0
  520. package/dist/sdk/session/read-server-session.d.ts +3 -0
  521. package/dist/sdk/session/read-server-session.js +5 -0
  522. package/dist/sdk/session/read-server-session.js.map +1 -1
  523. package/dist/sdk/session/return-path-segment.d.ts +10 -0
  524. package/dist/sdk/session/return-path-segment.js +15 -0
  525. package/dist/sdk/session/return-path-segment.js.map +1 -0
  526. package/dist/sdk/session/use-session-actions.js.map +1 -1
  527. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  528. package/dist/sdk/shipping/shipping-operations.js +13 -0
  529. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  530. package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -1
  531. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
  532. package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -1
  533. package/dist/sdk/state/cart.d.ts +9 -2
  534. package/dist/sdk/state/cart.js +9 -2
  535. package/dist/sdk/state/cart.js.map +1 -1
  536. package/dist/utils/safe-href.d.ts +2 -0
  537. package/package.json +4 -3
  538. package/skills/storefront-asset/SKILL.md +2 -2
  539. package/skills/storefront-asset/references/api-side.md +27 -14
  540. package/skills/storefront-asset/references/findings.md +5 -2
  541. package/src/styles/tailwind.css +9 -2
  542. package/dist/matter/shipping-address/country-descriptors.d.ts +0 -1
  543. package/dist/message-locales.json +0 -7
  544. package/dist/sdk/i18n/client.d.ts +0 -4
  545. package/dist/sdk/i18n/client.js +0 -4
  546. package/dist/sdk/i18n/locales.d.ts +0 -8
  547. package/dist/sdk/i18n/locales.js +0 -57
  548. package/dist/sdk/i18n/locales.js.map +0 -1
  549. package/dist/sdk/i18n/messages/en-US.js +0 -164
  550. package/dist/sdk/i18n/messages/en-US.js.map +0 -1
  551. package/dist/sdk/i18n/messages/en-US.json +0 -159
  552. package/dist/sdk/i18n/messages/en-US.json.d.ts +0 -163
  553. package/dist/sdk/i18n/messages/es-ES.js +0 -164
  554. package/dist/sdk/i18n/messages/es-ES.js.map +0 -1
  555. package/dist/sdk/i18n/messages/es-ES.json +0 -159
  556. package/dist/sdk/i18n/messages/pt-BR.js +0 -164
  557. package/dist/sdk/i18n/messages/pt-BR.js.map +0 -1
  558. package/dist/sdk/i18n/messages/pt-BR.json +0 -159
  559. package/dist/sdk/i18n/provider.d.ts +0 -1
  560. package/dist/sdk/i18n/provider.js +0 -30
  561. package/dist/sdk/i18n/provider.js.map +0 -1
  562. package/dist/sdk/i18n/server.d.ts +0 -28
  563. package/dist/sdk/i18n/server.js +0 -59
  564. package/dist/sdk/i18n/server.js.map +0 -1
  565. package/dist/utils/resolve-authored-copy.js +0 -18
  566. package/dist/utils/resolve-authored-copy.js.map +0 -1
  567. package/dist/utils/substitute-template.js +0 -33
  568. package/dist/utils/substitute-template.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"gallery.js","names":[],"sources":["../../../src/particles/gallery/gallery.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n DialogBackdrop,\n DialogClose,\n DialogPopup,\n DialogPortal,\n DialogRoot,\n DialogTitle,\n DialogViewport,\n} from '../dialog/dialog.js';\n\nexport type GalleryMediaType = 'image' | 'video';\n\nexport type GalleryMediaItem = {\n type: GalleryMediaType;\n url: string;\n altText: string;\n previewImageUrl?: string;\n};\n\nexport type GalleryContextValue = {\n media: GalleryMediaItem[];\n selectedIndex: number;\n setSelectedIndex: (index: number) => void;\n fullscreenOpen: boolean;\n openFullscreen: () => void;\n closeFullscreen: () => void;\n selectOnHover: boolean;\n thumbnailOpensFullscreen: boolean;\n zoomActive: boolean;\n setZoomActive: (active: boolean) => void;\n zoomPosition: { x: number; y: number };\n setZoomPosition: (pos: { x: number; y: number }) => void;\n magnification: number;\n lensSize: number;\n setZoomConfig: (config: { magnification: number; lensSize: number }) => void;\n zoomContainerSize: { width: number; height: number };\n setZoomContainerSize: (size: { width: number; height: number }) => void;\n thumbnailOffset: number;\n setThumbnailOffset: (offset: number) => void;\n thumbnailsWindowSize: number;\n setThumbnailsWindowSize: (size: number) => void;\n};\n\nexport type GalleryItemContextValue = {\n item: GalleryMediaItem;\n index: number;\n isOverflow: boolean;\n overflowCount: number;\n};\n\nexport type GalleryRootProps = ComponentPropsWithRef<'div'> & {\n media?: GalleryMediaItem[];\n defaultIndex?: number;\n selectOnHover?: boolean;\n thumbnailOpensFullscreen?: boolean;\n};\n\nexport type GalleryMainMediaProps = ComponentPropsWithRef<'div'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n videoAutoPlay?: boolean;\n videoControls?: boolean;\n clickOpensFullscreen?: boolean;\n};\n\nexport type GalleryThumbnailsProps = ComponentPropsWithRef<'div'> & {\n maxVisible?: number;\n slider?: boolean;\n animated?: boolean;\n direction?: 'horizontal' | 'vertical';\n hideWhenSingle?: boolean;\n children?: ReactNode;\n};\n\nexport type GalleryThumbnailsPreviousProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n step?: number;\n};\n\nexport type GalleryThumbnailsNextProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n step?: number;\n};\n\nexport type GalleryThumbnailProps = ComponentPropsWithRef<'button'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n};\n\nexport type GalleryOverflowCountProps = ComponentPropsWithRef<'button'> & {\n template?: string;\n ariaLabel?: string;\n};\n\nexport type GalleryMediaProps = ComponentPropsWithRef<'div'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n videoAutoPlay?: boolean;\n videoControls?: boolean;\n clickOpensFullscreen?: boolean;\n};\n\nexport type GalleryZoomProps = ComponentPropsWithRef<'div'> & {\n magnification?: number;\n lensSize?: number;\n};\n\nexport type GalleryZoomLensProps = ComponentPropsWithRef<'div'>;\n\nexport type GalleryZoomResultProps = ComponentPropsWithRef<'div'>;\n\nexport type GalleryFullscreenProps = ComponentPropsWithRef<'div'> & {\n children?: ReactNode;\n};\n\nexport type GalleryFullscreenTitleProps = ComponentPropsWithRef<'h2'>;\n\nexport type GalleryFullscreenCloseProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n};\n\nexport type GalleryPreviousProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n wrap?: boolean;\n};\n\nexport type GalleryNextProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n wrap?: boolean;\n};\n\nexport type GalleryMediaCountProps = ComponentPropsWithRef<'span'> & {\n template?: string;\n};\n\nconst GalleryContext = createContext<GalleryContextValue | null>(null);\n\nexport const GalleryItemContext = createContext<GalleryItemContextValue | null>(null);\n\ntype FullscreenTitleRegistry = { register: () => void };\n\nconst FullscreenTitleRegistryContext = createContext<FullscreenTitleRegistry | null>(null);\n\nexport function useGallery(): GalleryContextValue {\n const ctx = useContext(GalleryContext);\n if (!ctx) throw new Error('Gallery components must be used inside GalleryRoot.');\n return ctx;\n}\n\nexport function useGalleryItem(): GalleryItemContextValue {\n const ctx = useContext(GalleryItemContext);\n if (!ctx) throw new Error('GalleryThumbnail and GalleryOverflowCount must be used inside GalleryThumbnails.');\n return ctx;\n}\n\nconst GALLERY_DOC = './gallery.md';\n\nexport const GalleryRootDefinition = defineComponent<GalleryRootProps>({\n name: 'GalleryRoot',\n importPath: '@vtex/faststore/components',\n component: GalleryRoot,\n editor: { label: 'Gallery Root', category: 'content' },\n schema: {\n defaultIndex: { type: 'number', default: 0, label: 'Default Index' },\n selectOnHover: { type: 'boolean', default: false, label: 'Select on Hover' },\n thumbnailOpensFullscreen: { type: 'boolean', default: false, label: 'Thumbnail Opens Fullscreen' },\n },\n guideline:\n 'Root of the gallery. Manages selected media index, fullscreen state, and zoom state. Compose as: GalleryRoot > (GalleryMainMedia (or GalleryZoom > (GalleryMainMedia + GalleryZoomLens + GalleryZoomResult)) + GalleryThumbnails > [GalleryThumbnail + GalleryOverflowCount] + GalleryFullscreen > [GalleryFullscreenClose + GalleryPrevious + GalleryMainMedia + GalleryNext + GalleryThumbnails]). Set selectOnHover=true for hover-to-preview; thumbnailOpensFullscreen=true to open fullscreen on thumbnail click.',\n});\n\nexport const GalleryMainMediaDefinition = defineComponent<GalleryMainMediaProps>({\n name: 'GalleryMainMedia',\n importPath: '@vtex/faststore/components',\n component: GalleryMainMedia,\n editor: { label: 'Gallery Main Media', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n videoAutoPlay: { type: 'boolean', default: false, label: 'Video Auto Play' },\n videoControls: { type: 'boolean', default: true, label: 'Video Controls' },\n clickOpensFullscreen: { type: 'boolean', default: false, label: 'Click Opens Fullscreen' },\n },\n guideline:\n 'Renders the currently selected media item from GalleryRoot context: <img> for images, <video> for videos. Supports swipe gestures (50px threshold) to navigate. Set clickOpensFullscreen=true to open the fullscreen overlay on click. Must be inside GalleryRoot or GalleryZoom.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsDefinition = defineComponent<GalleryThumbnailsProps>({\n name: 'GalleryThumbnails',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnails,\n editor: { label: 'Gallery Thumbnails', category: 'content' },\n schema: {\n maxVisible: { type: 'number', label: 'Max Visible' },\n slider: { type: 'boolean', default: false, label: 'Slider Mode' },\n animated: { type: 'boolean', default: false, label: 'Animated' },\n direction: { type: ['horizontal', 'vertical'] as const, default: 'horizontal', label: 'Direction' },\n hideWhenSingle: { type: 'boolean', default: true, label: 'Hide when single image' },\n },\n guideline:\n 'Iterates media items and renders its children once per item. Returns null when there are 0 or 1 media items unless hideWhenSingle={false}. Set maxVisible to cap visible thumbnails. Without slider: last slot gets isOverflow=true for GalleryOverflowCount. With slider=true: window driven by GalleryThumbnailsPrevious/Next. Add animated=true for smooth scroll — also set direction to match the flex axis of the container.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsPreviousDefinition = defineComponent<GalleryThumbnailsPreviousProps>({\n name: 'GalleryThumbnailsPrevious',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnailsPrevious,\n editor: { label: 'Gallery Thumbnails Previous', category: 'content' },\n schema: {\n step: { type: 'number', default: 1, label: 'Step' },\n },\n guideline:\n 'Scrolls the thumbnail strip backward. Only active when GalleryThumbnails slider=true. Disabled at the first thumbnail. step=1 (default) moves one at a time; pass step equal to maxVisible to jump a full window. Place as sibling of GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsNextDefinition = defineComponent<GalleryThumbnailsNextProps>({\n name: 'GalleryThumbnailsNext',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnailsNext,\n editor: { label: 'Gallery Thumbnails Next', category: 'content' },\n schema: {\n step: { type: 'number', default: 1, label: 'Step' },\n },\n guideline:\n 'Scrolls the thumbnail strip forward. Only active when GalleryThumbnails slider=true. Disabled at the last visible thumbnail. step=1 (default) moves one at a time; pass step equal to maxVisible to jump a full window. Place as sibling of GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailDefinition = defineComponent<GalleryThumbnailProps>({\n name: 'GalleryThumbnail',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnail,\n editor: { label: 'Gallery Thumbnail', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n },\n guideline:\n 'Thumbnail button for a single media item. Reads from GalleryItemContext — must be inside GalleryThumbnails. Adds data-fs-gallery-thumbnail-selected=\"true\" when active. For videos, renders previewImageUrl as the thumbnail src.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryOverflowCountDefinition = defineComponent<GalleryOverflowCountProps>({\n name: 'GalleryOverflowCount',\n importPath: '@vtex/faststore/components',\n component: GalleryOverflowCount,\n editor: { label: 'Gallery Overflow Count', category: 'content' },\n schema: {\n template: { type: 'string', default: '+{count}', label: 'Template' },\n ariaLabel: { type: 'string', default: 'View all {total} images', label: 'Aria Label' },\n },\n guideline:\n 'Overflow indicator. Only renders when isOverflow=true in GalleryItemContext — place alongside GalleryThumbnail inside GalleryThumbnails. Clicking opens fullscreen. Use template=\"+{count}\" to customize the visible label. The rendered button carries an aria-label (default \"View all {total} images\") so screen readers announce the full action, not just the count.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryMediaDefinition = defineComponent<GalleryMediaProps>({\n name: 'GalleryMedia',\n importPath: '@vtex/faststore/components',\n component: GalleryMedia,\n editor: { label: 'Gallery Media', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n videoAutoPlay: { type: 'boolean', default: false, label: 'Video Auto Play' },\n videoControls: { type: 'boolean', default: true, label: 'Video Controls' },\n clickOpensFullscreen: { type: 'boolean', default: false, label: 'Click Opens Fullscreen' },\n },\n guideline:\n 'Full-size media display for items inside GalleryThumbnails. Unlike GalleryThumbnail, renders as a div (not a button) — use for grid layouts and vertical fullscreen stacks. Set clickOpensFullscreen=true to select the item and open fullscreen on click. Must be inside GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomDefinition = defineComponent<GalleryZoomProps>({\n name: 'GalleryZoom',\n importPath: '@vtex/faststore/components',\n component: GalleryZoom,\n editor: { label: 'Gallery Zoom', category: 'content' },\n schema: {\n magnification: { type: 'number', default: 2, label: 'Magnification' },\n lensSize: { type: 'number', default: 150, label: 'Lens Size (px)' },\n },\n guideline:\n 'Zoom container. Wrap GalleryMainMedia inside it to activate zoom on pointer enter (images only, not videos). Place GalleryZoomLens as a sibling of GalleryMainMedia inside GalleryZoom for the cursor indicator. Place GalleryZoomResult anywhere in GalleryRoot — as a sibling of GalleryZoom (side-panel) or absolute inside GalleryZoom (on-image overlay). Set magnification to control zoom level (default 2).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomLensDefinition = defineComponent<GalleryZoomLensProps>({\n name: 'GalleryZoomLens',\n importPath: '@vtex/faststore/components',\n component: GalleryZoomLens,\n editor: { label: 'Gallery Zoom Lens', category: 'content' },\n schema: {},\n guideline:\n 'Cursor focus indicator inside GalleryZoom. Only renders when zoom is active. Must be inside GalleryZoom. Style as absolute-positioned square — uses CSS custom properties --zoom-x, --zoom-y, --lens-size for positioning.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomResultDefinition = defineComponent<GalleryZoomResultProps>({\n name: 'GalleryZoomResult',\n importPath: '@vtex/faststore/components',\n component: GalleryZoomResult,\n editor: { label: 'Gallery Zoom Result', category: 'content' },\n schema: {},\n guideline:\n 'Magnified view driven by cursor position from GalleryZoom context. Only renders when zoom is active on an image. Place as sibling of GalleryZoom for side-panel zoom, or absolute inside GalleryZoom for on-image zoom.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenDefinition = defineComponent<GalleryFullscreenProps>({\n name: 'GalleryFullscreen',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreen,\n editor: { label: 'Gallery Fullscreen', category: 'content' },\n schema: {},\n guideline:\n 'Fullscreen overlay controlled by GalleryRoot state. Opens via GalleryOverflowCount, GalleryFullscreenTrigger, or thumbnailOpensFullscreen=true. Wraps a Dialog internally — place GalleryFullscreenClose, GalleryPrevious, GalleryMainMedia, GalleryNext, and optionally GalleryThumbnails as children. If no GalleryFullscreenTitle is composed, a default sr-only \"Gallery\" title is rendered automatically so the dialog always has an accessible name. Must be inside GalleryRoot.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenTitleDefinition = defineComponent<GalleryFullscreenTitleProps>({\n name: 'GalleryFullscreenTitle',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreenTitle,\n editor: { label: 'Gallery Fullscreen Title', category: 'content' },\n schema: {},\n guideline:\n 'Accessible title for the fullscreen dialog. Required for screen readers. Use sr-only to hide it visually or omit the class to display it. Must be inside GalleryFullscreen.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenCloseDefinition = defineComponent<GalleryFullscreenCloseProps>({\n name: 'GalleryFullscreenClose',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreenClose,\n editor: { label: 'Gallery Fullscreen Close', category: 'content' },\n schema: {},\n guideline:\n 'Closes the fullscreen overlay. Must be inside GalleryFullscreen. Place at the top-right corner. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryPreviousDefinition = defineComponent<GalleryPreviousProps>({\n name: 'GalleryPrevious',\n importPath: '@vtex/faststore/components',\n component: GalleryPrevious,\n editor: { label: 'Gallery Previous', category: 'content' },\n schema: {\n wrap: { type: 'boolean', default: true, label: 'Wrap Around' },\n },\n guideline:\n 'Navigates to the previous media item; wraps to the last by default, or stops at the first with wrap={false}. Use inside GalleryFullscreen or inline for carousel controls. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryNextDefinition = defineComponent<GalleryNextProps>({\n name: 'GalleryNext',\n importPath: '@vtex/faststore/components',\n component: GalleryNext,\n editor: { label: 'Gallery Next', category: 'content' },\n schema: {\n wrap: { type: 'boolean', default: true, label: 'Wrap Around' },\n },\n guideline:\n 'Navigates to the next media item; wraps to the first by default, or stops at the last with wrap={false}. Use inside GalleryFullscreen or inline for carousel controls. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryMediaCountDefinition = defineComponent<GalleryMediaCountProps>({\n name: 'GalleryMediaCount',\n importPath: '@vtex/faststore/components',\n component: GalleryMediaCount,\n editor: { label: 'Gallery Media Count', category: 'content' },\n schema: {\n template: { type: 'string', default: '{current} / {total}', label: 'Template' },\n },\n guideline:\n 'Displays the current media position and total count (e.g. \"2 / 10\"). Use {current} and {total} placeholders in template. Place anywhere inside GalleryRoot — typically in GalleryFullscreen or above GalleryMainMedia.',\n docPath: GALLERY_DOC,\n});\n\nexport function GalleryRoot({\n media = [],\n defaultIndex = 0,\n selectOnHover = false,\n thumbnailOpensFullscreen = false,\n children,\n ...props\n}: GalleryRootProps) {\n const [selectedIndex, setSelectedIndex] = useState(defaultIndex);\n const [fullscreenOpen, setFullscreenOpen] = useState(false);\n const [zoomActive, setZoomActive] = useState(false);\n const [zoomPosition, setZoomPosition] = useState({ x: 0, y: 0 });\n const [zoomConfig, setZoomConfig] = useState({ magnification: 2, lensSize: 150 });\n const [zoomContainerSize, setZoomContainerSize] = useState({ width: 0, height: 0 });\n const [thumbnailOffset, setThumbnailOffset] = useState(0);\n const [thumbnailsWindowSize, setThumbnailsWindowSize] = useState(0);\n\n const openFullscreen = useCallback(() => setFullscreenOpen(true), []);\n const closeFullscreen = useCallback(() => setFullscreenOpen(false), []);\n\n const ctx = useMemo<GalleryContextValue>(\n () => ({\n media,\n selectedIndex,\n setSelectedIndex,\n fullscreenOpen,\n openFullscreen,\n closeFullscreen,\n selectOnHover,\n thumbnailOpensFullscreen,\n zoomActive,\n setZoomActive,\n zoomPosition,\n setZoomPosition,\n magnification: zoomConfig.magnification,\n lensSize: zoomConfig.lensSize,\n setZoomConfig,\n zoomContainerSize,\n setZoomContainerSize,\n thumbnailOffset,\n setThumbnailOffset,\n thumbnailsWindowSize,\n setThumbnailsWindowSize,\n }),\n [\n media,\n selectedIndex,\n fullscreenOpen,\n openFullscreen,\n closeFullscreen,\n selectOnHover,\n thumbnailOpensFullscreen,\n zoomActive,\n zoomPosition,\n zoomConfig,\n zoomContainerSize,\n thumbnailOffset,\n thumbnailsWindowSize,\n ],\n );\n\n return (\n <GalleryContext value={ctx}>\n <div {...props} data-fs-gallery=\"\">\n {children}\n </div>\n </GalleryContext>\n );\n}\n\nconst SWIPE_THRESHOLD = 50;\n\nexport function GalleryMainMedia({\n objectFit = 'contain',\n aspectRatio,\n videoAutoPlay = false,\n videoControls = true,\n clickOpensFullscreen = false,\n style,\n ...props\n}: GalleryMainMediaProps) {\n const { media, selectedIndex, setSelectedIndex, openFullscreen } = useGallery();\n const currentItem = media[selectedIndex] ?? media[0];\n const pointerStartX = useRef<number | null>(null);\n\n function handlePointerDown(e: React.PointerEvent) {\n pointerStartX.current = e.clientX;\n }\n\n function handlePointerUp(e: React.PointerEvent) {\n if (pointerStartX.current === null) return;\n const delta = e.clientX - pointerStartX.current;\n pointerStartX.current = null;\n\n if (Math.abs(delta) < SWIPE_THRESHOLD) {\n if (clickOpensFullscreen) openFullscreen();\n return;\n }\n if (media.length === 0) return;\n if (delta < 0) {\n setSelectedIndex(selectedIndex < media.length - 1 ? selectedIndex + 1 : 0);\n } else {\n setSelectedIndex(selectedIndex > 0 ? selectedIndex - 1 : media.length - 1);\n }\n }\n\n if (!currentItem) {\n return <div {...props} data-fs-gallery-main-media=\"\" />;\n }\n\n if (currentItem.type === 'video') {\n return (\n <div {...props} data-fs-gallery-main-media=\"\" data-fs-gallery-main-media-type=\"video\">\n <video\n src={currentItem.url}\n controls={videoControls}\n autoPlay={videoAutoPlay}\n poster={currentItem.previewImageUrl}\n style={{ objectFit, aspectRatio, ...style } as React.CSSProperties}\n >\n <track kind=\"captions\" />\n </video>\n </div>\n );\n }\n\n return (\n <div\n {...props}\n data-fs-gallery-main-media=\"\"\n data-fs-gallery-main-media-type=\"image\"\n onPointerDown={handlePointerDown}\n onPointerUp={handlePointerUp}\n style={{ touchAction: 'pan-y', ...style }}\n >\n <img\n src={currentItem.url}\n alt={currentItem.altText}\n style={{ display: 'block', width: '100%', objectFit, aspectRatio } as React.CSSProperties}\n draggable={false}\n />\n </div>\n );\n}\n\nexport function GalleryThumbnails({ hideWhenSingle = true, ...rest }: GalleryThumbnailsProps) {\n const { media } = useGallery();\n if (hideWhenSingle && media.length <= 1) return null;\n return <GalleryThumbnailsInner {...rest} />;\n}\n\nfunction GalleryThumbnailsInner({\n maxVisible,\n slider = false,\n animated = false,\n direction = 'horizontal',\n children,\n style,\n ...props\n}: Omit<GalleryThumbnailsProps, 'hideWhenSingle'>) {\n const { media, thumbnailOffset, setThumbnailsWindowSize } = useGallery();\n const trackRef = useRef<HTMLDivElement>(null);\n const [containerSize, setContainerSize] = useState<number | null>(null);\n\n useEffect(() => {\n if (slider && maxVisible != null) setThumbnailsWindowSize(maxVisible);\n }, [slider, maxVisible, setThumbnailsWindowSize]);\n\n // Measure the exact size needed to show maxVisible items so overflow:hidden clips correctly.\n // useLayoutEffect runs after DOM commit but before paint — no visual flash.\n useLayoutEffect(() => {\n if (!animated || !slider || maxVisible == null || !trackRef.current) return;\n const lastVisible = trackRef.current.children[maxVisible - 1] as HTMLElement | undefined;\n if (!lastVisible) return;\n const size =\n direction === 'horizontal'\n ? lastVisible.offsetLeft + lastVisible.offsetWidth\n : lastVisible.offsetTop + lastVisible.offsetHeight;\n setContainerSize(size);\n }, [animated, slider, maxVisible, direction]);\n\n useEffect(() => {\n if (!animated || !slider || !trackRef.current) return;\n const target = trackRef.current.children[thumbnailOffset] as HTMLElement | undefined;\n if (!target) return;\n trackRef.current.scrollTo({\n left: direction === 'horizontal' ? target.offsetLeft : 0,\n top: direction === 'vertical' ? target.offsetTop : 0,\n behavior: 'smooth',\n });\n }, [thumbnailOffset, animated, slider, direction]);\n\n const visibleItems = (() => {\n if (animated && slider) return media; // render all; scroll handles visibility\n if (maxVisible == null) return media;\n if (slider) return media.slice(thumbnailOffset, thumbnailOffset + maxVisible);\n // overflow mode: show first maxVisible items, last slot is overflow\n return media.slice(0, maxVisible);\n })();\n\n const containerStyle: React.CSSProperties =\n animated && slider\n ? {\n overflow: 'hidden',\n position: 'relative',\n ...(direction === 'horizontal' && containerSize != null ? { width: containerSize } : {}),\n ...(direction === 'vertical' && containerSize != null ? { height: containerSize } : {}),\n ...style,\n }\n : { ...style };\n\n return (\n <div {...props} ref={trackRef} style={containerStyle} data-fs-gallery-thumbnails=\"\">\n {visibleItems.map((item, slotIndex) => {\n const index = animated && slider ? slotIndex : slider ? thumbnailOffset + slotIndex : slotIndex;\n const isOverflow = !slider && maxVisible != null && media.length > maxVisible && slotIndex === maxVisible - 1;\n const overflowCount = isOverflow ? media.length - maxVisible + 1 : 0;\n\n return (\n <GalleryItemContext key={index} value={{ item, index, isOverflow, overflowCount }}>\n {children}\n </GalleryItemContext>\n );\n })}\n </div>\n );\n}\n\nexport function GalleryThumbnail({ objectFit = 'contain', aspectRatio, style, ...props }: GalleryThumbnailProps) {\n const { selectedIndex, setSelectedIndex, openFullscreen, selectOnHover, thumbnailOpensFullscreen } = useGallery();\n const { item, index, isOverflow } = useGalleryItem();\n\n const thumbSrc = item.type === 'video' ? (item.previewImageUrl ?? '') : item.url;\n\n function handleClick() {\n setSelectedIndex(index);\n if (thumbnailOpensFullscreen || isOverflow) openFullscreen();\n }\n\n function handlePointerEnter() {\n if (selectOnHover && !isOverflow) setSelectedIndex(index);\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n onPointerEnter={handlePointerEnter}\n data-fs-gallery-thumbnail=\"\"\n data-fs-gallery-thumbnail-selected={String(index === selectedIndex)}\n data-fs-gallery-thumbnail-type={item.type}\n {...props}\n >\n <img\n src={thumbSrc}\n alt={item.altText}\n style={\n { display: 'block', width: '100%', height: '100%', objectFit, aspectRatio, ...style } as React.CSSProperties\n }\n />\n </button>\n );\n}\n\nexport function GalleryOverflowCount({\n template = '+{count}',\n ariaLabel = 'View all {total} images',\n ...props\n}: GalleryOverflowCountProps) {\n const { media, openFullscreen } = useGallery();\n const { isOverflow, overflowCount } = useGalleryItem();\n\n if (!isOverflow) return null;\n\n const label = template.replace('{count}', String(overflowCount));\n const resolvedAriaLabel = ariaLabel.replace('{total}', String(media.length));\n\n return (\n <button\n type=\"button\"\n onClick={openFullscreen}\n aria-label={resolvedAriaLabel}\n data-fs-gallery-overflow-count=\"\"\n {...props}\n >\n {label}\n </button>\n );\n}\n\nexport function GalleryMedia({\n objectFit = 'contain',\n aspectRatio,\n videoAutoPlay = false,\n videoControls = true,\n clickOpensFullscreen = false,\n style,\n ...props\n}: GalleryMediaProps) {\n const { setSelectedIndex, openFullscreen } = useGallery();\n const { item, index } = useGalleryItem();\n\n function handleClick() {\n setSelectedIndex(index);\n openFullscreen();\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === 'Enter' || e.key === ' ') handleClick();\n }\n\n const interactiveProps = clickOpensFullscreen\n ? { onClick: handleClick, onKeyDown: handleKeyDown, role: 'button' as const, tabIndex: 0 }\n : {};\n\n const wrapperStyle: React.CSSProperties = {\n ...style,\n ...(aspectRatio ? { aspectRatio, position: 'relative' } : {}),\n };\n const mediaStyle: React.CSSProperties = aspectRatio\n ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit }\n : { display: 'block', width: '100%', height: '100%', objectFit };\n\n if (item.type === 'video') {\n return (\n <div\n {...props}\n {...interactiveProps}\n style={wrapperStyle}\n data-fs-gallery-media-item=\"\"\n data-fs-gallery-media-item-type=\"video\"\n >\n <video\n src={item.url}\n controls={videoControls}\n autoPlay={videoAutoPlay}\n poster={item.previewImageUrl}\n style={mediaStyle as React.CSSProperties}\n >\n <track kind=\"captions\" />\n </video>\n </div>\n );\n }\n\n return (\n <div\n {...props}\n {...interactiveProps}\n style={wrapperStyle}\n data-fs-gallery-media-item=\"\"\n data-fs-gallery-media-item-type=\"image\"\n >\n <img src={item.url} alt={item.altText} style={mediaStyle as React.CSSProperties} draggable={false} />\n </div>\n );\n}\n\nexport function GalleryZoom({ magnification = 2, lensSize = 150, children, ...props }: GalleryZoomProps) {\n const { media, selectedIndex, setZoomActive, setZoomPosition, setZoomConfig, setZoomContainerSize } = useGallery();\n const containerRef = useRef<HTMLDivElement>(null);\n const currentItem = media[selectedIndex];\n const isImage = currentItem?.type === 'image';\n\n function handlePointerMove(e: React.PointerEvent) {\n if (!containerRef.current || !isImage) return;\n const rect = containerRef.current.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n setZoomPosition({ x: Math.max(0, Math.min(1, x)), y: Math.max(0, Math.min(1, y)) });\n }\n\n function handlePointerEnter() {\n setZoomConfig({ magnification, lensSize });\n if (containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n setZoomContainerSize({ width: rect.width, height: rect.height });\n }\n if (isImage) setZoomActive(true);\n }\n\n function handlePointerLeave() {\n setZoomActive(false);\n }\n\n return (\n <div\n ref={containerRef}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerEnter={handlePointerEnter}\n onPointerLeave={handlePointerLeave}\n data-fs-gallery-zoom=\"\"\n >\n {children}\n </div>\n );\n}\n\nexport function GalleryZoomLens({ style, ...props }: GalleryZoomLensProps) {\n const { zoomActive, zoomPosition, lensSize, zoomContainerSize } = useGallery();\n\n if (!zoomActive) return null;\n\n // Center the lens on the cursor, then clamp so the full square stays inside the container\n // (snaps at the edges instead of overflowing the image).\n const { width, height } = zoomContainerSize;\n const maxLeft = Math.max(0, width - lensSize);\n const maxTop = Math.max(0, height - lensSize);\n const left = width > 0 ? Math.min(Math.max(zoomPosition.x * width - lensSize / 2, 0), maxLeft) : 0;\n const top = height > 0 ? Math.min(Math.max(zoomPosition.y * height - lensSize / 2, 0), maxTop) : 0;\n\n const lensStyle: React.CSSProperties = {\n top,\n left,\n width: lensSize,\n height: lensSize,\n ...style,\n };\n\n return <div {...props} style={lensStyle} data-fs-gallery-zoom-lens=\"\" />;\n}\n\nexport function GalleryZoomResult({ style, ...props }: GalleryZoomResultProps) {\n const { media, selectedIndex, zoomActive, zoomPosition, magnification } = useGallery();\n const currentItem = media[selectedIndex];\n const isVisible = zoomActive && !!currentItem && currentItem.type === 'image';\n\n // Always renders to prevent layout shifts in flex/grid containers.\n // Returning null when inactive would change the container dimensions and\n // trigger pointerleave on GalleryZoom, causing a flicker loop.\n const resultStyle: React.CSSProperties = isVisible\n ? {\n backgroundImage: `url(${currentItem.url})`,\n backgroundSize: `${magnification * 100}%`,\n backgroundPosition: `${zoomPosition.x * 100}% ${zoomPosition.y * 100}%`,\n backgroundRepeat: 'no-repeat',\n ...style,\n }\n : { visibility: 'hidden', ...style };\n\n return <div {...props} style={resultStyle} data-fs-gallery-zoom-result=\"\" />;\n}\n\nexport function GalleryFullscreen({ children, ...props }: GalleryFullscreenProps) {\n const { fullscreenOpen, closeFullscreen } = useGallery();\n const [hasExplicitTitle, setHasExplicitTitle] = useState(false);\n const register = useCallback(() => setHasExplicitTitle(true), []);\n const registry = useMemo<FullscreenTitleRegistry>(() => ({ register }), [register]);\n\n return (\n <DialogRoot\n open={fullscreenOpen}\n onOpenChange={(open) => {\n if (!open) closeFullscreen();\n }}\n >\n <DialogPortal>\n <DialogBackdrop className=\"fixed inset-0 bg-black/80\" data-fs-gallery-fullscreen-backdrop=\"\" />\n <DialogViewport className=\"fixed inset-0 flex items-center justify-center\">\n <DialogPopup {...props} data-fs-gallery-fullscreen=\"\">\n <FullscreenTitleRegistryContext.Provider value={registry}>\n {!hasExplicitTitle && (\n <DialogTitle className=\"sr-only\" data-fs-gallery-fullscreen-title=\"\">\n Gallery\n </DialogTitle>\n )}\n {children}\n </FullscreenTitleRegistryContext.Provider>\n </DialogPopup>\n </DialogViewport>\n </DialogPortal>\n </DialogRoot>\n );\n}\n\nexport function GalleryFullscreenTitle({ children = 'Gallery', ...props }: GalleryFullscreenTitleProps) {\n const registry = useContext(FullscreenTitleRegistryContext);\n useLayoutEffect(() => {\n registry?.register();\n }, [registry]);\n return (\n <DialogTitle data-fs-gallery-fullscreen-title=\"\" {...props}>\n {children}\n </DialogTitle>\n );\n}\n\nexport function GalleryFullscreenClose({ children, ...props }: GalleryFullscreenCloseProps) {\n return (\n <DialogClose data-fs-gallery-fullscreen-close=\"\" {...props}>\n {children}\n </DialogClose>\n );\n}\n\nexport function GalleryPrevious({ children, wrap = true, ...props }: GalleryPreviousProps) {\n const { media, selectedIndex, setSelectedIndex } = useGallery();\n\n function handleClick() {\n if (media.length === 0) return;\n if (selectedIndex > 0) {\n setSelectedIndex(selectedIndex - 1);\n } else if (wrap) {\n setSelectedIndex(media.length - 1);\n }\n // wrap === false at index 0 → no-op\n }\n\n return (\n <button\n type=\"button\"\n disabled={media.length === 0 || (!wrap && selectedIndex === 0)}\n onClick={handleClick}\n data-fs-gallery-previous=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryNext({ children, wrap = true, ...props }: GalleryNextProps) {\n const { media, selectedIndex, setSelectedIndex } = useGallery();\n\n function handleClick() {\n if (media.length === 0) return;\n if (selectedIndex < media.length - 1) {\n setSelectedIndex(selectedIndex + 1);\n } else if (wrap) {\n setSelectedIndex(0);\n }\n // wrap === false at last index → no-op\n }\n\n return (\n <button\n type=\"button\"\n disabled={media.length === 0 || (!wrap && selectedIndex === media.length - 1)}\n onClick={handleClick}\n data-fs-gallery-next=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryThumbnailsPrevious({ step = 1, children, ...props }: GalleryThumbnailsPreviousProps) {\n const { thumbnailOffset, setThumbnailOffset } = useGallery();\n const isDisabled = thumbnailOffset === 0;\n return (\n <button\n type=\"button\"\n disabled={isDisabled}\n onClick={() => setThumbnailOffset(Math.max(0, thumbnailOffset - step))}\n data-fs-gallery-thumbnails-previous=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryThumbnailsNext({ step = 1, children, ...props }: GalleryThumbnailsNextProps) {\n const { media, thumbnailOffset, setThumbnailOffset, thumbnailsWindowSize } = useGallery();\n const isDisabled = thumbnailsWindowSize > 0 && thumbnailOffset + thumbnailsWindowSize >= media.length;\n const maxOffset = Math.max(0, media.length - thumbnailsWindowSize);\n\n return (\n <button\n type=\"button\"\n disabled={isDisabled}\n onClick={() => setThumbnailOffset(Math.min(maxOffset, thumbnailOffset + step))}\n data-fs-gallery-thumbnails-next=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryMediaCount({ template = '{current} / {total}', ...props }: GalleryMediaCountProps) {\n const { selectedIndex, media } = useGallery();\n const label = template.replace('{current}', String(selectedIndex + 1)).replace('{total}', String(media.length));\n\n return (\n <span data-fs-gallery-media-count=\"\" {...props}>\n {label}\n </span>\n );\n}\n\nexport const Gallery = {\n Root: GalleryRoot,\n MainMedia: GalleryMainMedia,\n Media: GalleryMedia,\n Thumbnails: GalleryThumbnails,\n ThumbnailsPrevious: GalleryThumbnailsPrevious,\n ThumbnailsNext: GalleryThumbnailsNext,\n Thumbnail: GalleryThumbnail,\n OverflowCount: GalleryOverflowCount,\n Zoom: GalleryZoom,\n ZoomLens: GalleryZoomLens,\n ZoomResult: GalleryZoomResult,\n Fullscreen: GalleryFullscreen,\n FullscreenTitle: GalleryFullscreenTitle,\n FullscreenClose: GalleryFullscreenClose,\n Previous: GalleryPrevious,\n Next: GalleryNext,\n MediaCount: GalleryMediaCount,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"gallery.js","names":[],"sources":["../../../src/particles/gallery/gallery.tsx"],"sourcesContent":["'use client';\n\nimport { type ContentValue, defineComponent, defineContentType, type MessageLocaleProp } from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\nimport {\n DialogBackdrop,\n DialogClose,\n DialogPopup,\n DialogPortal,\n DialogRoot,\n DialogTitle,\n DialogViewport,\n} from '../dialog/dialog.js';\n\nexport const GalleryOverflowCountContent = defineContentType({\n id: 'gallery-overflow-count',\n title: 'Gallery Overflow Count',\n description: 'Text and accessible name of the overflow indicator that opens the fullscreen gallery.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n template: {\n type: 'string',\n title: 'Text',\n description: 'The count argument is the number of hidden media items.',\n format: 'icu-message',\n messageSource: '+{count}',\n messageArguments: { type: 'object', properties: { count: { type: 'integer' } } },\n messageExample: { count: 3 },\n },\n ariaLabel: {\n type: 'string',\n title: 'Accessible label',\n description: 'The total argument is the number of media items in the gallery.',\n format: 'icu-message',\n messageSource: 'View all {total} images',\n messageArguments: { type: 'object', properties: { total: { type: 'integer' } } },\n messageExample: { total: 8 },\n },\n },\n },\n});\n\nexport const GalleryFullscreenContent = defineContentType({\n id: 'gallery-fullscreen',\n title: 'Gallery Fullscreen',\n description: 'Accessible name of the fullscreen dialog when no GalleryFullscreenTitle is composed.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n title: { type: 'string', title: 'Fallback title', format: 'icu-message', messageSource: 'Gallery' },\n },\n },\n});\n\nexport const GalleryFullscreenTitleContent = defineContentType({\n id: 'gallery-fullscreen-title',\n title: 'Gallery Fullscreen Title',\n description: 'Title of the fullscreen dialog, used when no children are composed.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Title', format: 'icu-message', messageSource: 'Gallery' },\n },\n },\n});\n\nexport const GalleryMediaCountContent = defineContentType({\n id: 'gallery-media-count',\n title: 'Gallery Media Count',\n description: 'Position of the selected media item in the gallery.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n template: {\n type: 'string',\n title: 'Text',\n description: 'current is the 1-based position of the selected item; total is the item count.',\n format: 'icu-message',\n messageSource: '{current} / {total}',\n messageArguments: {\n type: 'object',\n properties: { current: { type: 'integer' }, total: { type: 'integer' } },\n },\n messageExample: { current: 2, total: 8 },\n },\n },\n },\n});\n\nexport type GalleryMediaType = 'image' | 'video';\n\nexport type GalleryMediaItem = {\n type: GalleryMediaType;\n url: string;\n altText: string;\n previewImageUrl?: string;\n};\n\nexport type GalleryContextValue = {\n media: GalleryMediaItem[];\n selectedIndex: number;\n setSelectedIndex: (index: number) => void;\n fullscreenOpen: boolean;\n openFullscreen: () => void;\n closeFullscreen: () => void;\n selectOnHover: boolean;\n thumbnailOpensFullscreen: boolean;\n zoomActive: boolean;\n setZoomActive: (active: boolean) => void;\n zoomPosition: { x: number; y: number };\n setZoomPosition: (pos: { x: number; y: number }) => void;\n magnification: number;\n lensSize: number;\n setZoomConfig: (config: { magnification: number; lensSize: number }) => void;\n zoomContainerSize: { width: number; height: number };\n setZoomContainerSize: (size: { width: number; height: number }) => void;\n thumbnailOffset: number;\n setThumbnailOffset: (offset: number) => void;\n thumbnailsWindowSize: number;\n setThumbnailsWindowSize: (size: number) => void;\n};\n\nexport type GalleryItemContextValue = {\n item: GalleryMediaItem;\n index: number;\n isOverflow: boolean;\n overflowCount: number;\n};\n\nexport type GalleryRootProps = ComponentPropsWithRef<'div'> & {\n media?: GalleryMediaItem[];\n defaultIndex?: number;\n selectOnHover?: boolean;\n thumbnailOpensFullscreen?: boolean;\n};\n\nexport type GalleryMainMediaProps = ComponentPropsWithRef<'div'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n videoAutoPlay?: boolean;\n videoControls?: boolean;\n clickOpensFullscreen?: boolean;\n};\n\nexport type GalleryThumbnailsProps = ComponentPropsWithRef<'div'> & {\n maxVisible?: number;\n slider?: boolean;\n animated?: boolean;\n direction?: 'horizontal' | 'vertical';\n hideWhenSingle?: boolean;\n children?: ReactNode;\n};\n\nexport type GalleryThumbnailsPreviousProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n step?: number;\n};\n\nexport type GalleryThumbnailsNextProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n step?: number;\n};\n\nexport type GalleryThumbnailProps = ComponentPropsWithRef<'button'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n};\n\nexport type GalleryOverflowCountProps = ComponentPropsWithRef<'button'> &\n MessageLocaleProp & {\n $content?: ContentValue<typeof GalleryOverflowCountContent>;\n };\n\nexport type GalleryMediaProps = ComponentPropsWithRef<'div'> & {\n objectFit?: 'contain' | 'cover' | 'fill' | 'none';\n aspectRatio?: string;\n videoAutoPlay?: boolean;\n videoControls?: boolean;\n clickOpensFullscreen?: boolean;\n};\n\nexport type GalleryZoomProps = ComponentPropsWithRef<'div'> & {\n magnification?: number;\n lensSize?: number;\n};\n\nexport type GalleryZoomLensProps = ComponentPropsWithRef<'div'>;\n\nexport type GalleryZoomResultProps = ComponentPropsWithRef<'div'>;\n\nexport type GalleryFullscreenProps = ComponentPropsWithRef<'div'> &\n MessageLocaleProp & {\n children?: ReactNode;\n $content?: ContentValue<typeof GalleryFullscreenContent>;\n };\n\nexport type GalleryFullscreenTitleProps = ComponentPropsWithRef<'h2'> &\n MessageLocaleProp & {\n $content?: ContentValue<typeof GalleryFullscreenTitleContent>;\n };\n\nexport type GalleryFullscreenCloseProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n};\n\nexport type GalleryPreviousProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n wrap?: boolean;\n};\n\nexport type GalleryNextProps = ComponentPropsWithRef<'button'> & {\n children?: ReactNode;\n wrap?: boolean;\n};\n\nexport type GalleryMediaCountProps = ComponentPropsWithRef<'span'> &\n MessageLocaleProp & {\n $content?: ContentValue<typeof GalleryMediaCountContent>;\n };\n\nconst GalleryContext = createContext<GalleryContextValue | null>(null);\n\nexport const GalleryItemContext = createContext<GalleryItemContextValue | null>(null);\n\ntype FullscreenTitleRegistry = { register: () => void };\n\nconst FullscreenTitleRegistryContext = createContext<FullscreenTitleRegistry | null>(null);\n\nexport function useGallery(): GalleryContextValue {\n const ctx = useContext(GalleryContext);\n if (!ctx) throw new Error('Gallery components must be used inside GalleryRoot.');\n return ctx;\n}\n\nexport function useGalleryItem(): GalleryItemContextValue {\n const ctx = useContext(GalleryItemContext);\n if (!ctx) throw new Error('GalleryThumbnail and GalleryOverflowCount must be used inside GalleryThumbnails.');\n return ctx;\n}\n\nconst GALLERY_DOC = './gallery.md';\n\nexport const GalleryRootDefinition = defineComponent<GalleryRootProps>({\n name: 'GalleryRoot',\n importPath: '@vtex/faststore/components',\n component: GalleryRoot,\n editor: { label: 'Gallery Root', category: 'content' },\n schema: {\n defaultIndex: { type: 'number', default: 0, label: 'Default Index' },\n selectOnHover: { type: 'boolean', default: false, label: 'Select on Hover' },\n thumbnailOpensFullscreen: { type: 'boolean', default: false, label: 'Thumbnail Opens Fullscreen' },\n },\n guideline:\n 'Root of the gallery. Manages selected media index, fullscreen state, and zoom state. Compose as: GalleryRoot > (GalleryMainMedia (or GalleryZoom > (GalleryMainMedia + GalleryZoomLens + GalleryZoomResult)) + GalleryThumbnails > [GalleryThumbnail + GalleryOverflowCount] + GalleryFullscreen > [GalleryFullscreenClose + GalleryPrevious + GalleryMainMedia + GalleryNext + GalleryThumbnails]). Set selectOnHover=true for hover-to-preview; thumbnailOpensFullscreen=true to open fullscreen on thumbnail click.',\n});\n\nexport const GalleryMainMediaDefinition = defineComponent<GalleryMainMediaProps>({\n name: 'GalleryMainMedia',\n importPath: '@vtex/faststore/components',\n component: GalleryMainMedia,\n editor: { label: 'Gallery Main Media', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n videoAutoPlay: { type: 'boolean', default: false, label: 'Video Auto Play' },\n videoControls: { type: 'boolean', default: true, label: 'Video Controls' },\n clickOpensFullscreen: { type: 'boolean', default: false, label: 'Click Opens Fullscreen' },\n },\n guideline:\n 'Renders the currently selected media item from GalleryRoot context: <img> for images, <video> for videos. Supports swipe gestures (50px threshold) to navigate. Set clickOpensFullscreen=true to open the fullscreen overlay on click. Must be inside GalleryRoot or GalleryZoom.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsDefinition = defineComponent<GalleryThumbnailsProps>({\n name: 'GalleryThumbnails',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnails,\n editor: { label: 'Gallery Thumbnails', category: 'content' },\n schema: {\n maxVisible: { type: 'number', label: 'Max Visible' },\n slider: { type: 'boolean', default: false, label: 'Slider Mode' },\n animated: { type: 'boolean', default: false, label: 'Animated' },\n direction: { type: ['horizontal', 'vertical'] as const, default: 'horizontal', label: 'Direction' },\n hideWhenSingle: { type: 'boolean', default: true, label: 'Hide when single image' },\n },\n guideline:\n 'Iterates media items and renders its children once per item. Returns null when there are 0 or 1 media items unless hideWhenSingle={false}. Set maxVisible to cap visible thumbnails. Without slider: last slot gets isOverflow=true for GalleryOverflowCount. With slider=true: window driven by GalleryThumbnailsPrevious/Next. Add animated=true for smooth scroll — also set direction to match the flex axis of the container.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsPreviousDefinition = defineComponent<GalleryThumbnailsPreviousProps>({\n name: 'GalleryThumbnailsPrevious',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnailsPrevious,\n editor: { label: 'Gallery Thumbnails Previous', category: 'content' },\n schema: {\n step: { type: 'number', default: 1, label: 'Step' },\n },\n guideline:\n 'Scrolls the thumbnail strip backward. Only active when GalleryThumbnails slider=true. Disabled at the first thumbnail. step=1 (default) moves one at a time; pass step equal to maxVisible to jump a full window. Place as sibling of GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailsNextDefinition = defineComponent<GalleryThumbnailsNextProps>({\n name: 'GalleryThumbnailsNext',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnailsNext,\n editor: { label: 'Gallery Thumbnails Next', category: 'content' },\n schema: {\n step: { type: 'number', default: 1, label: 'Step' },\n },\n guideline:\n 'Scrolls the thumbnail strip forward. Only active when GalleryThumbnails slider=true. Disabled at the last visible thumbnail. step=1 (default) moves one at a time; pass step equal to maxVisible to jump a full window. Place as sibling of GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryThumbnailDefinition = defineComponent<GalleryThumbnailProps>({\n name: 'GalleryThumbnail',\n importPath: '@vtex/faststore/components',\n component: GalleryThumbnail,\n editor: { label: 'Gallery Thumbnail', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n },\n guideline:\n 'Thumbnail button for a single media item. Reads from GalleryItemContext — must be inside GalleryThumbnails. Adds data-fs-gallery-thumbnail-selected=\"true\" when active. For videos, renders previewImageUrl as the thumbnail src.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryOverflowCountDefinition = defineComponent<GalleryOverflowCountProps>({\n name: 'GalleryOverflowCount',\n importPath: '@vtex/faststore/components',\n component: GalleryOverflowCount,\n content: GalleryOverflowCountContent,\n editor: { label: 'Gallery Overflow Count', category: 'content' },\n schema: {},\n guideline:\n 'Overflow indicator. Only renders when isOverflow=true in GalleryItemContext — place alongside GalleryThumbnail inside GalleryThumbnails. Clicking opens fullscreen. Its text and aria-label come from the $content fields template ({count} hidden items) and ariaLabel ({total} items); the aria-label makes screen readers announce the full action, not just the count.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryMediaDefinition = defineComponent<GalleryMediaProps>({\n name: 'GalleryMedia',\n importPath: '@vtex/faststore/components',\n component: GalleryMedia,\n editor: { label: 'Gallery Media', category: 'content' },\n schema: {\n objectFit: { type: ['contain', 'cover', 'fill', 'none'] as const, default: 'contain', label: 'Object Fit' },\n aspectRatio: { type: 'string', default: '1 / 1', label: 'Aspect Ratio' },\n videoAutoPlay: { type: 'boolean', default: false, label: 'Video Auto Play' },\n videoControls: { type: 'boolean', default: true, label: 'Video Controls' },\n clickOpensFullscreen: { type: 'boolean', default: false, label: 'Click Opens Fullscreen' },\n },\n guideline:\n 'Full-size media display for items inside GalleryThumbnails. Unlike GalleryThumbnail, renders as a div (not a button) — use for grid layouts and vertical fullscreen stacks. Set clickOpensFullscreen=true to select the item and open fullscreen on click. Must be inside GalleryThumbnails.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomDefinition = defineComponent<GalleryZoomProps>({\n name: 'GalleryZoom',\n importPath: '@vtex/faststore/components',\n component: GalleryZoom,\n editor: { label: 'Gallery Zoom', category: 'content' },\n schema: {\n magnification: { type: 'number', default: 2, label: 'Magnification' },\n lensSize: { type: 'number', default: 150, label: 'Lens Size (px)' },\n },\n guideline:\n 'Zoom container. Wrap GalleryMainMedia inside it to activate zoom on pointer enter (images only, not videos). Place GalleryZoomLens as a sibling of GalleryMainMedia inside GalleryZoom for the cursor indicator. Place GalleryZoomResult anywhere in GalleryRoot — as a sibling of GalleryZoom (side-panel) or absolute inside GalleryZoom (on-image overlay). Set magnification to control zoom level (default 2).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomLensDefinition = defineComponent<GalleryZoomLensProps>({\n name: 'GalleryZoomLens',\n importPath: '@vtex/faststore/components',\n component: GalleryZoomLens,\n editor: { label: 'Gallery Zoom Lens', category: 'content' },\n schema: {},\n guideline:\n 'Cursor focus indicator inside GalleryZoom. Only renders when zoom is active. Must be inside GalleryZoom. Style as absolute-positioned square — uses CSS custom properties --zoom-x, --zoom-y, --lens-size for positioning.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryZoomResultDefinition = defineComponent<GalleryZoomResultProps>({\n name: 'GalleryZoomResult',\n importPath: '@vtex/faststore/components',\n component: GalleryZoomResult,\n editor: { label: 'Gallery Zoom Result', category: 'content' },\n schema: {},\n guideline:\n 'Magnified view driven by cursor position from GalleryZoom context. Only renders when zoom is active on an image. Place as sibling of GalleryZoom for side-panel zoom, or absolute inside GalleryZoom for on-image zoom.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenDefinition = defineComponent<GalleryFullscreenProps>({\n name: 'GalleryFullscreen',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreen,\n content: GalleryFullscreenContent,\n editor: { label: 'Gallery Fullscreen', category: 'content' },\n schema: {},\n guideline:\n 'Fullscreen overlay controlled by GalleryRoot state. Opens via GalleryOverflowCount, GalleryFullscreenTrigger, or thumbnailOpensFullscreen=true. Wraps a Dialog internally — place GalleryFullscreenClose, GalleryPrevious, GalleryMainMedia, GalleryNext, and optionally GalleryThumbnails as children. If no GalleryFullscreenTitle is composed, an sr-only title from the $content field title is rendered so the dialog always has an accessible name. Must be inside GalleryRoot.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenTitleDefinition = defineComponent<GalleryFullscreenTitleProps>({\n name: 'GalleryFullscreenTitle',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreenTitle,\n content: GalleryFullscreenTitleContent,\n editor: { label: 'Gallery Fullscreen Title', category: 'content' },\n schema: {},\n guideline:\n 'Accessible title for the fullscreen dialog. Required for screen readers. Renders its children, or the $content field label when it has none. Use sr-only to hide it visually or omit the class to display it. Must be inside GalleryFullscreen.',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryFullscreenCloseDefinition = defineComponent<GalleryFullscreenCloseProps>({\n name: 'GalleryFullscreenClose',\n importPath: '@vtex/faststore/components',\n component: GalleryFullscreenClose,\n editor: { label: 'Gallery Fullscreen Close', category: 'content' },\n schema: {},\n guideline:\n 'Closes the fullscreen overlay. Must be inside GalleryFullscreen. Place at the top-right corner. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryPreviousDefinition = defineComponent<GalleryPreviousProps>({\n name: 'GalleryPrevious',\n importPath: '@vtex/faststore/components',\n component: GalleryPrevious,\n editor: { label: 'Gallery Previous', category: 'content' },\n schema: {\n wrap: { type: 'boolean', default: true, label: 'Wrap Around' },\n },\n guideline:\n 'Navigates to the previous media item; wraps to the last by default, or stops at the first with wrap={false}. Use inside GalleryFullscreen or inline for carousel controls. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryNextDefinition = defineComponent<GalleryNextProps>({\n name: 'GalleryNext',\n importPath: '@vtex/faststore/components',\n component: GalleryNext,\n editor: { label: 'Gallery Next', category: 'content' },\n schema: {\n wrap: { type: 'boolean', default: true, label: 'Wrap Around' },\n },\n guideline:\n 'Navigates to the next media item; wraps to the first by default, or stops at the last with wrap={false}. Use inside GalleryFullscreen or inline for carousel controls. Accepts any children (Icon, text).',\n docPath: GALLERY_DOC,\n});\n\nexport const GalleryMediaCountDefinition = defineComponent<GalleryMediaCountProps>({\n name: 'GalleryMediaCount',\n importPath: '@vtex/faststore/components',\n component: GalleryMediaCount,\n content: GalleryMediaCountContent,\n editor: { label: 'Gallery Media Count', category: 'content' },\n schema: {},\n guideline:\n 'Displays the current media position and total count (e.g. \"2 / 10\"). The text is the $content field template, an ICU message with current and total arguments. Place anywhere inside GalleryRoot — typically in GalleryFullscreen or above GalleryMainMedia.',\n docPath: GALLERY_DOC,\n});\n\nexport function GalleryRoot({\n media = [],\n defaultIndex = 0,\n selectOnHover = false,\n thumbnailOpensFullscreen = false,\n children,\n ...props\n}: GalleryRootProps) {\n const [selectedIndex, setSelectedIndex] = useState(defaultIndex);\n const [fullscreenOpen, setFullscreenOpen] = useState(false);\n const [zoomActive, setZoomActive] = useState(false);\n const [zoomPosition, setZoomPosition] = useState({ x: 0, y: 0 });\n const [zoomConfig, setZoomConfig] = useState({ magnification: 2, lensSize: 150 });\n const [zoomContainerSize, setZoomContainerSize] = useState({ width: 0, height: 0 });\n const [thumbnailOffset, setThumbnailOffset] = useState(0);\n const [thumbnailsWindowSize, setThumbnailsWindowSize] = useState(0);\n\n const openFullscreen = useCallback(() => setFullscreenOpen(true), []);\n const closeFullscreen = useCallback(() => setFullscreenOpen(false), []);\n\n const ctx = useMemo<GalleryContextValue>(\n () => ({\n media,\n selectedIndex,\n setSelectedIndex,\n fullscreenOpen,\n openFullscreen,\n closeFullscreen,\n selectOnHover,\n thumbnailOpensFullscreen,\n zoomActive,\n setZoomActive,\n zoomPosition,\n setZoomPosition,\n magnification: zoomConfig.magnification,\n lensSize: zoomConfig.lensSize,\n setZoomConfig,\n zoomContainerSize,\n setZoomContainerSize,\n thumbnailOffset,\n setThumbnailOffset,\n thumbnailsWindowSize,\n setThumbnailsWindowSize,\n }),\n [\n media,\n selectedIndex,\n fullscreenOpen,\n openFullscreen,\n closeFullscreen,\n selectOnHover,\n thumbnailOpensFullscreen,\n zoomActive,\n zoomPosition,\n zoomConfig,\n zoomContainerSize,\n thumbnailOffset,\n thumbnailsWindowSize,\n ],\n );\n\n return (\n <GalleryContext value={ctx}>\n <div {...props} data-fs-gallery=\"\">\n {children}\n </div>\n </GalleryContext>\n );\n}\n\nconst SWIPE_THRESHOLD = 50;\n\nexport function GalleryMainMedia({\n objectFit = 'contain',\n aspectRatio,\n videoAutoPlay = false,\n videoControls = true,\n clickOpensFullscreen = false,\n style,\n ...props\n}: GalleryMainMediaProps) {\n const { media, selectedIndex, setSelectedIndex, openFullscreen } = useGallery();\n const currentItem = media[selectedIndex] ?? media[0];\n const pointerStartX = useRef<number | null>(null);\n\n function handlePointerDown(e: React.PointerEvent) {\n pointerStartX.current = e.clientX;\n }\n\n function handlePointerUp(e: React.PointerEvent) {\n if (pointerStartX.current === null) return;\n const delta = e.clientX - pointerStartX.current;\n pointerStartX.current = null;\n\n if (Math.abs(delta) < SWIPE_THRESHOLD) {\n if (clickOpensFullscreen) openFullscreen();\n return;\n }\n if (media.length === 0) return;\n if (delta < 0) {\n setSelectedIndex(selectedIndex < media.length - 1 ? selectedIndex + 1 : 0);\n } else {\n setSelectedIndex(selectedIndex > 0 ? selectedIndex - 1 : media.length - 1);\n }\n }\n\n if (!currentItem) {\n return <div {...props} data-fs-gallery-main-media=\"\" />;\n }\n\n if (currentItem.type === 'video') {\n return (\n <div {...props} data-fs-gallery-main-media=\"\" data-fs-gallery-main-media-type=\"video\">\n <video\n src={currentItem.url}\n controls={videoControls}\n autoPlay={videoAutoPlay}\n poster={currentItem.previewImageUrl}\n style={{ objectFit, aspectRatio, ...style } as React.CSSProperties}\n >\n <track kind=\"captions\" />\n </video>\n </div>\n );\n }\n\n return (\n <div\n {...props}\n data-fs-gallery-main-media=\"\"\n data-fs-gallery-main-media-type=\"image\"\n onPointerDown={handlePointerDown}\n onPointerUp={handlePointerUp}\n style={{ touchAction: 'pan-y', ...style }}\n >\n <img\n src={currentItem.url}\n alt={currentItem.altText}\n style={{ display: 'block', width: '100%', objectFit, aspectRatio } as React.CSSProperties}\n draggable={false}\n />\n </div>\n );\n}\n\nexport function GalleryThumbnails({ hideWhenSingle = true, ...rest }: GalleryThumbnailsProps) {\n const { media } = useGallery();\n if (hideWhenSingle && media.length <= 1) return null;\n return <GalleryThumbnailsInner {...rest} />;\n}\n\nfunction GalleryThumbnailsInner({\n maxVisible,\n slider = false,\n animated = false,\n direction = 'horizontal',\n children,\n style,\n ...props\n}: Omit<GalleryThumbnailsProps, 'hideWhenSingle'>) {\n const { media, thumbnailOffset, setThumbnailsWindowSize } = useGallery();\n const trackRef = useRef<HTMLDivElement>(null);\n const [containerSize, setContainerSize] = useState<number | null>(null);\n\n useEffect(() => {\n if (slider && maxVisible != null) setThumbnailsWindowSize(maxVisible);\n }, [slider, maxVisible, setThumbnailsWindowSize]);\n\n // Measure the exact size needed to show maxVisible items so overflow:hidden clips correctly.\n // useLayoutEffect runs after DOM commit but before paint — no visual flash.\n useLayoutEffect(() => {\n if (!animated || !slider || maxVisible == null || !trackRef.current) return;\n const lastVisible = trackRef.current.children[maxVisible - 1] as HTMLElement | undefined;\n if (!lastVisible) return;\n const size =\n direction === 'horizontal'\n ? lastVisible.offsetLeft + lastVisible.offsetWidth\n : lastVisible.offsetTop + lastVisible.offsetHeight;\n setContainerSize(size);\n }, [animated, slider, maxVisible, direction]);\n\n useEffect(() => {\n if (!animated || !slider || !trackRef.current) return;\n const target = trackRef.current.children[thumbnailOffset] as HTMLElement | undefined;\n if (!target) return;\n trackRef.current.scrollTo({\n left: direction === 'horizontal' ? target.offsetLeft : 0,\n top: direction === 'vertical' ? target.offsetTop : 0,\n behavior: 'smooth',\n });\n }, [thumbnailOffset, animated, slider, direction]);\n\n const visibleItems = (() => {\n if (animated && slider) return media; // render all; scroll handles visibility\n if (maxVisible == null) return media;\n if (slider) return media.slice(thumbnailOffset, thumbnailOffset + maxVisible);\n // overflow mode: show first maxVisible items, last slot is overflow\n return media.slice(0, maxVisible);\n })();\n\n const containerStyle: React.CSSProperties =\n animated && slider\n ? {\n overflow: 'hidden',\n position: 'relative',\n ...(direction === 'horizontal' && containerSize != null ? { width: containerSize } : {}),\n ...(direction === 'vertical' && containerSize != null ? { height: containerSize } : {}),\n ...style,\n }\n : { ...style };\n\n return (\n <div {...props} ref={trackRef} style={containerStyle} data-fs-gallery-thumbnails=\"\">\n {visibleItems.map((item, slotIndex) => {\n const index = animated && slider ? slotIndex : slider ? thumbnailOffset + slotIndex : slotIndex;\n const isOverflow = !slider && maxVisible != null && media.length > maxVisible && slotIndex === maxVisible - 1;\n const overflowCount = isOverflow ? media.length - maxVisible + 1 : 0;\n\n return (\n <GalleryItemContext key={index} value={{ item, index, isOverflow, overflowCount }}>\n {children}\n </GalleryItemContext>\n );\n })}\n </div>\n );\n}\n\nexport function GalleryThumbnail({ objectFit = 'contain', aspectRatio, style, ...props }: GalleryThumbnailProps) {\n const { selectedIndex, setSelectedIndex, openFullscreen, selectOnHover, thumbnailOpensFullscreen } = useGallery();\n const { item, index, isOverflow } = useGalleryItem();\n\n const thumbSrc = item.type === 'video' ? (item.previewImageUrl ?? '') : item.url;\n\n function handleClick() {\n setSelectedIndex(index);\n if (thumbnailOpensFullscreen || isOverflow) openFullscreen();\n }\n\n function handlePointerEnter() {\n if (selectOnHover && !isOverflow) setSelectedIndex(index);\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n onPointerEnter={handlePointerEnter}\n data-fs-gallery-thumbnail=\"\"\n data-fs-gallery-thumbnail-selected={String(index === selectedIndex)}\n data-fs-gallery-thumbnail-type={item.type}\n {...props}\n >\n <img\n src={thumbSrc}\n alt={item.altText}\n style={\n { display: 'block', width: '100%', height: '100%', objectFit, aspectRatio, ...style } as React.CSSProperties\n }\n />\n </button>\n );\n}\n\nexport function GalleryOverflowCount({ $locale, $content, ...props }: GalleryOverflowCountProps) {\n const { media, openFullscreen } = useGallery();\n const { isOverflow, overflowCount } = useGalleryItem();\n const messages = useMessageFormatter(GalleryOverflowCountContent, $content);\n\n if (!isOverflow) return null;\n\n return (\n <button\n type=\"button\"\n onClick={openFullscreen}\n aria-label={messages.format('ariaLabel', { total: media.length })}\n data-fs-gallery-overflow-count=\"\"\n {...props}\n >\n {messages.format('template', { count: overflowCount })}\n </button>\n );\n}\n\nexport function GalleryMedia({\n objectFit = 'contain',\n aspectRatio,\n videoAutoPlay = false,\n videoControls = true,\n clickOpensFullscreen = false,\n style,\n ...props\n}: GalleryMediaProps) {\n const { setSelectedIndex, openFullscreen } = useGallery();\n const { item, index } = useGalleryItem();\n\n function handleClick() {\n setSelectedIndex(index);\n openFullscreen();\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === 'Enter' || e.key === ' ') handleClick();\n }\n\n const interactiveProps = clickOpensFullscreen\n ? { onClick: handleClick, onKeyDown: handleKeyDown, role: 'button' as const, tabIndex: 0 }\n : {};\n\n const wrapperStyle: React.CSSProperties = {\n ...style,\n ...(aspectRatio ? { aspectRatio, position: 'relative' } : {}),\n };\n const mediaStyle: React.CSSProperties = aspectRatio\n ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit }\n : { display: 'block', width: '100%', height: '100%', objectFit };\n\n if (item.type === 'video') {\n return (\n <div\n {...props}\n {...interactiveProps}\n style={wrapperStyle}\n data-fs-gallery-media-item=\"\"\n data-fs-gallery-media-item-type=\"video\"\n >\n <video\n src={item.url}\n controls={videoControls}\n autoPlay={videoAutoPlay}\n poster={item.previewImageUrl}\n style={mediaStyle as React.CSSProperties}\n >\n <track kind=\"captions\" />\n </video>\n </div>\n );\n }\n\n return (\n <div\n {...props}\n {...interactiveProps}\n style={wrapperStyle}\n data-fs-gallery-media-item=\"\"\n data-fs-gallery-media-item-type=\"image\"\n >\n <img src={item.url} alt={item.altText} style={mediaStyle as React.CSSProperties} draggable={false} />\n </div>\n );\n}\n\nexport function GalleryZoom({ magnification = 2, lensSize = 150, children, ...props }: GalleryZoomProps) {\n const { media, selectedIndex, setZoomActive, setZoomPosition, setZoomConfig, setZoomContainerSize } = useGallery();\n const containerRef = useRef<HTMLDivElement>(null);\n const currentItem = media[selectedIndex];\n const isImage = currentItem?.type === 'image';\n\n function handlePointerMove(e: React.PointerEvent) {\n if (!containerRef.current || !isImage) return;\n const rect = containerRef.current.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = (e.clientY - rect.top) / rect.height;\n setZoomPosition({ x: Math.max(0, Math.min(1, x)), y: Math.max(0, Math.min(1, y)) });\n }\n\n function handlePointerEnter() {\n setZoomConfig({ magnification, lensSize });\n if (containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n setZoomContainerSize({ width: rect.width, height: rect.height });\n }\n if (isImage) setZoomActive(true);\n }\n\n function handlePointerLeave() {\n setZoomActive(false);\n }\n\n return (\n <div\n ref={containerRef}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerEnter={handlePointerEnter}\n onPointerLeave={handlePointerLeave}\n data-fs-gallery-zoom=\"\"\n >\n {children}\n </div>\n );\n}\n\nexport function GalleryZoomLens({ style, ...props }: GalleryZoomLensProps) {\n const { zoomActive, zoomPosition, lensSize, zoomContainerSize } = useGallery();\n\n if (!zoomActive) return null;\n\n // Center the lens on the cursor, then clamp so the full square stays inside the container\n // (snaps at the edges instead of overflowing the image).\n const { width, height } = zoomContainerSize;\n const maxLeft = Math.max(0, width - lensSize);\n const maxTop = Math.max(0, height - lensSize);\n const left = width > 0 ? Math.min(Math.max(zoomPosition.x * width - lensSize / 2, 0), maxLeft) : 0;\n const top = height > 0 ? Math.min(Math.max(zoomPosition.y * height - lensSize / 2, 0), maxTop) : 0;\n\n const lensStyle: React.CSSProperties = {\n top,\n left,\n width: lensSize,\n height: lensSize,\n ...style,\n };\n\n return <div {...props} style={lensStyle} data-fs-gallery-zoom-lens=\"\" />;\n}\n\nexport function GalleryZoomResult({ style, ...props }: GalleryZoomResultProps) {\n const { media, selectedIndex, zoomActive, zoomPosition, magnification } = useGallery();\n const currentItem = media[selectedIndex];\n const isVisible = zoomActive && !!currentItem && currentItem.type === 'image';\n\n // Always renders to prevent layout shifts in flex/grid containers.\n // Returning null when inactive would change the container dimensions and\n // trigger pointerleave on GalleryZoom, causing a flicker loop.\n const resultStyle: React.CSSProperties = isVisible\n ? {\n backgroundImage: `url(${currentItem.url})`,\n backgroundSize: `${magnification * 100}%`,\n backgroundPosition: `${zoomPosition.x * 100}% ${zoomPosition.y * 100}%`,\n backgroundRepeat: 'no-repeat',\n ...style,\n }\n : { visibility: 'hidden', ...style };\n\n return <div {...props} style={resultStyle} data-fs-gallery-zoom-result=\"\" />;\n}\n\nexport function GalleryFullscreen({ $locale, $content, children, ...props }: GalleryFullscreenProps) {\n const { fullscreenOpen, closeFullscreen } = useGallery();\n const messages = useMessageFormatter(GalleryFullscreenContent, $content);\n const [hasExplicitTitle, setHasExplicitTitle] = useState(false);\n const register = useCallback(() => setHasExplicitTitle(true), []);\n const registry = useMemo<FullscreenTitleRegistry>(() => ({ register }), [register]);\n\n return (\n <DialogRoot\n open={fullscreenOpen}\n onOpenChange={(open) => {\n if (!open) closeFullscreen();\n }}\n >\n <DialogPortal>\n <DialogBackdrop className=\"fixed inset-0 bg-black/80\" data-fs-gallery-fullscreen-backdrop=\"\" />\n <DialogViewport className=\"fixed inset-0 flex items-center justify-center\">\n <DialogPopup {...props} data-fs-gallery-fullscreen=\"\">\n <FullscreenTitleRegistryContext.Provider value={registry}>\n {!hasExplicitTitle && (\n <DialogTitle className=\"sr-only\" data-fs-gallery-fullscreen-title=\"\">\n {messages.format('title')}\n </DialogTitle>\n )}\n {children}\n </FullscreenTitleRegistryContext.Provider>\n </DialogPopup>\n </DialogViewport>\n </DialogPortal>\n </DialogRoot>\n );\n}\n\nexport function GalleryFullscreenTitle({ $locale, $content, children, ...props }: GalleryFullscreenTitleProps) {\n const registry = useContext(FullscreenTitleRegistryContext);\n const messages = useMessageFormatter(GalleryFullscreenTitleContent, $content);\n useLayoutEffect(() => {\n registry?.register();\n }, [registry]);\n return (\n <DialogTitle data-fs-gallery-fullscreen-title=\"\" {...props}>\n {children ?? messages.format('label')}\n </DialogTitle>\n );\n}\n\nexport function GalleryFullscreenClose({ children, ...props }: GalleryFullscreenCloseProps) {\n return (\n <DialogClose data-fs-gallery-fullscreen-close=\"\" {...props}>\n {children}\n </DialogClose>\n );\n}\n\nexport function GalleryPrevious({ children, wrap = true, ...props }: GalleryPreviousProps) {\n const { media, selectedIndex, setSelectedIndex } = useGallery();\n\n function handleClick() {\n if (media.length === 0) return;\n if (selectedIndex > 0) {\n setSelectedIndex(selectedIndex - 1);\n } else if (wrap) {\n setSelectedIndex(media.length - 1);\n }\n // wrap === false at index 0 → no-op\n }\n\n return (\n <button\n type=\"button\"\n disabled={media.length === 0 || (!wrap && selectedIndex === 0)}\n onClick={handleClick}\n data-fs-gallery-previous=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryNext({ children, wrap = true, ...props }: GalleryNextProps) {\n const { media, selectedIndex, setSelectedIndex } = useGallery();\n\n function handleClick() {\n if (media.length === 0) return;\n if (selectedIndex < media.length - 1) {\n setSelectedIndex(selectedIndex + 1);\n } else if (wrap) {\n setSelectedIndex(0);\n }\n // wrap === false at last index → no-op\n }\n\n return (\n <button\n type=\"button\"\n disabled={media.length === 0 || (!wrap && selectedIndex === media.length - 1)}\n onClick={handleClick}\n data-fs-gallery-next=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryThumbnailsPrevious({ step = 1, children, ...props }: GalleryThumbnailsPreviousProps) {\n const { thumbnailOffset, setThumbnailOffset } = useGallery();\n const isDisabled = thumbnailOffset === 0;\n return (\n <button\n type=\"button\"\n disabled={isDisabled}\n onClick={() => setThumbnailOffset(Math.max(0, thumbnailOffset - step))}\n data-fs-gallery-thumbnails-previous=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryThumbnailsNext({ step = 1, children, ...props }: GalleryThumbnailsNextProps) {\n const { media, thumbnailOffset, setThumbnailOffset, thumbnailsWindowSize } = useGallery();\n const isDisabled = thumbnailsWindowSize > 0 && thumbnailOffset + thumbnailsWindowSize >= media.length;\n const maxOffset = Math.max(0, media.length - thumbnailsWindowSize);\n\n return (\n <button\n type=\"button\"\n disabled={isDisabled}\n onClick={() => setThumbnailOffset(Math.min(maxOffset, thumbnailOffset + step))}\n data-fs-gallery-thumbnails-next=\"\"\n {...props}\n >\n {children}\n </button>\n );\n}\n\nexport function GalleryMediaCount({ $locale, $content, ...props }: GalleryMediaCountProps) {\n const { selectedIndex, media } = useGallery();\n const messages = useMessageFormatter(GalleryMediaCountContent, $content);\n\n return (\n <span data-fs-gallery-media-count=\"\" {...props}>\n {messages.format('template', { current: selectedIndex + 1, total: media.length })}\n </span>\n );\n}\n\nexport const Gallery = {\n Root: GalleryRoot,\n MainMedia: GalleryMainMedia,\n Media: GalleryMedia,\n Thumbnails: GalleryThumbnails,\n ThumbnailsPrevious: GalleryThumbnailsPrevious,\n ThumbnailsNext: GalleryThumbnailsNext,\n Thumbnail: GalleryThumbnail,\n OverflowCount: GalleryOverflowCount,\n Zoom: GalleryZoom,\n ZoomLens: GalleryZoomLens,\n ZoomResult: GalleryZoomResult,\n Fullscreen: GalleryFullscreen,\n FullscreenTitle: GalleryFullscreenTitle,\n FullscreenClose: GalleryFullscreenClose,\n Previous: GalleryPrevious,\n Next: GalleryNext,\n MediaCount: GalleryMediaCount,\n};\n"],"mappings":"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"}
@@ -65,7 +65,7 @@ export declare const IncentivesContent: {
65
65
  };
66
66
  };
67
67
  /**
68
- * The benefit glyphs the `icon` enum admits. Exported because a store's `global.json` has to list
68
+ * The benefit glyphs the `icon` enum admits. Exported because a store's foundation has to list
69
69
  * them under `icons.include` for a CMS-chosen name to resolve at runtime — one import there instead
70
70
  * of five retyped strings, which is what keeps the layout task from silently missing one. Reading it
71
71
  * off the model rather than declaring it alongside makes the two impossible to drift apart.
@@ -70,7 +70,7 @@ const IncentivesContent = defineContentType({
70
70
  }
71
71
  });
72
72
  /**
73
- * The benefit glyphs the `icon` enum admits. Exported because a store's `global.json` has to list
73
+ * The benefit glyphs the `icon` enum admits. Exported because a store's foundation has to list
74
74
  * them under `icons.include` for a CMS-chosen name to resolve at runtime — one import there instead
75
75
  * of five retyped strings, which is what keeps the layout task from silently missing one. Reading it
76
76
  * off the model rather than declaring it alongside makes the two impossible to drift apart.
@@ -1 +1 @@
1
- {"version":3,"file":"incentives.js","names":[],"sources":["../../../src/particles/incentives/incentives.tsx"],"sourcesContent":["import { type ContentValue, defineComponent, defineContentType } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport type { PageRef } from '../../sdk/navigation/types.js';\nimport { resolveSafeHref } from '../../utils/safe-href.js';\nimport { Icon } from '../icon/icon.js';\nimport { Image } from '../image/image.js';\nimport { NavigationLink } from '../navigation-link/navigation-link.js';\n\n// ---------------------------------------------------------------------------\n// Content model\n// ---------------------------------------------------------------------------\n\nexport const IncentivesContent = defineContentType({\n id: 'incentives',\n title: 'Incentives',\n description: 'Store benefit highlights rendered as a strip in the footer.',\n schema: {\n type: 'object',\n additionalProperties: false,\n // `items` is deliberately optional. A missing element key already omits the component before any\n // required check runs, so requiring the list would buy nothing and cost the prop fallback: an\n // entry without it would be shape-invalid and the authored `items` never reached.\n properties: {\n items: {\n type: 'array',\n title: 'Incentive items',\n // Author-time guidance only: no read-time gate enforces item bounds, so its one consumer is\n // the Content Platform Admin's form. An empty list still reaches the component, which\n // self-hides on it. No ceiling — the swatch has to lay out at any count regardless.\n minItems: 1,\n items: {\n type: 'object',\n additionalProperties: false,\n // `title` alone. A nested required property is validated at read time and a violation omits\n // the whole strip, so every entry here widens the blast radius of one under-filled item.\n required: ['title'],\n properties: {\n // `minLength` on the title alone: it is the required property, so a blank one is the only\n // blank that decides anything. Both lines render if present and drop if blank, which is\n // guidance the Admin form has no reason to state differently for one of them.\n title: { type: 'string', minLength: 1, title: 'Title' },\n firstLineText: { type: 'string', title: 'First line' },\n secondLineText: { type: 'string', title: 'Second line' },\n // Optional, because a benefit strip links nowhere and a shortcut row links everywhere,\n // and the two are the same shape. Author-time guidance only, deliberately identical to\n // FooterLinkGroup's so the Admin form cannot reject a destination `resolveSafeHref`\n // would have accepted; lookahead-free because that regex engine may be an RE2 family.\n href: {\n type: 'string',\n minLength: 1,\n title: 'Link',\n format: 'uri-reference',\n pattern: '^(?:https?://.*|mailto:.+|tel:.+|/(?:[^/].*)?)$',\n },\n // Inline rather than a named constant: the catalog scanner reads this file statically and\n // rejects an identifier it cannot evaluate.\n icon: {\n type: 'string',\n enum: ['truck', 'calendar', 'gift', 'store', 'shield-check'],\n title: 'Icon',\n },\n iconUrl: {\n type: 'string',\n format: 'uri',\n title: 'Custom icon',\n widget: { 'ui:widget': 'media-gallery' },\n },\n alt: { type: 'string', title: 'Custom icon alt text' },\n },\n },\n },\n },\n },\n});\n\n/**\n * The benefit glyphs the `icon` enum admits. Exported because a store's `global.json` has to list\n * them under `icons.include` for a CMS-chosen name to resolve at runtime — one import there instead\n * of five retyped strings, which is what keeps the layout task from silently missing one. Reading it\n * off the model rather than declaring it alongside makes the two impossible to drift apart.\n */\nexport const INCENTIVE_ICON_NAMES = IncentivesContent.schema.properties.items.items.properties.icon.enum;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype IncentivesContentValue = ContentValue<typeof IncentivesContent>;\n\ntype IncentiveContentItem = NonNullable<IncentivesContentValue['items']>[number];\n\n/** One incentive item. The prop accepts a page reference; a CMS href stays a string. */\nexport type IncentiveItem = Omit<IncentiveContentItem, 'href'> & {\n href?: PageRef | string;\n};\n\ntype IncentiveIconName = NonNullable<IncentiveItem['icon']>;\n\nexport type IncentivesProps = ComponentPropsWithRef<'ul'> & {\n /** Authored fallback list, rendered when no CMS entry supplies one. */\n items?: readonly IncentiveItem[];\n /** Injected by the compiler, sliced from the layout's composite content entry. */\n $content?: IncentivesContentValue;\n};\n\n// ---------------------------------------------------------------------------\n// Definition\n// ---------------------------------------------------------------------------\n\nexport const IncentivesDefinition = defineComponent({\n name: 'Incentives',\n importPath: '@vtex/faststore/components',\n component: Incentives,\n content: IncentivesContent,\n editor: { label: 'Incentives', category: 'content' },\n schema: {\n items: { type: 'array', label: 'Incentive items' },\n },\n guideline:\n \"The store's value propositions as a strip of icon-and-copy items, the whole list CMS-editable: each item carries a title, up to two description lines, either a predefined icon or an uploaded one, and an optional href that turns the whole block into a link. Every predefined icon name must be listed in the store's icons.include. Renders nothing when unconfigured. See incentives.md.\",\n});\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * The three glyph states an item can reach, kept as a union so \"at most one source\" is a property of\n * the type rather than of how the resolver happens to build it. `alt` belongs to the uploaded member\n * alone, since a sprite glyph has nothing to name.\n */\ntype ResolvedGlyph =\n | { icon: IncentiveIconName; src?: undefined; alt?: undefined }\n | { icon?: undefined; src: string; alt?: string }\n | { icon?: undefined; src?: undefined; alt?: undefined };\n\n/**\n * An item that can render: a non-blank title, its surviving description lines, a glyph state, and a\n * destination the allowlist cleared. The title is the item's identity, so it is the only part whose\n * absence drops the item.\n */\ntype ResolvedIncentive = { title: string; lines: string[]; href: PageRef | string | null } & ResolvedGlyph;\n\n/**\n * The item's destination, or null for both \"none authored\" and \"the allowlist refused it\". Unlike the\n * link group and the social row, where a link is the whole point, a refusal here costs the anchor\n * alone — an unlinked item is this component's ordinary shape, so the glyph and copy still render.\n */\nfunction readItems(\n content: readonly IncentiveContentItem[] | undefined,\n authored: readonly IncentiveItem[] | undefined,\n): readonly IncentiveItem[] {\n if (content !== undefined) return content;\n return authored ?? [];\n}\n\nfunction resolveHref(raw: PageRef | string | undefined, index: number): PageRef | string | null {\n // A page reference skips the string allowlist. Absent is \"no link\", not a rejection.\n if (typeof raw !== 'string') return raw ?? null;\n // Blank is \"no link\", not a rejection, so it never reaches the allowlist or the log.\n if (!raw.trim()) return null;\n\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n // A bounded reason and no authored value, the convention the content runtime's own log follows.\n console.warn('[Incentives] link destination rejected', { index, reason: destination.reason });\n return null;\n }\n\n return destination.href;\n}\n\n/**\n * Drops every item with no title to show, and every description line that would render empty.\n * Neither read-time gate enforces `minLength`, so both blanks reach the component. The asymmetry is\n * deliberate: an icon with no label is not an incentive, while a missing line is supplementary.\n */\nfunction resolveIncentives(items: readonly IncentiveItem[]): ResolvedIncentive[] {\n const resolved: ResolvedIncentive[] = [];\n\n items.forEach((item, index) => {\n if (!item.title.trim()) return;\n\n const lines = [item.firstLineText, item.secondLineText].filter((line): line is string => Boolean(line?.trim()));\n const href = resolveHref(item.href, index);\n\n if (item.iconUrl?.trim()) {\n resolved.push({ title: item.title, lines, href, src: item.iconUrl, alt: item.alt });\n } else if (item.icon) {\n resolved.push({ title: item.title, lines, href, icon: item.icon });\n } else {\n resolved.push({ title: item.title, lines, href });\n }\n });\n\n return resolved;\n}\n\n/**\n * The item's glyph, or nothing. Presence decides the channel — an upload first, then a predefined\n * sprite name — and an item carrying neither renders as copy alone rather than an empty slot.\n */\nfunction IncentiveGlyph({ item }: { item: ResolvedIncentive }) {\n if (item.src !== undefined) {\n return <Image src={item.src} alt={item.alt} data-fs-incentive-icon=\"\" />;\n }\n\n if (item.icon !== undefined) {\n return <Icon name={item.icon} data-fs-incentive-icon=\"\" />;\n }\n\n return null;\n}\n\n/**\n * The glyph and copy an item renders in both forms. Kept whole rather than split across the linked\n * and unlinked branches so the anchor wraps the entire block: on a shortcut row the pictogram is\n * half the click target, and a link around the label alone leaves it dead.\n */\nfunction IncentiveBody({ item }: { item: ResolvedIncentive }) {\n return (\n <>\n <IncentiveGlyph item={item} />\n <p data-fs-text=\"\" data-fs-incentive-title=\"\">\n {item.title}\n </p>\n {item.lines.map((line, lineIndex) => (\n <p key={lineIndex} data-fs-text=\"\" data-fs-incentive-description=\"\">\n {line}\n </p>\n ))}\n </>\n );\n}\n\nexport function Incentives({ items, $content, className, ...props }: IncentivesProps) {\n const resolved = resolveIncentives(readItems($content?.items, items));\n\n if (resolved.length === 0) return null;\n\n // `role` precedes the spread so a consumer can still override it.\n return (\n // biome-ignore lint/a11y/noRedundantRoles: WebKit drops the implicit list role from a ul whose computed `list-style` is `none` — exactly what this component's swatch sets — so the explicit role is what holds the semantics the list was chosen for.\n <ul role=\"list\" {...props} className={className} data-fs-incentives=\"\">\n {resolved.map((item, index) => (\n <li key={index} data-fs-incentive=\"\">\n {item.href === null ? (\n <IncentiveBody item={item} />\n ) : (\n // No `target`: these are the store's own shortcuts, not the outbound profiles the social\n // row forces a new tab for.\n <NavigationLink href={item.href} data-fs-incentive-link=\"\">\n <IncentiveBody item={item} />\n </NavigationLink>\n )}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"incentives.js","names":[],"sources":["../../../src/particles/incentives/incentives.tsx"],"sourcesContent":["import { type ContentValue, defineComponent, defineContentType } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport type { PageRef } from '../../sdk/navigation/types.js';\nimport { resolveSafeHref } from '../../utils/safe-href.js';\nimport { Icon } from '../icon/icon.js';\nimport { Image } from '../image/image.js';\nimport { NavigationLink } from '../navigation-link/navigation-link.js';\n\n// ---------------------------------------------------------------------------\n// Content model\n// ---------------------------------------------------------------------------\n\nexport const IncentivesContent = defineContentType({\n id: 'incentives',\n title: 'Incentives',\n description: 'Store benefit highlights rendered as a strip in the footer.',\n schema: {\n type: 'object',\n additionalProperties: false,\n // `items` is deliberately optional. A missing element key already omits the component before any\n // required check runs, so requiring the list would buy nothing and cost the prop fallback: an\n // entry without it would be shape-invalid and the authored `items` never reached.\n properties: {\n items: {\n type: 'array',\n title: 'Incentive items',\n // Author-time guidance only: no read-time gate enforces item bounds, so its one consumer is\n // the Content Platform Admin's form. An empty list still reaches the component, which\n // self-hides on it. No ceiling — the swatch has to lay out at any count regardless.\n minItems: 1,\n items: {\n type: 'object',\n additionalProperties: false,\n // `title` alone. A nested required property is validated at read time and a violation omits\n // the whole strip, so every entry here widens the blast radius of one under-filled item.\n required: ['title'],\n properties: {\n // `minLength` on the title alone: it is the required property, so a blank one is the only\n // blank that decides anything. Both lines render if present and drop if blank, which is\n // guidance the Admin form has no reason to state differently for one of them.\n title: { type: 'string', minLength: 1, title: 'Title' },\n firstLineText: { type: 'string', title: 'First line' },\n secondLineText: { type: 'string', title: 'Second line' },\n // Optional, because a benefit strip links nowhere and a shortcut row links everywhere,\n // and the two are the same shape. Author-time guidance only, deliberately identical to\n // FooterLinkGroup's so the Admin form cannot reject a destination `resolveSafeHref`\n // would have accepted; lookahead-free because that regex engine may be an RE2 family.\n href: {\n type: 'string',\n minLength: 1,\n title: 'Link',\n format: 'uri-reference',\n pattern: '^(?:https?://.*|mailto:.+|tel:.+|/(?:[^/].*)?)$',\n },\n // Inline rather than a named constant: the catalog scanner reads this file statically and\n // rejects an identifier it cannot evaluate.\n icon: {\n type: 'string',\n enum: ['truck', 'calendar', 'gift', 'store', 'shield-check'],\n title: 'Icon',\n },\n iconUrl: {\n type: 'string',\n format: 'uri',\n title: 'Custom icon',\n widget: { 'ui:widget': 'media-gallery' },\n },\n alt: { type: 'string', title: 'Custom icon alt text' },\n },\n },\n },\n },\n },\n});\n\n/**\n * The benefit glyphs the `icon` enum admits. Exported because a store's foundation has to list\n * them under `icons.include` for a CMS-chosen name to resolve at runtime — one import there instead\n * of five retyped strings, which is what keeps the layout task from silently missing one. Reading it\n * off the model rather than declaring it alongside makes the two impossible to drift apart.\n */\nexport const INCENTIVE_ICON_NAMES = IncentivesContent.schema.properties.items.items.properties.icon.enum;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype IncentivesContentValue = ContentValue<typeof IncentivesContent>;\n\ntype IncentiveContentItem = NonNullable<IncentivesContentValue['items']>[number];\n\n/** One incentive item. The prop accepts a page reference; a CMS href stays a string. */\nexport type IncentiveItem = Omit<IncentiveContentItem, 'href'> & {\n href?: PageRef | string;\n};\n\ntype IncentiveIconName = NonNullable<IncentiveItem['icon']>;\n\nexport type IncentivesProps = ComponentPropsWithRef<'ul'> & {\n /** Authored fallback list, rendered when no CMS entry supplies one. */\n items?: readonly IncentiveItem[];\n /** Injected by the compiler, sliced from the layout's composite content entry. */\n $content?: IncentivesContentValue;\n};\n\n// ---------------------------------------------------------------------------\n// Definition\n// ---------------------------------------------------------------------------\n\nexport const IncentivesDefinition = defineComponent({\n name: 'Incentives',\n importPath: '@vtex/faststore/components',\n component: Incentives,\n content: IncentivesContent,\n editor: { label: 'Incentives', category: 'content' },\n schema: {\n items: { type: 'array', label: 'Incentive items' },\n },\n guideline:\n \"The store's value propositions as a strip of icon-and-copy items, the whole list CMS-editable: each item carries a title, up to two description lines, either a predefined icon or an uploaded one, and an optional href that turns the whole block into a link. Every predefined icon name must be listed in the store's icons.include. Renders nothing when unconfigured. See incentives.md.\",\n});\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * The three glyph states an item can reach, kept as a union so \"at most one source\" is a property of\n * the type rather than of how the resolver happens to build it. `alt` belongs to the uploaded member\n * alone, since a sprite glyph has nothing to name.\n */\ntype ResolvedGlyph =\n | { icon: IncentiveIconName; src?: undefined; alt?: undefined }\n | { icon?: undefined; src: string; alt?: string }\n | { icon?: undefined; src?: undefined; alt?: undefined };\n\n/**\n * An item that can render: a non-blank title, its surviving description lines, a glyph state, and a\n * destination the allowlist cleared. The title is the item's identity, so it is the only part whose\n * absence drops the item.\n */\ntype ResolvedIncentive = { title: string; lines: string[]; href: PageRef | string | null } & ResolvedGlyph;\n\n/**\n * The item's destination, or null for both \"none authored\" and \"the allowlist refused it\". Unlike the\n * link group and the social row, where a link is the whole point, a refusal here costs the anchor\n * alone — an unlinked item is this component's ordinary shape, so the glyph and copy still render.\n */\nfunction readItems(\n content: readonly IncentiveContentItem[] | undefined,\n authored: readonly IncentiveItem[] | undefined,\n): readonly IncentiveItem[] {\n if (content !== undefined) return content;\n return authored ?? [];\n}\n\nfunction resolveHref(raw: PageRef | string | undefined, index: number): PageRef | string | null {\n // A page reference skips the string allowlist. Absent is \"no link\", not a rejection.\n if (typeof raw !== 'string') return raw ?? null;\n // Blank is \"no link\", not a rejection, so it never reaches the allowlist or the log.\n if (!raw.trim()) return null;\n\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n // A bounded reason and no authored value, the convention the content runtime's own log follows.\n console.warn('[Incentives] link destination rejected', { index, reason: destination.reason });\n return null;\n }\n\n return destination.href;\n}\n\n/**\n * Drops every item with no title to show, and every description line that would render empty.\n * Neither read-time gate enforces `minLength`, so both blanks reach the component. The asymmetry is\n * deliberate: an icon with no label is not an incentive, while a missing line is supplementary.\n */\nfunction resolveIncentives(items: readonly IncentiveItem[]): ResolvedIncentive[] {\n const resolved: ResolvedIncentive[] = [];\n\n items.forEach((item, index) => {\n if (!item.title.trim()) return;\n\n const lines = [item.firstLineText, item.secondLineText].filter((line): line is string => Boolean(line?.trim()));\n const href = resolveHref(item.href, index);\n\n if (item.iconUrl?.trim()) {\n resolved.push({ title: item.title, lines, href, src: item.iconUrl, alt: item.alt });\n } else if (item.icon) {\n resolved.push({ title: item.title, lines, href, icon: item.icon });\n } else {\n resolved.push({ title: item.title, lines, href });\n }\n });\n\n return resolved;\n}\n\n/**\n * The item's glyph, or nothing. Presence decides the channel — an upload first, then a predefined\n * sprite name — and an item carrying neither renders as copy alone rather than an empty slot.\n */\nfunction IncentiveGlyph({ item }: { item: ResolvedIncentive }) {\n if (item.src !== undefined) {\n return <Image src={item.src} alt={item.alt} data-fs-incentive-icon=\"\" />;\n }\n\n if (item.icon !== undefined) {\n return <Icon name={item.icon} data-fs-incentive-icon=\"\" />;\n }\n\n return null;\n}\n\n/**\n * The glyph and copy an item renders in both forms. Kept whole rather than split across the linked\n * and unlinked branches so the anchor wraps the entire block: on a shortcut row the pictogram is\n * half the click target, and a link around the label alone leaves it dead.\n */\nfunction IncentiveBody({ item }: { item: ResolvedIncentive }) {\n return (\n <>\n <IncentiveGlyph item={item} />\n <p data-fs-text=\"\" data-fs-incentive-title=\"\">\n {item.title}\n </p>\n {item.lines.map((line, lineIndex) => (\n <p key={lineIndex} data-fs-text=\"\" data-fs-incentive-description=\"\">\n {line}\n </p>\n ))}\n </>\n );\n}\n\nexport function Incentives({ items, $content, className, ...props }: IncentivesProps) {\n const resolved = resolveIncentives(readItems($content?.items, items));\n\n if (resolved.length === 0) return null;\n\n // `role` precedes the spread so a consumer can still override it.\n return (\n // biome-ignore lint/a11y/noRedundantRoles: WebKit drops the implicit list role from a ul whose computed `list-style` is `none` — exactly what this component's swatch sets — so the explicit role is what holds the semantics the list was chosen for.\n <ul role=\"list\" {...props} className={className} data-fs-incentives=\"\">\n {resolved.map((item, index) => (\n <li key={index} data-fs-incentive=\"\">\n {item.href === null ? (\n <IncentiveBody item={item} />\n ) : (\n // No `target`: these are the store's own shortcuts, not the outbound profiles the social\n // row forces a new tab for.\n <NavigationLink href={item.href} data-fs-incentive-link=\"\">\n <IncentiveBody item={item} />\n </NavigationLink>\n )}\n </li>\n ))}\n </ul>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ContentValue } from "../../core/dist/define-content-type.js";
1
+ import { ContentValue, MessageLocaleProp } from "../../core/dist/define-content-type.js";
2
2
  import { ComponentDefinition } from "../../core/dist/define-component.js";
3
3
  import "../../core/dist/index.js";
4
4
  import { ComponentPropsWithRef } from "react";
@@ -14,15 +14,17 @@ export declare const OrderDetailsBackContent: {
14
14
  readonly label: {
15
15
  readonly type: "string";
16
16
  readonly title: "Label";
17
+ readonly format: "icu-message";
18
+ readonly messageSource: "Back to orders";
17
19
  };
18
20
  };
19
21
  };
20
22
  };
21
23
  export type OrderDetailsBackContentValue = ContentValue<typeof OrderDetailsBackContent>;
22
- export type OrderDetailsBackProps = ComponentPropsWithRef<'a'> & {
24
+ export type OrderDetailsBackProps = ComponentPropsWithRef<'a'> & MessageLocaleProp & {
23
25
  $content?: OrderDetailsBackContentValue;
24
26
  };
25
27
  export declare const OrderDetailsBackDefinition: ComponentDefinition<OrderDetailsBackProps>;
26
- export declare function OrderDetailsBack({ className, ref, $content, ...props }: OrderDetailsBackProps): import("react/jsx-runtime").JSX.Element;
28
+ export declare function OrderDetailsBack({ className, ref, $content, $locale, ...props }: OrderDetailsBackProps): import("react/jsx-runtime").JSX.Element;
27
29
  //#endregion
28
30
  //# sourceMappingURL=order-details-back.d.ts.map
@@ -2,7 +2,7 @@
2
2
  import { defineComponent } from "../../core/dist/define-component.js";
3
3
  import { defineContentType } from "../../core/dist/define-content-type.js";
4
4
  import "../../core/dist/index.js";
5
- import { useIntl } from "../../sdk/i18n/client.js";
5
+ import { useMessageFormatter } from "../../sdk/i18n/use-message-formatter.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region src/particles/order-details-back/order-details-back.tsx
8
8
  const LIST_HREF = "/pvt/orders";
@@ -15,7 +15,9 @@ const OrderDetailsBackContent = defineContentType({
15
15
  additionalProperties: false,
16
16
  properties: { label: {
17
17
  type: "string",
18
- title: "Label"
18
+ title: "Label",
19
+ format: "icu-message",
20
+ messageSource: "Back to orders"
19
21
  } }
20
22
  }
21
23
  });
@@ -29,21 +31,17 @@ const OrderDetailsBackDefinition = defineComponent({
29
31
  category: "action"
30
32
  },
31
33
  schema: {},
32
- guideline: "The return from one order to the order list. Place it first on the order page when the layout has no account breadcrumb. The label is content; a blank field keeps the catalogue."
34
+ guideline: "The return from one order to the order list. Place it first on the order page when the layout has no account breadcrumb. The label is content."
33
35
  });
34
- function authored(value, fallback) {
35
- return value?.trim() || fallback;
36
- }
37
- function OrderDetailsBack({ className, ref, $content, ...props }) {
38
- const intl = useIntl();
39
- const label = authored($content?.label, intl.formatMessage({ id: "fs/order.back-to-orders" }));
36
+ function OrderDetailsBack({ className, ref, $content, $locale, ...props }) {
37
+ const { format } = useMessageFormatter(OrderDetailsBackContent, $content);
40
38
  return /* @__PURE__ */ jsx("a", {
41
39
  ...props,
42
40
  ref,
43
41
  href: LIST_HREF,
44
42
  className,
45
43
  "data-fs-order-details-back": "",
46
- children: label
44
+ children: format("label")
47
45
  });
48
46
  }
49
47
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"order-details-back.js","names":[],"sources":["../../../src/particles/order-details-back/order-details-back.tsx"],"sourcesContent":["'use client';\n\nimport { type ContentValue, defineComponent, defineContentType } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { useIntl } from '../../sdk/i18n/client.js';\n\nconst LIST_HREF = '/pvt/orders';\n\nexport const OrderDetailsBackContent = defineContentType({\n id: 'order-details-back',\n title: 'Order Details Back',\n description: 'The link back to the order list.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label' },\n },\n },\n});\n\nexport type OrderDetailsBackContentValue = ContentValue<typeof OrderDetailsBackContent>;\n\nexport type OrderDetailsBackProps = ComponentPropsWithRef<'a'> & {\n $content?: OrderDetailsBackContentValue;\n};\n\nexport const OrderDetailsBackDefinition = defineComponent<OrderDetailsBackProps>({\n name: 'OrderDetailsBack',\n importPath: '@vtex/faststore/components',\n component: OrderDetailsBack,\n content: OrderDetailsBackContent,\n editor: { label: 'Order Details Back', category: 'action' },\n schema: {},\n guideline:\n 'The return from one order to the order list. Place it first on the order page when the layout has no account breadcrumb. The label is content; a blank field keeps the catalogue.',\n});\n\nfunction authored(value: string | undefined, fallback: string): string {\n const trimmed = value?.trim();\n return trimmed || fallback;\n}\n\nexport function OrderDetailsBack({ className, ref, $content, ...props }: OrderDetailsBackProps) {\n const intl = useIntl();\n const label = authored($content?.label, intl.formatMessage({ id: 'fs/order.back-to-orders' }));\n\n return (\n <a {...props} ref={ref} href={LIST_HREF} className={className} data-fs-order-details-back=\"\">\n {label}\n </a>\n );\n}\n"],"mappings":";;;;;;;AAMA,MAAM,YAAY;AAElB,MAAa,0BAA0B,kBAAkB;CACvD,IAAI;CACJ,OAAO;CACP,aAAa;CACb,QAAQ;EACN,MAAM;EACN,sBAAsB;EACtB,YAAY,EACV,OAAO;GAAE,MAAM;GAAU,OAAO;EAAQ,EAC1C;CACF;AACF,CAAC;AAQD,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,SAAS;CACT,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAS;CAC1D,QAAQ,CAAC;CACT,WACE;AACJ,CAAC;AAED,SAAS,SAAS,OAA2B,UAA0B;CAErE,OADgB,OAAO,KAAK,KACV;AACpB;AAEA,SAAgB,iBAAiB,EAAE,WAAW,KAAK,UAAU,GAAG,SAAgC;CAC9F,MAAM,OAAO,QAAQ;CACrB,MAAM,QAAQ,SAAS,UAAU,OAAO,KAAK,cAAc,EAAE,IAAI,0BAA0B,CAAC,CAAC;CAE7F,OACE,oBAAC,KAAD;EAAG,GAAI;EAAY;EAAK,MAAM;EAAsB;EAAW,8BAA2B;EACvF,UAAA;CACA,CAAA;AAEP"}
1
+ {"version":3,"file":"order-details-back.js","names":[],"sources":["../../../src/particles/order-details-back/order-details-back.tsx"],"sourcesContent":["'use client';\n\nimport { type ContentValue, defineComponent, defineContentType, type MessageLocaleProp } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\n\nconst LIST_HREF = '/pvt/orders';\n\nexport const OrderDetailsBackContent = defineContentType({\n id: 'order-details-back',\n title: 'Order Details Back',\n description: 'The link back to the order list.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label', format: 'icu-message', messageSource: 'Back to orders' },\n },\n },\n});\n\nexport type OrderDetailsBackContentValue = ContentValue<typeof OrderDetailsBackContent>;\n\nexport type OrderDetailsBackProps = ComponentPropsWithRef<'a'> &\n MessageLocaleProp & {\n $content?: OrderDetailsBackContentValue;\n };\n\nexport const OrderDetailsBackDefinition = defineComponent<OrderDetailsBackProps>({\n name: 'OrderDetailsBack',\n importPath: '@vtex/faststore/components',\n component: OrderDetailsBack,\n content: OrderDetailsBackContent,\n editor: { label: 'Order Details Back', category: 'action' },\n schema: {},\n guideline:\n 'The return from one order to the order list. Place it first on the order page when the layout has no account breadcrumb. The label is content.',\n});\n\nexport function OrderDetailsBack({ className, ref, $content, $locale, ...props }: OrderDetailsBackProps) {\n const { format } = useMessageFormatter(OrderDetailsBackContent, $content);\n\n return (\n <a {...props} ref={ref} href={LIST_HREF} className={className} data-fs-order-details-back=\"\">\n {format('label')}\n </a>\n );\n}\n"],"mappings":";;;;;;;AAMA,MAAM,YAAY;AAElB,MAAa,0BAA0B,kBAAkB;CACvD,IAAI;CACJ,OAAO;CACP,aAAa;CACb,QAAQ;EACN,MAAM;EACN,sBAAsB;EACtB,YAAY,EACV,OAAO;GAAE,MAAM;GAAU,OAAO;GAAS,QAAQ;GAAe,eAAe;EAAiB,EAClG;CACF;AACF,CAAC;AASD,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,SAAS;CACT,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAS;CAC1D,QAAQ,CAAC;CACT,WACE;AACJ,CAAC;AAED,SAAgB,iBAAiB,EAAE,WAAW,KAAK,UAAU,SAAS,GAAG,SAAgC;CACvG,MAAM,EAAE,WAAW,oBAAoB,yBAAyB,QAAQ;CAExE,OACE,oBAAC,KAAD;EAAG,GAAI;EAAY;EAAK,MAAM;EAAsB;EAAW,8BAA2B;EACvF,UAAA,OAAO,OAAO;CACd,CAAA;AAEP"}
@@ -5,13 +5,13 @@ import { ComponentPropsWithRef } from "react";
5
5
  export type OrderStatusState = 'ongoing' | 'completed' | 'cancelled';
6
6
  export type OrderStatusTone = 'neutral' | 'progress' | 'success' | 'danger';
7
7
  export type OrderStatusMessageKey = 'cancelled' | 'cancellation-requested' | 'in-progress' | 'delivered' | 'shipped' | 'ready-for-pickup' | 'collected' | 'placeholder';
8
- /** Per-label sentences. A blank value keeps the catalogue sentence for that label. */
9
- export type OrderStatusMessages = Partial<Record<OrderStatusMessageKey, string>>;
8
+ /** The formatted sentence for each status label, supplied by the component that owns the copy. */
9
+ export type OrderStatusMessages = Record<OrderStatusMessageKey, string>;
10
10
  export type OrderStatusBadgeProps = Omit<ComponentPropsWithRef<'span'>, 'children'> & {
11
11
  state: OrderStatusState;
12
12
  tone: OrderStatusTone;
13
13
  label: string;
14
- messages?: OrderStatusMessages;
14
+ messages: OrderStatusMessages;
15
15
  };
16
16
  export declare const OrderStatusBadgeDefinition: ComponentDefinition<OrderStatusBadgeProps>;
17
17
  export declare function OrderStatusBadge({ state, tone, label, messages, className, ...props }: OrderStatusBadgeProps): import("react/jsx-runtime").JSX.Element;
@@ -1,23 +1,9 @@
1
1
  "use client";
2
2
  import { defineComponent } from "../../core/dist/define-component.js";
3
3
  import "../../core/dist/index.js";
4
- import { useIntl } from "../../sdk/i18n/client.js";
5
4
  import { Badge } from "../badge/badge.js";
6
5
  import { jsx } from "react/jsx-runtime";
7
6
  //#region src/particles/order-status-badge/order-status-badge.tsx
8
- const ORDER_STATUS_MESSAGES = {
9
- cancelled: "fs/order-status.cancelled",
10
- "cancellation-requested": "fs/order-status.cancellation-requested",
11
- "in-progress": "fs/order-status.in-progress",
12
- delivered: "fs/order-status.delivered",
13
- shipped: "fs/order-status.shipped",
14
- "ready-for-pickup": "fs/order-status.ready-for-pickup",
15
- collected: "fs/order-status.collected"
16
- };
17
- function orderStatusMessageId(label) {
18
- if (!Object.hasOwn(ORDER_STATUS_MESSAGES, label)) return "fs/order-status.placeholder";
19
- return ORDER_STATUS_MESSAGES[label] ?? "fs/order-status.placeholder";
20
- }
21
7
  const OrderStatusBadgeDefinition = defineComponent({
22
8
  name: "OrderStatusBadge",
23
9
  importPath: "@vtex/faststore/components",
@@ -27,21 +13,19 @@ const OrderStatusBadgeDefinition = defineComponent({
27
13
  category: "content"
28
14
  },
29
15
  schema: {},
30
- guideline: "Shopper-facing order status. Pass the completion view, the label id, and a tone. A messages entry replaces the catalogue sentence for that label; a blank entry and an unknown label keep the catalogue."
16
+ guideline: "Shopper-facing order status. Pass the completion view, the label id, a tone and the formatted messages; an unknown label renders the placeholder. The order list row and the order details header render it; do not place it on a page alone."
31
17
  });
32
- function messageKey(label) {
33
- return Object.hasOwn(ORDER_STATUS_MESSAGES, label) ? label : "placeholder";
18
+ function statusMessage(messages, label) {
19
+ return Object.hasOwn(messages, label) ? messages[label] : messages.placeholder;
34
20
  }
35
21
  function OrderStatusBadge({ state, tone, label, messages, className, ...props }) {
36
- const intl = useIntl();
37
- const authored = messages?.[messageKey(label)]?.trim();
38
22
  return /* @__PURE__ */ jsx(Badge, {
39
23
  ...props,
40
24
  className,
41
25
  "data-fs-order-status-badge": "",
42
26
  "data-fs-order-status-badge-state": state,
43
27
  "data-fs-order-status-badge-tone": tone,
44
- children: authored || intl.formatMessage({ id: orderStatusMessageId(label) })
28
+ children: statusMessage(messages, label)
45
29
  });
46
30
  }
47
31
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"order-status-badge.js","names":[],"sources":["../../../src/particles/order-status-badge/order-status-badge.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { useIntl } from '../../sdk/i18n/client.js';\nimport type { MessageId } from '../../sdk/i18n/locales.js';\nimport { Badge } from '../badge/badge.js';\n\nexport type OrderStatusState = 'ongoing' | 'completed' | 'cancelled';\n\nexport type OrderStatusTone = 'neutral' | 'progress' | 'success' | 'danger';\n\nexport type OrderStatusMessageKey =\n | 'cancelled'\n | 'cancellation-requested'\n | 'in-progress'\n | 'delivered'\n | 'shipped'\n | 'ready-for-pickup'\n | 'collected'\n | 'placeholder';\n\n/** Per-label sentences. A blank value keeps the catalogue sentence for that label. */\nexport type OrderStatusMessages = Partial<Record<OrderStatusMessageKey, string>>;\n\nexport type OrderStatusBadgeProps = Omit<ComponentPropsWithRef<'span'>, 'children'> & {\n state: OrderStatusState;\n tone: OrderStatusTone;\n label: string;\n messages?: OrderStatusMessages;\n};\n\nconst ORDER_STATUS_MESSAGES: Record<string, MessageId> = {\n cancelled: 'fs/order-status.cancelled',\n 'cancellation-requested': 'fs/order-status.cancellation-requested',\n 'in-progress': 'fs/order-status.in-progress',\n delivered: 'fs/order-status.delivered',\n shipped: 'fs/order-status.shipped',\n 'ready-for-pickup': 'fs/order-status.ready-for-pickup',\n collected: 'fs/order-status.collected',\n};\n\nfunction orderStatusMessageId(label: string): MessageId {\n // Bracket access walks Object.prototype, so \"constructor\" would skip the placeholder.\n if (!Object.hasOwn(ORDER_STATUS_MESSAGES, label)) {\n return 'fs/order-status.placeholder';\n }\n\n return ORDER_STATUS_MESSAGES[label] ?? 'fs/order-status.placeholder';\n}\n\nexport const OrderStatusBadgeDefinition = defineComponent<OrderStatusBadgeProps>({\n name: 'OrderStatusBadge',\n importPath: '@vtex/faststore/components',\n component: OrderStatusBadge,\n editor: { label: 'Order Status Badge', category: 'content' },\n schema: {},\n guideline:\n 'Shopper-facing order status. Pass the completion view, the label id, and a tone. A messages entry replaces the catalogue sentence for that label; a blank entry and an unknown label keep the catalogue.',\n});\n\nfunction messageKey(label: string): OrderStatusMessageKey {\n return Object.hasOwn(ORDER_STATUS_MESSAGES, label) ? (label as OrderStatusMessageKey) : 'placeholder';\n}\n\nexport function OrderStatusBadge({ state, tone, label, messages, className, ...props }: OrderStatusBadgeProps) {\n const intl = useIntl();\n const authored = messages?.[messageKey(label)]?.trim();\n\n return (\n <Badge\n {...props}\n className={className}\n data-fs-order-status-badge=\"\"\n data-fs-order-status-badge-state={state}\n data-fs-order-status-badge-tone={tone}\n >\n {authored || intl.formatMessage({ id: orderStatusMessageId(label) })}\n </Badge>\n );\n}\n"],"mappings":";;;;;;;AAgCA,MAAM,wBAAmD;CACvD,WAAW;CACX,0BAA0B;CAC1B,eAAe;CACf,WAAW;CACX,SAAS;CACT,oBAAoB;CACpB,WAAW;AACb;AAEA,SAAS,qBAAqB,OAA0B;CAEtD,IAAI,CAAC,OAAO,OAAO,uBAAuB,KAAK,GAC7C,OAAO;CAGT,OAAO,sBAAsB,UAAU;AACzC;AAEA,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAU;CAC3D,QAAQ,CAAC;CACT,WACE;AACJ,CAAC;AAED,SAAS,WAAW,OAAsC;CACxD,OAAO,OAAO,OAAO,uBAAuB,KAAK,IAAK,QAAkC;AAC1F;AAEA,SAAgB,iBAAiB,EAAE,OAAO,MAAM,OAAO,UAAU,WAAW,GAAG,SAAgC;CAC7G,MAAM,OAAO,QAAQ;CACrB,MAAM,WAAW,WAAW,WAAW,KAAK,EAAE,EAAE,KAAK;CAErD,OACE,oBAAC,OAAD;EACE,GAAI;EACO;EACX,8BAA2B;EAC3B,oCAAkC;EAClC,mCAAiC;EAEhC,UAAA,YAAY,KAAK,cAAc,EAAE,IAAI,qBAAqB,KAAK,EAAE,CAAC;CAC9D,CAAA;AAEX"}
1
+ {"version":3,"file":"order-status-badge.js","names":[],"sources":["../../../src/particles/order-status-badge/order-status-badge.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { Badge } from '../badge/badge.js';\n\nexport type OrderStatusState = 'ongoing' | 'completed' | 'cancelled';\n\nexport type OrderStatusTone = 'neutral' | 'progress' | 'success' | 'danger';\n\nexport type OrderStatusMessageKey =\n | 'cancelled'\n | 'cancellation-requested'\n | 'in-progress'\n | 'delivered'\n | 'shipped'\n | 'ready-for-pickup'\n | 'collected'\n | 'placeholder';\n\n/** The formatted sentence for each status label, supplied by the component that owns the copy. */\nexport type OrderStatusMessages = Record<OrderStatusMessageKey, string>;\n\nexport type OrderStatusBadgeProps = Omit<ComponentPropsWithRef<'span'>, 'children'> & {\n state: OrderStatusState;\n tone: OrderStatusTone;\n label: string;\n messages: OrderStatusMessages;\n};\n\nexport const OrderStatusBadgeDefinition = defineComponent<OrderStatusBadgeProps>({\n name: 'OrderStatusBadge',\n importPath: '@vtex/faststore/components',\n component: OrderStatusBadge,\n editor: { label: 'Order Status Badge', category: 'content' },\n schema: {},\n guideline:\n 'Shopper-facing order status. Pass the completion view, the label id, a tone and the formatted messages; an unknown label renders the placeholder. The order list row and the order details header render it; do not place it on a page alone.',\n});\n\nfunction statusMessage(messages: OrderStatusMessages, label: string): string {\n // Bracket access walks Object.prototype, so \"constructor\" would skip the placeholder.\n return Object.hasOwn(messages, label) ? messages[label as OrderStatusMessageKey] : messages.placeholder;\n}\n\nexport function OrderStatusBadge({ state, tone, label, messages, className, ...props }: OrderStatusBadgeProps) {\n return (\n <Badge\n {...props}\n className={className}\n data-fs-order-status-badge=\"\"\n data-fs-order-status-badge-state={state}\n data-fs-order-status-badge-tone={tone}\n >\n {statusMessage(messages, label)}\n </Badge>\n );\n}\n"],"mappings":";;;;;;AA8BA,MAAa,6BAA6B,gBAAuC;CAC/E,MAAM;CACN,YAAY;CACZ,WAAW;CACX,QAAQ;EAAE,OAAO;EAAsB,UAAU;CAAU;CAC3D,QAAQ,CAAC;CACT,WACE;AACJ,CAAC;AAED,SAAS,cAAc,UAA+B,OAAuB;CAE3E,OAAO,OAAO,OAAO,UAAU,KAAK,IAAI,SAAS,SAAkC,SAAS;AAC9F;AAEA,SAAgB,iBAAiB,EAAE,OAAO,MAAM,OAAO,UAAU,WAAW,GAAG,SAAgC;CAC7G,OACE,oBAAC,OAAD;EACE,GAAI;EACO;EACX,8BAA2B;EAC3B,oCAAkC;EAClC,mCAAiC;EAEhC,UAAA,cAAc,UAAU,KAAK;CACzB,CAAA;AAEX"}
@@ -26,6 +26,6 @@ export declare const PasswordFieldDefinition: ComponentDefinition<PasswordFieldP
26
26
  * toggle. Presence-only validation is caller-driven via `invalid`/`errorMessage` — this
27
27
  * particle computes no validity of its own. `revealed` is local, uncontrolled UI state.
28
28
  */
29
- export declare function PasswordField({ value, defaultValue, onValueChange, invalid, errorMessage, label, placeholder, requirement, autoComplete, showPasswordLabel, hidePasswordLabel, disabled, name, id, className }: PasswordFieldProps): import("react/jsx-runtime").JSX.Element;
29
+ export declare function PasswordField({ value, defaultValue, onValueChange, invalid, errorMessage, label, placeholder, requirement, autoComplete, showPasswordLabel, hidePasswordLabel, disabled, name, id, className }: Readonly<PasswordFieldProps>): import("react/jsx-runtime").JSX.Element;
30
30
  //#endregion
31
31
  //# sourceMappingURL=password-field.d.ts.map
@@ -37,12 +37,10 @@ const PasswordFieldDefinition = defineComponent({
37
37
  },
38
38
  showPasswordLabel: {
39
39
  type: "string",
40
- default: "Show password",
41
40
  label: "Show password label"
42
41
  },
43
42
  hidePasswordLabel: {
44
43
  type: "string",
45
- default: "Hide password",
46
44
  label: "Hide password label"
47
45
  },
48
46
  disabled: {
@@ -51,14 +49,14 @@ const PasswordFieldDefinition = defineComponent({
51
49
  label: "Disabled"
52
50
  }
53
51
  },
54
- guideline: "Presentational password input with a show/hide reveal toggle. Set autoComplete=\"new-password\" for recovery/set-password screens (default is \"current-password\" for sign-in). No validation beyond presence — invalid/errorMessage are caller-driven. No data layer: does not call login, does not read session."
52
+ guideline: "Presentational password input with a show/hide reveal toggle. Set autoComplete=\"new-password\" for recovery/set-password screens (default is \"current-password\" for sign-in). The owner passes showPasswordLabel and hidePasswordLabel already formatted; they have no default. No validation beyond presence — invalid/errorMessage are caller-driven. No data layer: does not call login, does not read session."
55
53
  });
56
54
  /**
57
55
  * Composes Field + Input + Toggle + Icon into a password input with a show/hide reveal
58
56
  * toggle. Presence-only validation is caller-driven via `invalid`/`errorMessage` — this
59
57
  * particle computes no validity of its own. `revealed` is local, uncontrolled UI state.
60
58
  */
61
- function PasswordField({ value, defaultValue, onValueChange, invalid = false, errorMessage, label, placeholder, requirement = "mandatory", autoComplete = "current-password", showPasswordLabel = "Show password", hidePasswordLabel = "Hide password", disabled = false, name, id, className }) {
59
+ function PasswordField({ value, defaultValue, onValueChange, invalid = false, errorMessage, label, placeholder, requirement = "mandatory", autoComplete = "current-password", showPasswordLabel, hidePasswordLabel, disabled = false, name, id, className }) {
62
60
  const [revealed, setRevealed] = useState(false);
63
61
  function handleChange(event) {
64
62
  onValueChange?.(event.target.value);