@vtex/faststore 0.0.7 → 0.0.10

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 (498) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/dist/actions.json +194 -1
  3. package/dist/catalog.json +3449 -1612
  4. package/dist/cli/index.d.ts +512 -63
  5. package/dist/cli/index.js +2098 -686
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/server-runtime.js +44 -24
  8. package/dist/cli/server-runtime.js.map +1 -1
  9. package/dist/client.d.ts +5 -1
  10. package/dist/client.js +5 -1
  11. package/dist/components.d.ts +42 -10
  12. package/dist/components.js +47 -15
  13. package/dist/content-types.json +823 -0
  14. package/dist/core/dist/define-component.d.ts +12 -2
  15. package/dist/docs/account-access-gate.md +4 -4
  16. package/dist/docs/account-address-book.md +519 -0
  17. package/dist/docs/account-entry-point.md +5 -5
  18. package/dist/docs/account-menu.md +7 -7
  19. package/dist/docs/account-saved-cards.md +301 -0
  20. package/dist/docs/alert-dialog.md +2 -2
  21. package/dist/docs/billing-address.md +17 -9
  22. package/dist/docs/binding-switcher.md +154 -0
  23. package/dist/docs/card-entry.md +38 -7
  24. package/dist/docs/card-summary.md +175 -0
  25. package/dist/docs/cardholder-document.md +16 -14
  26. package/dist/docs/cart-destination.md +238 -0
  27. package/dist/docs/cart-item.md +22 -4
  28. package/dist/docs/cart-totalizer.md +1 -1
  29. package/dist/docs/cart.md +126 -19
  30. package/dist/docs/client-profile-fieldset.md +7 -5
  31. package/dist/docs/copy-text.md +84 -0
  32. package/dist/docs/document-field.md +8 -8
  33. package/dist/docs/footer-link-group.md +2 -2
  34. package/dist/docs/footer-social.md +1 -1
  35. package/dist/docs/free-shipping-progress.md +13 -9
  36. package/dist/docs/header-root.md +1 -1
  37. package/dist/docs/incentives.md +4 -4
  38. package/dist/docs/logo.md +6 -6
  39. package/dist/docs/my-account-profile.md +4 -4
  40. package/dist/docs/navigation-link-list.md +2 -2
  41. package/dist/docs/navigation-link.md +3 -3
  42. package/dist/docs/order-cancel.md +52 -0
  43. package/dist/docs/order-delivery-address.md +63 -0
  44. package/dist/docs/order-delivery-group.md +83 -0
  45. package/dist/docs/order-details-back.md +41 -0
  46. package/dist/docs/order-details-header.md +48 -0
  47. package/dist/docs/order-list-row.md +46 -0
  48. package/dist/docs/order-list-search.md +101 -0
  49. package/dist/docs/order-list-views.md +97 -0
  50. package/dist/docs/order-list.md +94 -0
  51. package/dist/docs/order-payment.md +94 -0
  52. package/dist/docs/order-placed-date.md +49 -0
  53. package/dist/docs/order-placed-payment-summary.md +13 -15
  54. package/dist/docs/order-placed.md +225 -0
  55. package/dist/docs/order-progress.md +88 -0
  56. package/dist/docs/order-status-badge.md +91 -0
  57. package/dist/docs/order-summary.md +53 -0
  58. package/dist/docs/payment-method-badges.md +16 -5
  59. package/dist/docs/payment-methods.md +1 -1
  60. package/dist/docs/place-order.md +13 -9
  61. package/dist/docs/product-information.md +2 -2
  62. package/dist/docs/product-shelf.md +7 -0
  63. package/dist/docs/saved-cards.md +2 -2
  64. package/dist/docs/select.md +22 -10
  65. package/dist/docs/session.md +1 -1
  66. package/dist/docs/shipping-address.md +1 -1
  67. package/dist/docs/sign-in-redirect.md +7 -7
  68. package/dist/docs/toast.md +35 -13
  69. package/dist/index.d.ts +7 -2
  70. package/dist/index.js +2 -1
  71. package/dist/internal/client.d.ts +9 -1
  72. package/dist/internal/client.js +10 -2
  73. package/dist/internal/server.d.ts +8 -2
  74. package/dist/internal/server.js +8 -2
  75. package/dist/matter/account-access-gate/account-access-gate.d.ts +2 -1
  76. package/dist/matter/account-access-gate/account-access-gate.js +19 -16
  77. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
  78. package/dist/matter/account-address-book/account-address-book-delete.d.ts +60 -0
  79. package/dist/matter/account-address-book/account-address-book-delete.js +184 -0
  80. package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -0
  81. package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +19 -0
  82. package/dist/matter/account-address-book/account-address-book-deliverability.js +50 -0
  83. package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -0
  84. package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +42 -0
  85. package/dist/matter/account-address-book/account-address-book-form-parts.js +146 -0
  86. package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -0
  87. package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +25 -0
  88. package/dist/matter/account-address-book/account-address-book-profile-notice.js +72 -0
  89. package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -0
  90. package/dist/matter/account-address-book/account-address-book.d.ts +120 -0
  91. package/dist/matter/account-address-book/account-address-book.js +469 -0
  92. package/dist/matter/account-address-book/account-address-book.js.map +1 -0
  93. package/dist/matter/account-address-book/account-address-country-switch.js +59 -0
  94. package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -0
  95. package/dist/matter/account-address-book/account-address-country.d.ts +36 -0
  96. package/dist/matter/account-address-book/account-address-country.js +151 -0
  97. package/dist/matter/account-address-book/account-address-country.js.map +1 -0
  98. package/dist/matter/account-address-book/account-address-first-line.js +11 -0
  99. package/dist/matter/account-address-book/account-address-first-line.js.map +1 -0
  100. package/dist/matter/account-address-book/account-address-form-context.d.ts +55 -0
  101. package/dist/matter/account-address-book/account-address-form-context.js +14 -0
  102. package/dist/matter/account-address-book/account-address-form-context.js.map +1 -0
  103. package/dist/matter/account-address-book/account-address-form.d.ts +85 -0
  104. package/dist/matter/account-address-book/account-address-form.js +946 -0
  105. package/dist/matter/account-address-book/account-address-form.js.map +1 -0
  106. package/dist/matter/account-address-book/account-address-postal-autofill.js +189 -0
  107. package/dist/matter/account-address-book/account-address-postal-autofill.js.map +1 -0
  108. package/dist/matter/account-address-book/account-address-record.d.ts +26 -0
  109. package/dist/matter/account-address-book/account-address-record.js +138 -0
  110. package/dist/matter/account-address-book/account-address-record.js.map +1 -0
  111. package/dist/matter/account-entry-point/account-entry-point.js +11 -11
  112. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  113. package/dist/matter/account-menu/account-menu.d.ts +7 -3
  114. package/dist/matter/account-menu/account-menu.js +69 -28
  115. package/dist/matter/account-menu/account-menu.js.map +1 -1
  116. package/dist/matter/account-saved-cards/account-saved-cards.d.ts +383 -0
  117. package/dist/matter/account-saved-cards/account-saved-cards.js +956 -0
  118. package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
  119. package/dist/matter/billing-address/billing-address.d.ts +30 -17
  120. package/dist/matter/billing-address/billing-address.js +128 -33
  121. package/dist/matter/billing-address/billing-address.js.map +1 -1
  122. package/dist/matter/breadcrumb/breadcrumb.js +2 -2
  123. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
  124. package/dist/matter/card-entry/card-capture.js +4 -3
  125. package/dist/matter/card-entry/card-capture.js.map +1 -1
  126. package/dist/matter/card-entry/card-entry.d.ts +5 -3
  127. package/dist/matter/card-entry/card-entry.js +77 -27
  128. package/dist/matter/card-entry/card-entry.js.map +1 -1
  129. package/dist/matter/cardholder-document/cardholder-document.d.ts +10 -9
  130. package/dist/matter/cardholder-document/cardholder-document.js +36 -16
  131. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -1
  132. package/dist/matter/cart/cart-namespace.d.ts +5 -1
  133. package/dist/matter/cart/cart-namespace.js +5 -1
  134. package/dist/matter/cart/cart-namespace.js.map +1 -1
  135. package/dist/matter/cart/cart.d.ts +41 -6
  136. package/dist/matter/cart/cart.js +267 -54
  137. package/dist/matter/cart/cart.js.map +1 -1
  138. package/dist/matter/cart-destination/cart-destination.d.ts +222 -0
  139. package/dist/matter/cart-destination/cart-destination.js +613 -0
  140. package/dist/matter/cart-destination/cart-destination.js.map +1 -0
  141. package/dist/matter/cart-item/cart-item.d.ts +4 -2
  142. package/dist/matter/cart-item/cart-item.js +76 -17
  143. package/dist/matter/cart-item/cart-item.js.map +1 -1
  144. package/dist/matter/cart-totalizer/cart-totalizer.js +3 -2
  145. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
  146. package/dist/matter/client-preferences/client-preferences-fieldset.js +1 -1
  147. package/dist/matter/client-profile-form/client-profile-fieldset.js +8 -5
  148. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
  149. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +6 -3
  150. package/dist/matter/free-shipping-progress/free-shipping-progress.js +76 -33
  151. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
  152. package/dist/matter/identity-edit/identity-edit.js +3 -3
  153. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  154. package/dist/matter/identity-summary/identity-summary.js +2 -2
  155. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  156. package/dist/matter/my-account-profile/my-account-profile.d.ts +3 -3
  157. package/dist/matter/my-account-profile/my-account-profile.js +4 -4
  158. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  159. package/dist/matter/order-cancel/order-cancel.d.ts +110 -0
  160. package/dist/matter/order-cancel/order-cancel.js +344 -0
  161. package/dist/matter/order-cancel/order-cancel.js.map +1 -0
  162. package/dist/matter/order-delivery-address/order-delivery-address.d.ts +73 -0
  163. package/dist/matter/order-delivery-address/order-delivery-address.js +172 -0
  164. package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -0
  165. package/dist/matter/order-delivery-group/order-delivery-group.d.ts +128 -0
  166. package/dist/matter/order-delivery-group/order-delivery-group.js +408 -0
  167. package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -0
  168. package/dist/matter/order-details-header/order-details-header.d.ts +104 -0
  169. package/dist/matter/order-details-header/order-details-header.js +190 -0
  170. package/dist/matter/order-details-header/order-details-header.js.map +1 -0
  171. package/dist/matter/order-list/customer-orders-filter.d.ts +12 -0
  172. package/dist/matter/order-list/customer-orders-filter.js +30 -0
  173. package/dist/matter/order-list/customer-orders-filter.js.map +1 -0
  174. package/dist/matter/order-list/order-list.d.ts +121 -0
  175. package/dist/matter/order-list/order-list.js +395 -0
  176. package/dist/matter/order-list/order-list.js.map +1 -0
  177. package/dist/matter/order-list-row/order-list-row.d.ts +44 -0
  178. package/dist/matter/order-list-row/order-list-row.js +127 -0
  179. package/dist/matter/order-list-row/order-list-row.js.map +1 -0
  180. package/dist/matter/order-list-search/order-list-search.d.ts +72 -0
  181. package/dist/matter/order-list-search/order-list-search.js +296 -0
  182. package/dist/matter/order-list-search/order-list-search.js.map +1 -0
  183. package/dist/matter/order-list-views/order-list-views.d.ts +65 -0
  184. package/dist/matter/order-list-views/order-list-views.js +154 -0
  185. package/dist/matter/order-list-views/order-list-views.js.map +1 -0
  186. package/dist/matter/order-payment/order-payment.d.ts +83 -0
  187. package/dist/matter/order-payment/order-payment.js +258 -0
  188. package/dist/matter/order-payment/order-payment.js.map +1 -0
  189. package/dist/matter/order-placed/order-placed-deliveries.d.ts +145 -0
  190. package/dist/matter/order-placed/order-placed-deliveries.js +380 -0
  191. package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -0
  192. package/dist/matter/order-placed/order-placed.d.ts +122 -0
  193. package/dist/matter/order-placed/order-placed.js +452 -0
  194. package/dist/matter/order-placed/order-placed.js.map +1 -0
  195. package/dist/matter/order-placed-date/order-placed-date.d.ts +45 -0
  196. package/dist/matter/order-placed-date/order-placed-date.js +92 -0
  197. package/dist/matter/order-placed-date/order-placed-date.js.map +1 -0
  198. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +5 -8
  199. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +29 -81
  200. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
  201. package/dist/matter/order-progress/order-progress.d.ts +85 -0
  202. package/dist/matter/order-progress/order-progress.js +203 -0
  203. package/dist/matter/order-progress/order-progress.js.map +1 -0
  204. package/dist/matter/order-summary/order-summary.d.ts +81 -0
  205. package/dist/matter/order-summary/order-summary.js +192 -0
  206. package/dist/matter/order-summary/order-summary.js.map +1 -0
  207. package/dist/matter/payment/cardholder-document-rule.d.ts +35 -0
  208. package/dist/matter/payment/cardholder-document-rule.js +35 -0
  209. package/dist/matter/payment/cardholder-document-rule.js.map +1 -0
  210. package/dist/matter/payment/payment-card-capture.js +38 -23
  211. package/dist/matter/payment/payment-card-capture.js.map +1 -1
  212. package/dist/matter/payment/payment-controller.js +11 -0
  213. package/dist/matter/payment/payment-controller.js.map +1 -1
  214. package/dist/matter/payment/payment-method-badges.js +4 -2
  215. package/dist/matter/payment/payment-method-badges.js.map +1 -1
  216. package/dist/matter/payment/payment.js +11 -0
  217. package/dist/matter/payment/payment.js.map +1 -1
  218. package/dist/matter/payment/use-payment-method-selection.d.ts +39 -0
  219. package/dist/matter/payment/use-payment-method-selection.js +30 -2
  220. package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
  221. package/dist/matter/payment/use-payment-submit-gate.d.ts +16 -2
  222. package/dist/matter/payment/use-payment-submit-gate.js +42 -14
  223. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
  224. package/dist/matter/place-order/place-order.d.ts +12 -7
  225. package/dist/matter/place-order/place-order.js +126 -103
  226. package/dist/matter/place-order/place-order.js.map +1 -1
  227. package/dist/matter/pricing/pricing.js +5 -5
  228. package/dist/matter/pricing/pricing.js.map +1 -1
  229. package/dist/matter/product-shelf/product-shelf.d.ts +7 -0
  230. package/dist/matter/product-shelf/product-shelf.js +115 -1
  231. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  232. package/dist/matter/region/region.js +1 -1
  233. package/dist/matter/saved-cards/saved-cards.js +26 -15
  234. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  235. package/dist/matter/session/session.js +2 -2
  236. package/dist/matter/session/session.js.map +1 -1
  237. package/dist/matter/shipping-address/country-descriptors.d.ts +1 -0
  238. package/dist/matter/shipping-address/country-descriptors.js +23 -1
  239. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  240. package/dist/matter/shipping-address/shipping-address.js +62 -14
  241. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  242. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +2 -2
  243. package/dist/matter/shipping-simulator/shipping-simulator.js +6 -2
  244. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  245. package/dist/matter/sign-in-redirect/sign-in-redirect.js +48 -10
  246. package/dist/matter/sign-in-redirect/sign-in-redirect.js.map +1 -1
  247. package/dist/matter/variant-selector/variant-selector.js +2 -2
  248. package/dist/matter/variant-selector/variant-selector.js.map +1 -1
  249. package/dist/particles/address-summary/address-summary.js +2 -2
  250. package/dist/particles/address-summary/address-summary.js.map +1 -1
  251. package/dist/particles/alert-dialog/alert-dialog.d.ts +5 -1
  252. package/dist/particles/alert-dialog/alert-dialog.js +5 -2
  253. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -1
  254. package/dist/particles/binding-switcher/binding-switcher.d.ts +38 -0
  255. package/dist/particles/binding-switcher/binding-switcher.js +183 -0
  256. package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
  257. package/dist/particles/card-summary/card-network.d.ts +17 -0
  258. package/dist/particles/card-summary/card-network.js +25 -0
  259. package/dist/particles/card-summary/card-network.js.map +1 -0
  260. package/dist/particles/card-summary/card-summary.d.ts +83 -0
  261. package/dist/particles/card-summary/card-summary.js +188 -0
  262. package/dist/particles/card-summary/card-summary.js.map +1 -0
  263. package/dist/particles/copy-text/copy-text.d.ts +28 -0
  264. package/dist/particles/copy-text/copy-text.js +140 -0
  265. package/dist/particles/copy-text/copy-text.js.map +1 -0
  266. package/dist/particles/document-field/document-field.d.ts +34 -5
  267. package/dist/particles/document-field/document-field.js +115 -19
  268. package/dist/particles/document-field/document-field.js.map +1 -1
  269. package/dist/particles/field/field.js +1 -1
  270. package/dist/particles/field/field.js.map +1 -1
  271. package/dist/particles/footer-link-group/footer-link-group.d.ts +6 -2
  272. package/dist/particles/footer-link-group/footer-link-group.js +18 -7
  273. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
  274. package/dist/particles/footer-social/footer-social.d.ts +1 -1
  275. package/dist/particles/footer-social/footer-social.js +1 -1
  276. package/dist/particles/footer-social/footer-social.js.map +1 -1
  277. package/dist/particles/incentives/incentives.d.ts +7 -3
  278. package/dist/particles/incentives/incentives.js +8 -3
  279. package/dist/particles/incentives/incentives.js.map +1 -1
  280. package/dist/particles/logo/logo.d.ts +3 -2
  281. package/dist/particles/logo/logo.js +20 -8
  282. package/dist/particles/logo/logo.js.map +1 -1
  283. package/dist/particles/navigation-link/navigation-link.d.ts +2 -3
  284. package/dist/particles/navigation-link/navigation-link.js +4 -4
  285. package/dist/particles/navigation-link/navigation-link.js.map +1 -1
  286. package/dist/particles/navigation-link-list/navigation-link-list.d.ts +6 -2
  287. package/dist/particles/navigation-link-list/navigation-link-list.js +18 -7
  288. package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -1
  289. package/dist/particles/order-details-back/order-details-back.d.ts +28 -0
  290. package/dist/particles/order-details-back/order-details-back.js +52 -0
  291. package/dist/particles/order-details-back/order-details-back.js.map +1 -0
  292. package/dist/particles/order-status-badge/order-status-badge.d.ts +19 -0
  293. package/dist/particles/order-status-badge/order-status-badge.js +50 -0
  294. package/dist/particles/order-status-badge/order-status-badge.js.map +1 -0
  295. package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
  296. package/dist/particles/payment-methods/payment-methods.js +1 -1
  297. package/dist/particles/payment-methods/payment-methods.js.map +1 -1
  298. package/dist/particles/phone-field/phone-field.js +2 -2
  299. package/dist/particles/phone-field/phone-field.js.map +1 -1
  300. package/dist/particles/select/select.js +6 -6
  301. package/dist/particles/select/select.js.map +1 -1
  302. package/dist/particles/toast/toast.d.ts +21 -7
  303. package/dist/particles/toast/toast.js +76 -8
  304. package/dist/particles/toast/toast.js.map +1 -1
  305. package/dist/schema.graphql +1376 -126
  306. package/dist/sdk/actions/address-action-provider.d.ts +16 -0
  307. package/dist/sdk/actions/address-action-provider.js +20 -0
  308. package/dist/sdk/actions/address-action-provider.js.map +1 -0
  309. package/dist/sdk/actions/analytics-action-provider.js +1 -1
  310. package/dist/sdk/actions/index.d.ts +5 -1
  311. package/dist/sdk/actions/index.js +5 -1
  312. package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
  313. package/dist/sdk/actions/locale-action-provider.js +20 -0
  314. package/dist/sdk/actions/locale-action-provider.js.map +1 -0
  315. package/dist/sdk/actions/order-action-provider.d.ts +12 -0
  316. package/dist/sdk/actions/order-action-provider.js +16 -0
  317. package/dist/sdk/actions/order-action-provider.js.map +1 -0
  318. package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
  319. package/dist/sdk/actions/saved-card-action-provider.js +16 -0
  320. package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
  321. package/dist/sdk/actions/types.d.ts +10 -2
  322. package/dist/sdk/address/address-fields.js +38 -0
  323. package/dist/sdk/address/address-fields.js.map +1 -0
  324. package/dist/sdk/address/checkout-readiness.js +17 -0
  325. package/dist/sdk/address/checkout-readiness.js.map +1 -0
  326. package/dist/sdk/address/constants.js +60 -0
  327. package/dist/sdk/address/constants.js.map +1 -0
  328. package/dist/sdk/address/country-display.js +19 -0
  329. package/dist/sdk/address/country-display.js.map +1 -0
  330. package/dist/sdk/address/country-rules.js +30 -0
  331. package/dist/sdk/address/country-rules.js.map +1 -0
  332. package/dist/sdk/address/format-address.js +18 -0
  333. package/dist/sdk/address/format-address.js.map +1 -0
  334. package/dist/sdk/address/iso-countries.js +262 -0
  335. package/dist/sdk/address/iso-countries.js.map +1 -0
  336. package/dist/sdk/address/layouts.js +56 -0
  337. package/dist/sdk/address/layouts.js.map +1 -0
  338. package/dist/sdk/address/messages.js +97 -0
  339. package/dist/sdk/address/messages.js.map +1 -0
  340. package/dist/sdk/address/operations.d.ts +54 -0
  341. package/dist/sdk/address/operations.js +83 -0
  342. package/dist/sdk/address/operations.js.map +1 -0
  343. package/dist/sdk/address/postal-code-lookup-operations.js +23 -0
  344. package/dist/sdk/address/postal-code-lookup-operations.js.map +1 -0
  345. package/dist/sdk/address/postal-code.js +11 -0
  346. package/dist/sdk/address/postal-code.js.map +1 -0
  347. package/dist/sdk/address/schema.js +14 -0
  348. package/dist/sdk/address/schema.js.map +1 -0
  349. package/dist/sdk/address/server-fields.js +25 -0
  350. package/dist/sdk/address/server-fields.js.map +1 -0
  351. package/dist/sdk/address/switch-country.js +57 -0
  352. package/dist/sdk/address/switch-country.js.map +1 -0
  353. package/dist/sdk/address/types.d.ts +26 -0
  354. package/dist/sdk/address/use-address-actions.d.ts +29 -0
  355. package/dist/sdk/address/use-address-actions.js +247 -0
  356. package/dist/sdk/address/use-address-actions.js.map +1 -0
  357. package/dist/sdk/address/use-address-by-postal-code.js +57 -0
  358. package/dist/sdk/address/use-address-by-postal-code.js.map +1 -0
  359. package/dist/sdk/address/validate-address.js +62 -0
  360. package/dist/sdk/address/validate-address.js.map +1 -0
  361. package/dist/sdk/cache/storefront-cache.js +30 -4
  362. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  363. package/dist/sdk/cart/operations.d.ts +2 -1
  364. package/dist/sdk/cart/operations.js +55 -1
  365. package/dist/sdk/cart/operations.js.map +1 -1
  366. package/dist/sdk/cart/optimistic.d.ts +30 -7
  367. package/dist/sdk/cart/optimistic.js +78 -41
  368. package/dist/sdk/cart/optimistic.js.map +1 -1
  369. package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
  370. package/dist/sdk/cart/use-cart-actions.js +61 -15
  371. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  372. package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
  373. package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
  374. package/dist/sdk/client/fetch-page-data.d.ts +11 -0
  375. package/dist/sdk/client/fetch-page-data.js +12 -1
  376. package/dist/sdk/client/fetch-page-data.js.map +1 -1
  377. package/dist/sdk/content/create-content-runtime.js +1 -8
  378. package/dist/sdk/content/create-content-runtime.js.map +1 -1
  379. package/dist/sdk/data/failed-fields.js +23 -0
  380. package/dist/sdk/data/failed-fields.js.map +1 -0
  381. package/dist/sdk/data/index.js +2 -2
  382. package/dist/sdk/data/page-reactive-data-root.d.ts +45 -7
  383. package/dist/sdk/data/page-reactive-data-root.js +88 -12
  384. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  385. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  386. package/dist/sdk/generated/fragment-types.js +2 -0
  387. package/dist/sdk/generated/fragment-types.js.map +1 -1
  388. package/dist/sdk/generated/gql.js +17 -11
  389. package/dist/sdk/generated/gql.js.map +1 -1
  390. package/dist/sdk/generated/graphql.d.ts +185 -46
  391. package/dist/sdk/generated/graphql.js +2587 -155
  392. package/dist/sdk/generated/graphql.js.map +1 -1
  393. package/dist/sdk/i18n/messages/en-US.js +157 -1
  394. package/dist/sdk/i18n/messages/en-US.json +157 -1
  395. package/dist/sdk/i18n/messages/en-US.json.d.ts +156 -0
  396. package/dist/sdk/i18n/messages/es-ES.js +157 -1
  397. package/dist/sdk/i18n/messages/es-ES.json +157 -1
  398. package/dist/sdk/i18n/messages/pt-BR.js +157 -1
  399. package/dist/sdk/i18n/messages/pt-BR.json +157 -1
  400. package/dist/sdk/i18n/provider.js +1 -1
  401. package/dist/sdk/i18n/provider.js.map +1 -1
  402. package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
  403. package/dist/sdk/locale/binding-switch-provider.js +20 -0
  404. package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
  405. package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
  406. package/dist/sdk/locale/use-locale-actions.js +70 -0
  407. package/dist/sdk/locale/use-locale-actions.js.map +1 -0
  408. package/dist/sdk/navigation/binding-switch.d.ts +39 -0
  409. package/dist/sdk/navigation/binding-switch.js +129 -0
  410. package/dist/sdk/navigation/binding-switch.js.map +1 -0
  411. package/dist/sdk/navigation/current-page.js +30 -0
  412. package/dist/sdk/navigation/current-page.js.map +1 -0
  413. package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
  414. package/dist/sdk/navigation/decode-route-params.js +32 -0
  415. package/dist/sdk/navigation/decode-route-params.js.map +1 -0
  416. package/dist/sdk/navigation/not-found-log.d.ts +28 -0
  417. package/dist/sdk/navigation/not-found-log.js +133 -0
  418. package/dist/sdk/navigation/not-found-log.js.map +1 -0
  419. package/dist/sdk/navigation/path.js +25 -0
  420. package/dist/sdk/navigation/path.js.map +1 -0
  421. package/dist/sdk/navigation/redirect.d.ts +11 -0
  422. package/dist/sdk/navigation/redirect.js +22 -0
  423. package/dist/sdk/navigation/redirect.js.map +1 -0
  424. package/dist/sdk/navigation/report.js +70 -0
  425. package/dist/sdk/navigation/report.js.map +1 -0
  426. package/dist/sdk/navigation/resolve-storefront-href.d.ts +12 -0
  427. package/dist/sdk/navigation/resolve-storefront-href.js +214 -0
  428. package/dist/sdk/navigation/resolve-storefront-href.js.map +1 -0
  429. package/dist/sdk/navigation/route-identity-provider.d.ts +11 -0
  430. package/dist/sdk/navigation/route-identity-provider.js +20 -0
  431. package/dist/sdk/navigation/route-identity-provider.js.map +1 -0
  432. package/dist/sdk/navigation/route-map-provider.d.ts +19 -0
  433. package/dist/sdk/navigation/route-map-provider.js +29 -0
  434. package/dist/sdk/navigation/route-map-provider.js.map +1 -0
  435. package/dist/sdk/navigation/storefront-link.d.ts +16 -0
  436. package/dist/sdk/navigation/storefront-link.js +66 -0
  437. package/dist/sdk/navigation/storefront-link.js.map +1 -0
  438. package/dist/sdk/navigation/types.d.ts +45 -0
  439. package/dist/sdk/navigation/use-storefront-navigation.d.ts +26 -0
  440. package/dist/sdk/navigation/use-storefront-navigation.js +73 -0
  441. package/dist/sdk/navigation/use-storefront-navigation.js.map +1 -0
  442. package/dist/sdk/navigation/use-storefront-route.d.ts +26 -0
  443. package/dist/sdk/navigation/use-storefront-route.js +87 -0
  444. package/dist/sdk/navigation/use-storefront-route.js.map +1 -0
  445. package/dist/sdk/navigation/use-storefront-search-params.d.ts +11 -0
  446. package/dist/sdk/navigation/use-storefront-search-params.js +16 -0
  447. package/dist/sdk/navigation/use-storefront-search-params.js.map +1 -0
  448. package/dist/sdk/orders/completion-badge.d.ts +8 -0
  449. package/dist/sdk/orders/completion-badge.js +47 -0
  450. package/dist/sdk/orders/completion-badge.js.map +1 -0
  451. package/dist/sdk/orders/order-operations.d.ts +19 -0
  452. package/dist/sdk/orders/order-operations.js +21 -0
  453. package/dist/sdk/orders/order-operations.js.map +1 -0
  454. package/dist/sdk/orders/use-order-actions.d.ts +23 -0
  455. package/dist/sdk/orders/use-order-actions.js +62 -0
  456. package/dist/sdk/orders/use-order-actions.js.map +1 -0
  457. package/dist/sdk/payment/gateway-origin.js +26 -13
  458. package/dist/sdk/payment/gateway-origin.js.map +1 -1
  459. package/dist/sdk/payment/gateway.d.ts +14 -2
  460. package/dist/sdk/payment/gateway.js +32 -14
  461. package/dist/sdk/payment/gateway.js.map +1 -1
  462. package/dist/sdk/payment/operations.js +11 -0
  463. package/dist/sdk/payment/operations.js.map +1 -1
  464. package/dist/sdk/payment/submission-registry.d.ts +2 -1
  465. package/dist/sdk/payment/submission-registry.js +12 -8
  466. package/dist/sdk/payment/submission-registry.js.map +1 -1
  467. package/dist/sdk/payment/use-payment-actions.d.ts +5 -3
  468. package/dist/sdk/payment/use-payment-actions.js +5 -2
  469. package/dist/sdk/payment/use-payment-actions.js.map +1 -1
  470. package/dist/sdk/payment/use-place-order.d.ts +6 -3
  471. package/dist/sdk/payment/use-place-order.js +333 -143
  472. package/dist/sdk/payment/use-place-order.js.map +1 -1
  473. package/dist/sdk/saved-cards/operations.d.ts +16 -0
  474. package/dist/sdk/saved-cards/operations.js +41 -0
  475. package/dist/sdk/saved-cards/operations.js.map +1 -0
  476. package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
  477. package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
  478. package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
  479. package/dist/sdk/seo/page-alternates.d.ts +57 -0
  480. package/dist/sdk/seo/page-alternates.js +127 -0
  481. package/dist/sdk/seo/page-alternates.js.map +1 -0
  482. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  483. package/dist/sdk/shipping/shipping-operations.js +13 -0
  484. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  485. package/dist/sdk/state/cart.d.ts +9 -2
  486. package/dist/sdk/state/cart.js +9 -2
  487. package/dist/sdk/state/cart.js.map +1 -1
  488. package/dist/utils/own-value.js +19 -0
  489. package/dist/utils/own-value.js.map +1 -0
  490. package/dist/utils/safe-href.d.ts +4 -4
  491. package/dist/utils/safe-href.js +31 -22
  492. package/dist/utils/safe-href.js.map +1 -1
  493. package/package.json +5 -1
  494. package/skills/storefront-asset/SKILL.md +111 -0
  495. package/skills/storefront-asset/references/api-side.md +153 -0
  496. package/skills/storefront-asset/references/findings.md +40 -0
  497. package/skills/storefront-asset/references/ui-side.md +94 -0
  498. package/src/styles/tailwind.css +28 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-saved-cards.js","names":[],"sources":["../../../src/matter/account-saved-cards/account-saved-cards.tsx"],"sourcesContent":["'use client';\n\nimport type { ErrorLike } from '@apollo/client';\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { type ContentValue, defineComponent, defineContentType } from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n cloneElement,\n createContext,\n isValidElement,\n type MouseEvent,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AlertDialogBackdrop,\n AlertDialogClose,\n AlertDialogDescription,\n AlertDialogPopup,\n AlertDialogPortal,\n AlertDialogRoot,\n AlertDialogTitle,\n AlertDialogTrigger,\n AlertDialogViewport,\n} from '../../particles/alert-dialog/alert-dialog.js';\nimport { CardSummary, CardSummaryRoot, useCardSummary } from '../../particles/card-summary/card-summary.js';\nimport { NavigationLink } from '../../particles/navigation-link/navigation-link.js';\nimport { ActionsOverrideContext, useActionsOverride } from '../../sdk/actions/actions-override-context.js';\nimport type { ComponentActions } from '../../sdk/actions/types.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { ListItemRefContext } from '../../sdk/data/list-item-ref-context.js';\nimport { ReactiveRootContext } from '../../sdk/data/page-reactive-data-root.js';\nimport { graphql } from '../../sdk/generated/gql.js';\nimport type { CustomerSavedCardStatus } from '../../sdk/generated/graphql.js';\nimport { useIntl } from '../../sdk/i18n/client.js';\nimport { useStorefrontRoute } from '../../sdk/navigation/use-storefront-route.js';\nimport { resolveAuthoredCopy } from '../../utils/resolve-authored-copy.js';\nimport { signInTarget } from '../../utils/safe-href.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * The signed-in shopper's saved cards in the account.\n * The Root reads card ids only; each AccountSavedCardItem subscribes to its own CustomerSavedCard\n * (ADR-0012) and provides `card-summary` and the row itself, so the schema arranges the CardSummary\n * parts and AccountSavedCardExpiry in the row.\n * Every text resolves children, then the CMS entry, then the `fs/saved-cards.*` catalog; the expiry\n * line, repeated per row, takes no children.\n * Removal state lives in the Root, because a successful removal unmounts the row it started from. The\n * Root also declares the `savedCard.remove` write, so a remove control rendered by a default, which the\n * compiler cannot wrap, still reaches the provider.\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL fragments\n// ---------------------------------------------------------------------------\n\nconst fragment = graphql(`\n fragment AccountSavedCardsData on Query {\n customerSavedCards {\n __typename\n id\n cards {\n __typename\n id\n }\n }\n }\n`);\n\nconst itemFragment = graphql(`\n fragment AccountSavedCardItemData on Query {\n customerSavedCards {\n cards {\n __typename\n id\n network {\n name\n }\n lastDigits\n expiry {\n month\n year\n }\n status\n }\n }\n }\n`);\n\n// ---------------------------------------------------------------------------\n// Content models — optional and default-free, so an unauthored field falls through to the catalog\n// ---------------------------------------------------------------------------\n\nexport const AccountSavedCardsHeadingContent = defineContentType({\n id: 'account-saved-cards-heading',\n title: 'Account Saved Cards Heading',\n description: \"Heading of the account's saved-cards section.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Heading' },\n },\n },\n});\n\nexport const AccountSavedCardsEmptyContent = defineContentType({\n id: 'account-saved-cards-empty',\n title: 'Account Saved Cards Empty',\n description: 'Statement shown when the shopper has no saved cards.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Empty statement' },\n },\n },\n});\n\nexport const AccountSavedCardsLoadingContent = defineContentType({\n id: 'account-saved-cards-loading',\n title: 'Account Saved Cards Loading',\n description: 'Announcement read to assistive technology while the saved cards load.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Loading announcement' },\n },\n },\n});\n\nexport const AccountSavedCardsErrorContent = defineContentType({\n id: 'account-saved-cards-error',\n title: 'Account Saved Cards Error',\n description: 'Messages shown when the saved cards cannot be read.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Load failure message' },\n sessionExpiredText: { type: 'string', minLength: 1, title: 'Session expired message' },\n signInLabel: { type: 'string', minLength: 1, title: 'Sign-in link label' },\n },\n },\n});\n\nexport const AccountSavedCardExpiryContent = defineContentType({\n id: 'account-saved-card-expiry',\n title: 'Account Saved Card Expiry',\n description: \"A saved card's expiry line. The date follows the label and is never authored.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n expiresLabel: { type: 'string', minLength: 1, title: \"Label before a working card's date\" },\n expiredLabel: { type: 'string', minLength: 1, title: \"Label before an expired card's date\" },\n expiredText: { type: 'string', minLength: 1, title: 'Expired card with no date' },\n unusableText: { type: 'string', minLength: 1, title: 'Unusable card' },\n },\n },\n});\n\nexport const AccountSavedCardRemoveTriggerContent = defineContentType({\n id: 'account-saved-card-remove-trigger',\n title: 'Account Saved Card Remove Trigger',\n description: \"Label of the control that opens a saved card's removal prompt.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Trigger label' },\n },\n },\n});\n\nexport const AccountSavedCardRemoveTitleContent = defineContentType({\n id: 'account-saved-card-remove-title',\n title: 'Account Saved Card Remove Title',\n description: 'Question that titles the removal prompt.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Prompt title' },\n },\n },\n});\n\nexport const AccountSavedCardRemoveDescriptionContent = defineContentType({\n id: 'account-saved-card-remove-description',\n title: 'Account Saved Card Remove Description',\n description: 'What removing the card means, shown after the card in the removal prompt.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Consequence' },\n },\n },\n});\n\nexport const AccountSavedCardRemoveCancelContent = defineContentType({\n id: 'account-saved-card-remove-cancel',\n title: 'Account Saved Card Remove Cancel',\n description: 'Label of the control that keeps the card.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Cancel label' },\n },\n },\n});\n\nexport const AccountSavedCardRemoveConfirmContent = defineContentType({\n id: 'account-saved-card-remove-confirm',\n title: 'Account Saved Card Remove Confirm',\n description: 'Label of the control that removes the card, and its label while the removal runs.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n text: { type: 'string', minLength: 1, title: 'Confirm label' },\n pendingText: { type: 'string', minLength: 1, title: 'Label while removing' },\n },\n },\n});\n\nexport const AccountSavedCardsRemoveFeedbackContent = defineContentType({\n id: 'account-saved-cards-remove-feedback',\n title: 'Account Saved Cards Remove Feedback',\n description: 'Messages that tell the shopper how a card removal ended.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n successText: { type: 'string', minLength: 1, title: 'Card removed' },\n failureText: { type: 'string', minLength: 1, title: 'Card not removed' },\n sessionExpiredText: { type: 'string', minLength: 1, title: 'Session expired message' },\n signInLabel: { type: 'string', minLength: 1, title: 'Sign-in link label' },\n },\n },\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The unwrapped `customerSavedCards` entity the reactive runtime delivers to the Root. */\nexport type AccountSavedCardsData = {\n id?: string | null;\n cards?: ReadonlyArray<{ id: string }> | null;\n} | null;\n\n/** One card's slice, delivered per row by the reactive-list-item runtime. */\nexport type AccountSavedCardItemData = {\n id: string;\n network: { name: string };\n lastDigits: string;\n expiry?: { month: number; year: number } | null;\n status: CustomerSavedCardStatus;\n} | null;\n\n/** The row a resolved AccountSavedCardItem provides to the parts inside it. */\nexport type AccountSavedCardContextValue = NonNullable<AccountSavedCardItemData>;\n\n/** `idle` is a null slice with no query in flight, such as a render with no reactive root. */\nexport type AccountSavedCardsState = 'idle' | 'loading' | 'error' | 'empty' | 'ready';\n\nexport type AccountSavedCardRemovalOutcome = Readonly<{ kind: 'removed' }> | Readonly<{ kind: 'failed'; code: string }>;\n\nexport type AccountSavedCardsRemoval = Readonly<{\n /** Card id of the removal in flight, or null. At most one per section. */\n pendingId: string | null;\n /** The last removal's outcome, or null before any and after begin(). */\n outcome: AccountSavedCardRemovalOutcome | null;\n /** Starts a removal. False, with no state change, while another is pending. */\n begin: (id: string) => boolean;\n /** Ends the pending removal with the action's userErrors (empty on success). */\n settle: (id: string, userErrors: readonly { code: string }[]) => void;\n}>;\n\nexport type AccountSavedCardsContextValue = Readonly<{\n state: AccountSavedCardsState;\n cards: ReadonlyArray<{ id: string }>;\n /** `extensions.code` of the read's error, or `null`. Set only in the `error` state. */\n errorCode: string | null;\n removal: AccountSavedCardsRemoval;\n}>;\n\nexport type AccountSavedCardsRootProps = ComponentPropsWithRef<'div'> & {\n $data?: AccountSavedCardsData;\n /** Injected by the compiler from `actions: { savedCard: ['remove'] }`, for every remove control inside. */\n $actions?: ComponentActions;\n};\n\nexport type AccountSavedCardsHeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n\nexport type AccountSavedCardsHeadingProps = ComponentPropsWithRef<'h2'> & {\n /** Heading level. `h1` is excluded: the page title belongs to the page shell. Defaults to `h2`. */\n as?: AccountSavedCardsHeadingLevel;\n $content?: ContentValue<typeof AccountSavedCardsHeadingContent>;\n};\n\nexport type AccountSavedCardsListProps = ComponentPropsWithRef<'ul'> & {\n /** The per-row template, typically one AccountSavedCardItem. */\n children?: ReactNode;\n};\n\nexport type AccountSavedCardItemProps = ComponentPropsWithRef<'li'> & {\n /** Per-row slice from the reactive-list-item runtime; passed directly in tests. */\n $data?: AccountSavedCardItemData;\n};\n\nexport type AccountSavedCardExpiryProps = Omit<ComponentPropsWithRef<'p'>, 'children'> & {\n $content?: ContentValue<typeof AccountSavedCardExpiryContent>;\n};\n\nexport type AccountSavedCardsEmptyProps = ComponentPropsWithRef<'p'> & {\n $content?: ContentValue<typeof AccountSavedCardsEmptyContent>;\n};\n\nexport type AccountSavedCardsLoadingProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n /** Placeholder rows shown while the cards load. Defaults to 2. */\n skeletonCount?: number;\n $content?: ContentValue<typeof AccountSavedCardsLoadingContent>;\n};\n\nexport type AccountSavedCardsErrorProps = ComponentPropsWithRef<'div'> & {\n /** Replaces the message for every error code and drops the sign-in link. */\n children?: ReactNode;\n $content?: ContentValue<typeof AccountSavedCardsErrorContent>;\n};\n\n/** The remove controller a row's prompt parts read. */\nexport type AccountSavedCardRemoveValue = Readonly<{\n id: string;\n /** This card's removal is pending. */\n pending: boolean;\n /** Any removal in the section is pending. */\n blocked: boolean;\n close: () => void;\n}>;\n\nexport type AccountSavedCardRemoveProps = {\n /** One AlertDialogRoot to control, or none for the default prompt. */\n children?: ReactNode;\n};\n\nexport type AccountSavedCardRemoveTriggerProps = ComponentPropsWithRef<'button'> & {\n $content?: ContentValue<typeof AccountSavedCardRemoveTriggerContent>;\n};\n\nexport type AccountSavedCardRemoveTitleProps = ComponentPropsWithRef<'h2'> & {\n $content?: ContentValue<typeof AccountSavedCardRemoveTitleContent>;\n};\n\nexport type AccountSavedCardRemoveDescriptionProps = ComponentPropsWithRef<'p'> & {\n $content?: ContentValue<typeof AccountSavedCardRemoveDescriptionContent>;\n};\n\nexport type AccountSavedCardRemoveCancelProps = ComponentPropsWithRef<'button'> & {\n $content?: ContentValue<typeof AccountSavedCardRemoveCancelContent>;\n};\n\nexport type AccountSavedCardRemoveConfirmProps = ComponentPropsWithRef<'button'> & {\n $content?: ContentValue<typeof AccountSavedCardRemoveConfirmContent>;\n};\n\nexport type AccountSavedCardsRemoveFeedbackProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n $content?: ContentValue<typeof AccountSavedCardsRemoveFeedbackContent>;\n};\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nconst AccountSavedCardsContext = createContext<AccountSavedCardsContextValue | null>(null);\n\n/** The section state the nearest AccountSavedCardsRoot publishes. Throws outside one. */\nexport function useAccountSavedCards(): AccountSavedCardsContextValue {\n const ctx = useContext(AccountSavedCardsContext);\n if (!ctx) throw new Error('AccountSavedCards parts must be used inside AccountSavedCardsRoot.');\n return ctx;\n}\n\nconst AccountSavedCardContext = createContext<AccountSavedCardContextValue | null>(null);\n\n/** The card the nearest AccountSavedCardItem provides. Throws outside one. */\nexport function useAccountSavedCard(): AccountSavedCardContextValue {\n const ctx = useContext(AccountSavedCardContext);\n if (!ctx) throw new Error('AccountSavedCard parts must be used inside AccountSavedCardItem.');\n return ctx;\n}\n\nconst AccountSavedCardRemoveContext = createContext<AccountSavedCardRemoveValue | null>(null);\n\n/** The remove controller the nearest AccountSavedCardRemove provides. Throws outside one. */\nexport function useAccountSavedCardRemove(): AccountSavedCardRemoveValue {\n const ctx = useContext(AccountSavedCardRemoveContext);\n if (!ctx) throw new Error('AccountSavedCardRemove parts must be used inside AccountSavedCardRemove.');\n return ctx;\n}\n\ntype SavedCardState = 'usable' | 'expired' | 'unusable';\n\n/** Only an explicit USABLE reads as usable, so a status this client does not know never looks usable. */\nfunction savedCardState(status: string): SavedCardState {\n if (status === 'USABLE') return 'usable';\n if (status === 'EXPIRED') return 'expired';\n return 'unusable';\n}\n\nfunction validExpiry(expiry: AccountSavedCardContextValue['expiry']): { month: number; year: number } | null {\n if (!expiry) return null;\n const { month, year } = expiry;\n if (!Number.isInteger(month) || month < 1 || month > 12) return null;\n if (!Number.isInteger(year) || year < 1000 || year > 9999) return null;\n return { month, year };\n}\n\nconst EMPTY_CARDS: ReadonlyArray<{ id: string }> = Object.freeze([]);\n\n/**\n * The read's own error code. The root error is page-wide, so an error whose path names another field\n * does not count; with no path at all, the first code stands.\n */\nfunction readErrorCode(error: ErrorLike): string | null {\n if (!CombinedGraphQLErrors.is(error)) return null;\n const own =\n error.errors.find((entry) => entry.path?.[0] === 'customerSavedCards') ??\n error.errors.find((entry) => entry.path == null);\n const code = own?.extensions?.code;\n return typeof code === 'string' ? code : null;\n}\n\n/**\n * One state for the whole section. A null slice plus an error is a failed read; an error beside a\n * resolved slice belongs to another field of the page query and changes nothing here.\n */\nfunction resolveSectionState(\n data: AccountSavedCardsData,\n loading: boolean,\n error: ErrorLike | undefined,\n): Omit<AccountSavedCardsContextValue, 'removal'> {\n if (data == null) {\n if (error) return { state: 'error', cards: EMPTY_CARDS, errorCode: readErrorCode(error) };\n return { state: loading ? 'loading' : 'idle', cards: EMPTY_CARDS, errorCode: null };\n }\n const cards = data.cards ?? EMPTY_CARDS;\n return { state: cards.length === 0 ? 'empty' : 'ready', cards, errorCode: null };\n}\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const AccountSavedCardsRootDefinition = defineComponent<AccountSavedCardsRootProps>({\n name: 'AccountSavedCardsRoot',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsRoot,\n fragment,\n fetchStrategy: 'reactive',\n requiresContext: 'session',\n providesContext: 'account-saved-cards',\n actions: { savedCard: ['remove'] },\n editor: { label: 'Account Saved Cards Root', category: 'identity' },\n schema: {},\n guideline:\n \"The signed-in shopper's saved cards, read with no cart. Renders nothing unless the session is loggedIn, and no chrome of its own: compose AccountSavedCardsHeading, AccountSavedCardsRemoveFeedback, AccountSavedCardsLoading, AccountSavedCardsError, AccountSavedCardsEmpty, and AccountSavedCardsList (with an AccountSavedCardItem inside) as children. Exactly one of Loading, Error, Empty, or List renders at a time; the state is on data-fs-account-saved-cards-state. It owns the removal state and supplies the savedCard.remove write to every AccountSavedCardRemove inside, placed or default, so the write sits here rather than on the control that dispatches it; with no remove control composed the write is never called. Must be inside a SessionRoot, normally the my-account layout's. See account-saved-cards.md.\",\n});\n\nexport const AccountSavedCardsHeadingDefinition = defineComponent<AccountSavedCardsHeadingProps>({\n name: 'AccountSavedCardsHeading',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsHeading,\n content: AccountSavedCardsHeadingContent,\n requiresContext: 'account-saved-cards',\n editor: { label: 'Account Saved Cards Heading', category: 'identity' },\n schema: {\n as: { type: ['h2', 'h3', 'h4', 'h5', 'h6'] as const, default: 'h2', label: 'Heading level' },\n },\n guideline:\n 'The section heading, rendered in every state. `as` sets the level from h2 to h6 (default h2); there is no h1, because the page title belongs to the page shell — pick the level that fits where the section is nested, or omit the heading. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.heading). Must be inside AccountSavedCardsRoot.',\n});\n\nexport const AccountSavedCardsListDefinition = defineComponent<AccountSavedCardsListProps>({\n name: 'AccountSavedCardsList',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsList,\n requiresContext: 'account-saved-cards',\n providesContext: 'account-saved-card',\n editor: { label: 'Account Saved Cards List', category: 'identity' },\n schema: {},\n guideline:\n 'The list of saved cards, one row per card in the platform order, rendered only when the shopper has at least one. Place one AccountSavedCardItem inside as the row template. Must be inside AccountSavedCardsRoot.',\n});\n\nexport const AccountSavedCardItemDefinition = defineComponent<AccountSavedCardItemProps>({\n name: 'AccountSavedCardItem',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardItem,\n fragment: itemFragment,\n fetchStrategy: 'reactive-list-item',\n requiresContext: 'account-saved-card',\n providesContext: ['card-summary', 'account-saved-card-data'],\n editor: { label: 'Account Saved Card Item', category: 'identity' },\n schema: {},\n guideline:\n 'One saved card as a list row. It provides the card to the CardSummary parts, AccountSavedCardExpiry, and AccountSavedCardRemove. With no children it renders CardSummary (mark, network name, mask, last four digits), AccountSavedCardExpiry, and AccountSavedCardRemove, whose text is then always the catalog wording; compose them as children to rearrange them or to reword them from the CMS, keep AccountSavedCardExpiry in any custom row, and leave AccountSavedCardRemove out only for a read-only list. An expired row carries data-fs-account-saved-card-expired, an unusable one data-fs-account-saved-card-unusable, and a row whose removal is pending data-fs-account-saved-card-removing, for a swatch to dim. Never shows more than the last four digits. Must be inside AccountSavedCardsList.',\n});\n\nexport const AccountSavedCardExpiryDefinition = defineComponent<AccountSavedCardExpiryProps>({\n name: 'AccountSavedCardExpiry',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardExpiry,\n content: AccountSavedCardExpiryContent,\n requiresContext: 'account-saved-card-data',\n editor: { label: 'Account Saved Card Expiry', category: 'identity' },\n schema: {},\n guideline:\n 'When a saved card expires: \"Expires 05/28\" for a working card, \"Expired 05/24\" (or \"Expired\" with no date) for an expired one, and \"This card can\\'t be used\", with no date, for an unusable one. Renders nothing for a working card with no date. The label comes from the CMS entry, then the catalog (fs/saved-cards.expires, .expired, .expired-no-date, .unusable); the component always places the MM/YY date after it, and only a placed element reads the CMS entry. The state is on data-fs-account-saved-card-expiry-status (usable, expired, unusable). Must be inside AccountSavedCardItem.',\n});\n\nexport const AccountSavedCardsEmptyDefinition = defineComponent<AccountSavedCardsEmptyProps>({\n name: 'AccountSavedCardsEmpty',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsEmpty,\n content: AccountSavedCardsEmptyContent,\n requiresContext: 'account-saved-cards',\n editor: { label: 'Account Saved Cards Empty', category: 'identity' },\n schema: {},\n guideline:\n 'States that the shopper has no saved cards. Renders only once the read resolved with none — never while loading or after a failure. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.empty). Must be inside AccountSavedCardsRoot.',\n});\n\nexport const AccountSavedCardsLoadingDefinition = defineComponent<AccountSavedCardsLoadingProps>({\n name: 'AccountSavedCardsLoading',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsLoading,\n content: AccountSavedCardsLoadingContent,\n requiresContext: 'account-saved-cards',\n editor: { label: 'Account Saved Cards Loading', category: 'identity' },\n schema: {\n skeletonCount: { type: 'number', default: 2, label: 'Placeholder rows' },\n },\n guideline:\n 'Placeholder rows while the saved cards load, plus one polite live region that announces the wait (CMS entry, then the catalog fs/saved-cards.loading). The rows are hidden from assistive technology; style them through data-fs-account-saved-cards-loading-row. Without this part the section shows no loading look. Must be inside AccountSavedCardsRoot.',\n});\n\nexport const AccountSavedCardsErrorDefinition = defineComponent<AccountSavedCardsErrorProps>({\n name: 'AccountSavedCardsError',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsError,\n content: AccountSavedCardsErrorContent,\n requiresContext: 'account-saved-cards',\n editor: { label: 'Account Saved Cards Error', category: 'identity' },\n schema: {},\n guideline:\n 'An alert shown when the saved cards cannot be read. An expired session says so and links to sign-in, returning the shopper to this page; any other failure says the cards could not be loaded. The wording comes from the CMS entry, then the catalog (fs/saved-cards.session-expired, .sign-in, .load-failed), never from the server; children replace it for every failure and drop the link. Must be inside AccountSavedCardsRoot.',\n});\n\nexport const AccountSavedCardRemoveDefinition = defineComponent<AccountSavedCardRemoveProps>({\n name: 'AccountSavedCardRemove',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemove,\n requiresContext: 'account-saved-card-data',\n providesContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove', category: 'identity' },\n schema: {},\n guideline:\n \"Lets the shopper remove the row's card after confirming. State-only controller: wrap one AlertDialogRoot and it becomes controlled, so never set open or onOpenChange on it. Compose AlertDialogRoot > (AccountSavedCardRemoveTrigger + AlertDialogPortal > (AlertDialogBackdrop + AlertDialogViewport > AlertDialogPopup > (AccountSavedCardRemoveTitle + AccountSavedCardRemoveDescription + AccountSavedCardRemoveCancel + AccountSavedCardRemoveConfirm))), Cancel before Confirm so the safe action takes focus. With no children it renders that prompt with catalog text; compose the parts to reword them from the CMS. The prompt stays open while the removal runs and closes when it fails; on success the row leaves the list. AccountSavedCardsRoot supplies the savedCard.remove write, and the outcome goes unreported unless the section composes AccountSavedCardsRemoveFeedback. Must be inside AccountSavedCardItem.\",\n});\n\nexport const AccountSavedCardRemoveTriggerDefinition = defineComponent<AccountSavedCardRemoveTriggerProps>({\n name: 'AccountSavedCardRemoveTrigger',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemoveTrigger,\n content: AccountSavedCardRemoveTriggerContent,\n requiresContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove Trigger', category: 'identity' },\n schema: {},\n guideline:\n 'Opens the removal prompt. Its accessible name is its text followed by the card, e.g. \"Remove Visa ending in 1234\"; the card part is visually hidden. Disabled while any removal in the section is pending. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.remove.trigger). Direct child of the AlertDialogRoot inside AccountSavedCardRemove.',\n});\n\nexport const AccountSavedCardRemoveTitleDefinition = defineComponent<AccountSavedCardRemoveTitleProps>({\n name: 'AccountSavedCardRemoveTitle',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemoveTitle,\n content: AccountSavedCardRemoveTitleContent,\n requiresContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove Title', category: 'identity' },\n schema: {},\n guideline:\n \"The removal prompt's question and its accessible name. Required inside AlertDialogPopup. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.remove.title). Must be inside AccountSavedCardRemove.\",\n});\n\nexport const AccountSavedCardRemoveDescriptionDefinition = defineComponent<AccountSavedCardRemoveDescriptionProps>({\n name: 'AccountSavedCardRemoveDescription',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemoveDescription,\n content: AccountSavedCardRemoveDescriptionContent,\n requiresContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove Description', category: 'identity' },\n schema: {},\n guideline:\n 'Names the card and states the consequence; screen readers announce it with the prompt. With no children it renders CardSummary and then the text, which resolves the CMS entry, then the catalog (fs/saved-cards.remove.description); children replace both, so keep a CardSummary in them for the prompt to name the card. Inside AlertDialogPopup, after AccountSavedCardRemoveTitle. Must be inside AccountSavedCardRemove.',\n});\n\nexport const AccountSavedCardRemoveCancelDefinition = defineComponent<AccountSavedCardRemoveCancelProps>({\n name: 'AccountSavedCardRemoveCancel',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemoveCancel,\n content: AccountSavedCardRemoveCancelContent,\n requiresContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove Cancel', category: 'identity' },\n schema: {},\n guideline:\n 'Closes the removal prompt and keeps the card. Disabled while the removal runs. Place it before AccountSavedCardRemoveConfirm so it takes focus when the prompt opens. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.remove.cancel). Must be inside AccountSavedCardRemove.',\n});\n\nexport const AccountSavedCardRemoveConfirmDefinition = defineComponent<AccountSavedCardRemoveConfirmProps>({\n name: 'AccountSavedCardRemoveConfirm',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardRemoveConfirm,\n content: AccountSavedCardRemoveConfirmContent,\n requiresContext: 'account-saved-card-remove',\n editor: { label: 'Account Saved Card Remove Confirm', category: 'identity' },\n schema: {},\n guideline:\n 'Removes the card. It dispatches savedCard.remove through the write AccountSavedCardsRoot supplies and declares none of its own. While the removal runs it is busy and shows its pending text; one removal runs at a time in the section. Text resolves children, then the CMS entry, then the catalog (fs/saved-cards.remove.confirm, .pending). Must be inside AccountSavedCardRemove.',\n});\n\nexport const AccountSavedCardsRemoveFeedbackDefinition = defineComponent<AccountSavedCardsRemoveFeedbackProps>({\n name: 'AccountSavedCardsRemoveFeedback',\n importPath: '@vtex/faststore/components',\n component: AccountSavedCardsRemoveFeedback,\n content: AccountSavedCardsRemoveFeedbackContent,\n requiresContext: 'account-saved-cards',\n editor: { label: 'Account Saved Cards Remove Feedback', category: 'identity' },\n schema: {},\n guideline:\n \"Tells the shopper how a card removal ended: a status message that takes focus when the card was removed, or an alert when it was not, with a sign-in link back to this page when the session expired. Renders in every state of the section, so the message outlives the removed row and an emptied list; it stays until the next removal starts. Without this part a removal's outcome goes unreported. The wording comes from the CMS entry, then the catalog (fs/saved-cards.remove.success, .failed, fs/saved-cards.session-expired, .sign-in), never from the server; the outcome is on data-fs-account-saved-cards-remove-feedback-outcome. Must be inside AccountSavedCardsRoot.\",\n});\n\n// ---------------------------------------------------------------------------\n// Implementations\n// ---------------------------------------------------------------------------\n\n/**\n * One removal at a time: each success replaces the whole cached list, so two in flight could land out\n * of order and restore a card the later one removed.\n */\nfunction useRemovalState(): AccountSavedCardsRemoval {\n const [pendingId, setPendingId] = useState<string | null>(null);\n const [outcome, setOutcome] = useState<AccountSavedCardRemovalOutcome | null>(null);\n // Read synchronously, so a second activation in the same tick already sees the first.\n const pendingRef = useRef<string | null>(null);\n\n const begin = useCallback((id: string) => {\n if (pendingRef.current !== null) return false;\n pendingRef.current = id;\n setPendingId(id);\n setOutcome(null);\n return true;\n }, []);\n\n const settle = useCallback((id: string, userErrors: readonly { code: string }[]) => {\n if (pendingRef.current !== id) return;\n pendingRef.current = null;\n setPendingId(null);\n const [first] = userErrors;\n setOutcome(first ? { kind: 'failed', code: first.code } : { kind: 'removed' });\n }, []);\n\n return useMemo(() => ({ pendingId, outcome, begin, settle }), [pendingId, outcome, begin, settle]);\n}\n\nexport function AccountSavedCardsRoot({\n $data: $dataProp,\n $actions: $actionsProp,\n className,\n children,\n ...props\n}: AccountSavedCardsRootProps) {\n // Enforces the SessionRoot ancestor: useSession() throws outside one.\n const { state: sessionState } = useSession();\n const data = useDataOverride<AccountSavedCardsData | undefined>($dataProp) ?? null;\n const $actions = useActionsOverride($actionsProp);\n const { loading, error } = useContext(ReactiveRootContext);\n const section = useMemo(() => resolveSectionState(data, loading, error), [data, loading, error]);\n const removal = useRemovalState();\n const value = useMemo(() => ({ ...section, removal }), [section, removal]);\n\n if (sessionState !== 'loggedIn') return null;\n\n return (\n <AccountSavedCardsContext value={value}>\n <ActionsOverrideContext value={$actions}>\n <div\n {...props}\n className={className}\n data-fs-account-saved-cards=\"\"\n data-fs-account-saved-cards-state={value.state}\n >\n {children}\n </div>\n </ActionsOverrideContext>\n </AccountSavedCardsContext>\n );\n}\n\nexport function AccountSavedCardsHeading({\n as: Tag = 'h2',\n $content,\n className,\n children,\n ...props\n}: AccountSavedCardsHeadingProps) {\n useAccountSavedCards();\n const intl = useIntl();\n return (\n <Tag {...props} className={className} data-fs-account-saved-cards-heading=\"\">\n {children ?? resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.heading' }))}\n </Tag>\n );\n}\n\nexport function AccountSavedCardsList({ className, children, ...props }: AccountSavedCardsListProps) {\n const { state, cards } = useAccountSavedCards();\n if (state !== 'ready') return null;\n\n return (\n <ul {...props} className={className} data-fs-account-saved-cards-list=\"\">\n {cards.map((card) => (\n // No fallback slice: the Root selects ids only, so an incomplete row renders nothing until\n // its cache entry resolves rather than a partial card.\n <ListItemRefContext\n key={card.id}\n value={{ __typename: 'CustomerSavedCard', id: card.id, fallbackData: undefined }}\n >\n {children}\n </ListItemRefContext>\n ))}\n </ul>\n );\n}\n\nexport function AccountSavedCardItem({ $data: $dataProp, className, children, ...props }: AccountSavedCardItemProps) {\n const card = useDataOverride<AccountSavedCardItemData | undefined>($dataProp) ?? null;\n // Not useAccountSavedCards(): an Item composed without a remove control stays usable outside a Root.\n const pendingId = useContext(AccountSavedCardsContext)?.removal.pendingId ?? null;\n if (!card) return null;\n const state = savedCardState(card.status);\n\n return (\n <AccountSavedCardContext value={card}>\n <li\n {...props}\n className={className}\n data-fs-account-saved-card=\"\"\n {...(state === 'expired' ? { 'data-fs-account-saved-card-expired': '' } : {})}\n {...(state === 'unusable' ? { 'data-fs-account-saved-card-unusable': '' } : {})}\n {...(pendingId === card.id ? { 'data-fs-account-saved-card-removing': '' } : {})}\n >\n <CardSummaryRoot network={card.network.name} lastDigits={card.lastDigits}>\n {children ?? (\n <>\n <CardSummary />\n <AccountSavedCardExpiry />\n <AccountSavedCardRemove />\n </>\n )}\n </CardSummaryRoot>\n </li>\n </AccountSavedCardContext>\n );\n}\n\nexport function AccountSavedCardExpiry({ $content, className, ...props }: AccountSavedCardExpiryProps) {\n const { status, expiry } = useAccountSavedCard();\n const intl = useIntl();\n const state = savedCardState(status);\n const date = state === 'unusable' ? null : validExpiry(expiry);\n if (state === 'usable' && !date) return null;\n\n let label: string;\n if (state === 'unusable') {\n label = resolveAuthoredCopy($content?.unusableText, intl.formatMessage({ id: 'fs/saved-cards.unusable' }));\n } else if (!date) {\n label = resolveAuthoredCopy($content?.expiredText, intl.formatMessage({ id: 'fs/saved-cards.expired-no-date' }));\n } else if (state === 'expired') {\n label = resolveAuthoredCopy($content?.expiredLabel, intl.formatMessage({ id: 'fs/saved-cards.expired' }));\n } else {\n label = resolveAuthoredCopy($content?.expiresLabel, intl.formatMessage({ id: 'fs/saved-cards.expires' }));\n }\n const month = date ? String(date.month).padStart(2, '0') : '';\n\n return (\n <p\n {...props}\n className={className}\n data-fs-account-saved-card-expiry=\"\"\n data-fs-account-saved-card-expiry-status={state}\n >\n <span data-fs-account-saved-card-expiry-label=\"\">{label}</span>\n {date ? (\n <>\n {' '}\n <time data-fs-account-saved-card-expiry-date=\"\" dateTime={`${date.year}-${month}`} aria-hidden=\"true\">\n {`${month}/${String(date.year % 100).padStart(2, '0')}`}\n </time>{' '}\n <span data-fs-sr-only=\"\" className=\"sr-only\">\n {/* UTC on the first of the month, so no time zone moves the date into another month. */}\n {intl.formatDate(Date.UTC(date.year, date.month - 1, 1), {\n month: 'long',\n year: 'numeric',\n timeZone: 'UTC',\n })}\n </span>\n </>\n ) : null}\n </p>\n );\n}\n\nexport function AccountSavedCardsEmpty({ $content, className, children, ...props }: AccountSavedCardsEmptyProps) {\n const { state } = useAccountSavedCards();\n const intl = useIntl();\n if (state !== 'empty') return null;\n\n return (\n <p {...props} className={className} data-fs-account-saved-cards-empty=\"\">\n {children ?? resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.empty' }))}\n </p>\n );\n}\n\nconst DEFAULT_SKELETON_COUNT = 2;\n\nexport function AccountSavedCardsLoading({\n skeletonCount = DEFAULT_SKELETON_COUNT,\n $content,\n className,\n ...props\n}: AccountSavedCardsLoadingProps) {\n const { state } = useAccountSavedCards();\n const intl = useIntl();\n const loading = state === 'loading';\n const label = resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.loading' }));\n const rows = Number.isFinite(skeletonCount) ? Math.max(1, Math.trunc(skeletonCount)) : DEFAULT_SKELETON_COUNT;\n\n // A live region only announces text written after it mounted, so it stays in the tree and is\n // filled on the pass after loading starts (AccountEntryPoint's pattern).\n const [announcement, setAnnouncement] = useState('');\n const pendingLabel = loading ? label : '';\n useEffect(() => {\n setAnnouncement(pendingLabel);\n }, [pendingLabel]);\n\n return (\n <>\n {loading ? (\n <div {...props} className={className} aria-hidden=\"true\" data-fs-account-saved-cards-loading=\"\">\n {Array.from({ length: rows }, (_, index) => (\n <span key={index} data-fs-account-saved-cards-loading-row=\"\" />\n ))}\n </div>\n ) : null}\n <output aria-live=\"polite\" data-fs-account-saved-cards-loading-announcement=\"\">\n {announcement}\n </output>\n </>\n );\n}\n\nexport function AccountSavedCardsError({ $content, className, children, ...props }: AccountSavedCardsErrorProps) {\n const { state, errorCode } = useAccountSavedCards();\n const intl = useIntl();\n const { path } = useStorefrontRoute();\n if (state !== 'error') return null;\n\n // Keyed on the code as a whole: confronted identity gives every refusal one UNAUTHORIZED, and the\n // server's message is never rendered.\n const sessionExpired = errorCode === 'UNAUTHORIZED';\n\n return (\n <div\n {...props}\n role=\"alert\"\n className={className}\n data-fs-account-saved-cards-error=\"\"\n data-fs-account-saved-cards-error-code={sessionExpired ? 'unauthorized' : 'failed'}\n >\n {children ??\n (sessionExpired ? (\n <>\n {resolveAuthoredCopy(\n $content?.sessionExpiredText,\n intl.formatMessage({ id: 'fs/saved-cards.session-expired' }),\n )}{' '}\n <NavigationLink href={signInTarget(path)} prefetch={false} data-fs-account-saved-cards-sign-in=\"\">\n {resolveAuthoredCopy($content?.signInLabel, intl.formatMessage({ id: 'fs/saved-cards.sign-in' }))}\n </NavigationLink>\n </>\n ) : (\n resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.load-failed' }))\n ))}\n </div>\n );\n}\n\ntype OverlayOpenProps = {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n};\n\nexport function AccountSavedCardRemove({ children }: Readonly<AccountSavedCardRemoveProps>) {\n const { id } = useAccountSavedCard();\n const { removal } = useAccountSavedCards();\n const [open, setOpen] = useState(false);\n const pending = removal.pendingId === id;\n const blocked = removal.pendingId !== null;\n const close = useCallback(() => setOpen(false), []);\n const value = useMemo(() => ({ id, pending, blocked, close }), [id, pending, blocked, close]);\n const prompt = children ?? <AccountSavedCardRemoveDefaultPrompt />;\n\n if (!isValidElement<OverlayOpenProps>(prompt)) {\n return <AccountSavedCardRemoveContext value={value}>{prompt}</AccountSavedCardRemoveContext>;\n }\n\n return (\n <AccountSavedCardRemoveContext value={value}>\n {cloneElement(prompt, {\n open,\n onOpenChange: (next: boolean) => {\n // Escape and Cancel cannot leave a removal in flight, and no prompt opens while one runs.\n if (next ? blocked : pending) return;\n setOpen(next);\n },\n })}\n </AccountSavedCardRemoveContext>\n );\n}\n\nfunction AccountSavedCardRemoveDefaultPrompt({ open, onOpenChange }: Readonly<OverlayOpenProps>) {\n return (\n <AlertDialogRoot open={open} onOpenChange={onOpenChange}>\n <AccountSavedCardRemoveTrigger />\n <AlertDialogPortal>\n <AlertDialogBackdrop />\n <AlertDialogViewport>\n <AlertDialogPopup>\n <AccountSavedCardRemoveTitle />\n <AccountSavedCardRemoveDescription />\n <AccountSavedCardRemoveCancel />\n <AccountSavedCardRemoveConfirm />\n </AlertDialogPopup>\n </AlertDialogViewport>\n </AlertDialogPortal>\n </AlertDialogRoot>\n );\n}\n\nexport function AccountSavedCardRemoveTrigger({\n $content,\n className,\n children,\n disabled,\n ...props\n}: AccountSavedCardRemoveTriggerProps) {\n const { blocked } = useAccountSavedCardRemove();\n const { name, lastFour } = useCardSummary();\n const intl = useIntl();\n const card = [name, lastFour ? intl.formatMessage({ id: 'fs/card.ending-in' }, { lastDigits: lastFour }) : null]\n .filter(Boolean)\n .join(' ');\n\n return (\n <AlertDialogTrigger\n {...props}\n className={className}\n disabled={blocked || disabled}\n data-fs-account-saved-card-remove-trigger=\"\"\n >\n {children ?? resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.remove.trigger' }))}\n {card ? (\n <>\n {' '}\n <span data-fs-sr-only=\"\" className=\"sr-only\">\n {card}\n </span>\n </>\n ) : null}\n </AlertDialogTrigger>\n );\n}\n\nexport function AccountSavedCardRemoveTitle({\n $content,\n className,\n children,\n ...props\n}: AccountSavedCardRemoveTitleProps) {\n useAccountSavedCardRemove();\n const intl = useIntl();\n return (\n <AlertDialogTitle {...props} className={className} data-fs-account-saved-card-remove-title=\"\">\n {children ?? resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.remove.title' }))}\n </AlertDialogTitle>\n );\n}\n\nexport function AccountSavedCardRemoveDescription({\n $content,\n className,\n children,\n ...props\n}: AccountSavedCardRemoveDescriptionProps) {\n useAccountSavedCardRemove();\n const intl = useIntl();\n return (\n <AlertDialogDescription {...props} className={className} data-fs-account-saved-card-remove-description=\"\">\n {children ?? (\n <>\n <CardSummary />{' '}\n {resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.remove.description' }))}\n </>\n )}\n </AlertDialogDescription>\n );\n}\n\nexport function AccountSavedCardRemoveCancel({\n $content,\n className,\n children,\n disabled,\n ...props\n}: AccountSavedCardRemoveCancelProps) {\n const { pending } = useAccountSavedCardRemove();\n const intl = useIntl();\n return (\n <AlertDialogClose\n {...props}\n className={className}\n disabled={pending || disabled}\n data-fs-account-saved-card-remove-cancel=\"\"\n >\n {children ?? resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.remove.cancel' }))}\n </AlertDialogClose>\n );\n}\n\nexport function AccountSavedCardRemoveConfirm({\n $content,\n className,\n children,\n onClick,\n ...props\n}: AccountSavedCardRemoveConfirmProps) {\n const { id, pending, close } = useAccountSavedCardRemove();\n const { removal } = useAccountSavedCards();\n const remove = useActionsOverride(undefined)?.savedCard?.remove;\n const intl = useIntl();\n\n async function handleClick(event: MouseEvent<HTMLButtonElement>) {\n onClick?.(event);\n if (event.defaultPrevented || !remove || !removal.begin(id)) return;\n let userErrors: readonly { code: string }[];\n try {\n userErrors = await remove({ id });\n } catch {\n // An injected action may reject; a removal left pending would lock the prompt open.\n userErrors = [{ code: 'NETWORK_ERROR' }];\n }\n // On success the row, and this prompt with it, has already left the list; the Root is still there.\n removal.settle(id, userErrors);\n close();\n }\n\n return (\n <button\n {...props}\n type=\"button\"\n className={className}\n // aria-disabled rather than disabled, so focus stays on the control while it reports progress.\n aria-disabled={pending || undefined}\n aria-busy={pending || undefined}\n data-fs-account-saved-card-remove-confirm=\"\"\n {...(pending ? { 'data-fs-account-saved-card-remove-confirm-pending': '' } : {})}\n onClick={handleClick}\n >\n {pending\n ? resolveAuthoredCopy($content?.pendingText, intl.formatMessage({ id: 'fs/saved-cards.remove.pending' }))\n : (children ??\n resolveAuthoredCopy($content?.text, intl.formatMessage({ id: 'fs/saved-cards.remove.confirm' })))}\n </button>\n );\n}\n\nfunction feedbackOutcome(outcome: AccountSavedCardRemovalOutcome | null) {\n if (!outcome) return undefined;\n if (outcome.kind === 'removed') return 'removed';\n return outcome.code === 'UNAUTHORIZED' ? 'unauthorized' : 'failed';\n}\n\nexport function AccountSavedCardsRemoveFeedback({\n $content,\n className,\n ...props\n}: AccountSavedCardsRemoveFeedbackProps) {\n const {\n removal: { outcome },\n } = useAccountSavedCards();\n const intl = useIntl();\n const { path } = useStorefrontRoute();\n const statusRef = useRef<HTMLOutputElement>(null);\n const kind = feedbackOutcome(outcome);\n const successText = resolveAuthoredCopy(\n $content?.successText,\n intl.formatMessage({ id: 'fs/saved-cards.remove.success' }),\n );\n\n // A live region only announces text written after it mounted, so it stays in the tree and is filled\n // on the pass after the outcome. Focus moves to it because the trigger it would return to left with\n // the removed row.\n const [announcement, setAnnouncement] = useState('');\n useEffect(() => {\n const removed = outcome?.kind === 'removed';\n setAnnouncement(removed ? successText : '');\n if (removed) statusRef.current?.focus();\n }, [outcome, successText]);\n\n return (\n <div\n {...props}\n className={className}\n data-fs-account-saved-cards-remove-feedback=\"\"\n data-fs-account-saved-cards-remove-feedback-outcome={kind}\n >\n <output ref={statusRef} aria-live=\"polite\" tabIndex={-1}>\n {announcement}\n </output>\n {kind === 'unauthorized' ? (\n <div role=\"alert\">\n {resolveAuthoredCopy(\n $content?.sessionExpiredText,\n intl.formatMessage({ id: 'fs/saved-cards.session-expired' }),\n )}{' '}\n <NavigationLink\n href={signInTarget(path)}\n prefetch={false}\n data-fs-account-saved-cards-remove-feedback-sign-in=\"\"\n >\n {resolveAuthoredCopy($content?.signInLabel, intl.formatMessage({ id: 'fs/saved-cards.sign-in' }))}\n </NavigationLink>\n </div>\n ) : null}\n {kind === 'failed' ? (\n <div role=\"alert\">\n {resolveAuthoredCopy($content?.failureText, intl.formatMessage({ id: 'fs/saved-cards.remove.failed' }))}\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { ComponentDefinition } from "../../core/dist/define-component.js";
2
2
  import "../../core/dist/index.js";
3
3
  import { ComponentActions } from "../../sdk/actions/types.js";
4
+ import "../shipping-address/country-descriptors.js";
4
5
  import { ComponentPropsWithRef } from "react";
5
6
  //#region src/matter/billing-address/billing-address.d.ts
6
7
  /**
@@ -12,8 +13,8 @@ import { ComponentPropsWithRef } from "react";
12
13
  * The shared `Address` composition RFC D6 names (shipping and billing as two control matters over
13
14
  * one set of reusable particles) is DEFERRED — an implementation-time call the engineer resolved
14
15
  * narrow (specs/billing-address.md Decision 1). This component builds its own controls and imports
15
- * `countryDescriptors` from `../shipping-address/country-descriptors.js`; `matter/shipping-address/`
16
- * is read, never modified — zero bytes of that directory change here.
16
+ * `countryDescriptors` from `../shipping-address/country-descriptors.js`, the one place a country's field
17
+ * set, labels, copy and format rules live.
17
18
  *
18
19
  * There is NO read-back path for a persisted billing address (specs/billing-address.md Decision 3):
19
20
  * `type Payment` carries no `billingAddress` field, and `setBillingAddress` itself resolves only
@@ -46,18 +47,20 @@ import { ComponentPropsWithRef } from "react";
46
47
  * `<form>` in this render tree and the submit control is `type="button"`, so the browser's own
47
48
  * constraint validation never runs — nothing in this file or its tests may claim this attribute itself
48
49
  * prevents a shopper from placing an order with an unsaved address; the actual submit gate is
49
- * `isBillingAddressFormValid`, read at the submit control's own `disabled` below. Since T38
50
+ * `isBillingAddressFormValid`'s verdict (`areRenderableFieldsValid`), read at the submit control's own
51
+ * `disabled` below. Since T38
50
52
  * (specs/harden-and-verify-accessibility-across-the.md FR-6) each rendered field does carry a
51
- * `Field.Error`, but it is driven by a local blur-tracked `touched` set and this same non-blank rule,
52
- * never by `required`'s own native `ValidityState` — so this paragraph's point is unchanged: `required`
53
- * itself still enforces nothing here. What this component owes, and
54
- * does: make the gap **visible** — an inline `role="status"` notice while the form is open and nothing
55
- * has been persisted yet — and publish that same fact (`setDraftBillingAddressUnsaved`) onto the
56
- * shared draft, from the identical expression the notice renders from (T24,
57
- * specs/cardholder-document-submit-gate.md FR-6). **The actual hard block lives elsewhere**: T24's
58
- * `usePaymentSubmitGate()` reads that published fact and refuses Place Order client-side — this
59
- * component's own job stops at publishing the fact and showing the notice, never at gating the CTA
60
- * itself. See `specs/billing-address.md`'s Documentation Gaps #1 for the deferral this closes.
53
+ * `Field.Error`, but it is driven by a local `touched` set (a field joins it on blur, or when a refused
54
+ * submit moves focus to it) and `getFieldIssue`'s verdict (`required` for a blank field, `format` for a
55
+ * non-blank value that fails the country's postal pattern), never by `required`'s own native
56
+ * `ValidityState` — so this paragraph's point is unchanged: `required` itself still enforces nothing
57
+ * here. What this component owes, and does: make the gap **visible** — an inline `role="status"`
58
+ * notice while the form is open and nothing has been persisted yet — and publish that same fact
59
+ * (`setDraftBillingAddressUnsaved`) onto the shared draft, from the identical expression the notice
60
+ * renders from (T24, specs/cardholder-document-submit-gate.md FR-6). **The actual hard block lives
61
+ * elsewhere**: T24's `usePaymentSubmitGate()` reads that published fact and refuses Place Order
62
+ * client-side — this component's own job stops at publishing the fact and showing the notice, never at
63
+ * gating the CTA itself. See `specs/billing-address.md`'s Documentation Gaps #1 for the deferral this closes.
61
64
  */
62
65
  /**
63
66
  * Local-only values for the "different" address form, keyed by the country descriptor's own
@@ -134,6 +137,15 @@ export type BillingAddressProps = Omit<ComponentPropsWithRef<'div'>, 'children'>
134
137
  * Resolved through `resolveAuthoredCopy`.
135
138
  */
136
139
  fieldRequiredMessage?: string;
140
+ /**
141
+ * Shown as a `Field.Error` under a touched, non-blank postal code that does not match the selected
142
+ * country's format (the descriptor's `rule.pattern`). Only the postal code reads this prop: any other
143
+ * field that gains a pattern speaks with its own descriptor message. Blank wins over format: a blank
144
+ * field reads `fieldRequiredMessage`, never this. Never contains the typed value. Resolved through
145
+ * `resolveAuthoredCopy`, so a blank value falls back to the English default like every other copy on
146
+ * this form.
147
+ */
148
+ postalCodeInvalidMessage?: string;
137
149
  /** Disables the toggle, every form field, the country selector, and the submit control. */
138
150
  disabled?: boolean;
139
151
  /** Compiler-injected action surface; carries `payment.setBillingAddress`. */
@@ -151,15 +163,16 @@ export declare function resolveSameAsDelivery(billingAddressDifferent: boolean |
151
163
  * `MISSING_BILLING_ADDRESS_FIELDS` floor ("sameAsDelivery is false but postalCode **or country** was
152
164
  * omitted" [source: `core.graphql:2857-2858`]) — every field the active country's descriptor renders,
153
165
  * except `complement` (`OPTIONAL_FORM_FIELD_NAMES`), must be non-blank (PR #544 N1 item 1: the
154
- * engineer's own rule that the new-address fields are required once "different" is selected). Resolves
155
- * the descriptor from `formDraft.country` itself rather than taking a second parameter, so this stays a
156
- * single self-contained fact about one `BillingAddressFormDraft` value. `country` itself is not part of
166
+ * engineer's own rule that the new-address fields are required once "different" is selected), and every
167
+ * non-blank value must match its descriptor's `rule.pattern`. Resolves the descriptor from
168
+ * `formDraft.country` itself rather than taking a second parameter, so this stays a single
169
+ * self-contained fact about one `BillingAddressFormDraft` value. `country` itself is not part of
157
170
  * `descriptor.fields` (Decision 7) and is never checked here — it always carries a non-blank value from
158
171
  * `defaultCountry` or the selector's own current value (review F12), so it can never be the field this
159
172
  * gate would fail on.
160
173
  */
161
174
  export declare function isBillingAddressFormValid(formDraft: BillingAddressFormDraft): boolean;
162
175
  export declare const BillingAddressDefinition: ComponentDefinition<BillingAddressProps>;
163
- export declare function BillingAddress({ sameAsDeliveryLabel, defaultCountry, countryLabel, submitLabel, submitPendingLabel, requiredNoticeLabel, unsavedAddressNoticeLabel, billingMatchNoticeLabel, billingMatchNoticeVisible, recipientNameLabel, streetLabel, numberLabel, complementLabel, neighborhoodLabel, cityLabel, stateLabel, postalCodeLabel, fieldRequiredMessage, disabled, className, $actions: $actionsProp, ...props }: BillingAddressProps): import("react/jsx-runtime").JSX.Element | null;
176
+ export declare function BillingAddress({ sameAsDeliveryLabel, defaultCountry, countryLabel, submitLabel, submitPendingLabel, requiredNoticeLabel, unsavedAddressNoticeLabel, billingMatchNoticeLabel, billingMatchNoticeVisible, recipientNameLabel, streetLabel, numberLabel, complementLabel, neighborhoodLabel, cityLabel, stateLabel, postalCodeLabel, fieldRequiredMessage, postalCodeInvalidMessage, disabled, className, $actions: $actionsProp, ...props }: BillingAddressProps): import("react/jsx-runtime").JSX.Element | null;
164
177
  //#endregion
165
178
  //# sourceMappingURL=billing-address.d.ts.map
@@ -5,11 +5,11 @@ import { Checkbox } from "../../particles/checkbox/checkbox.js";
5
5
  import { Field } from "../../particles/field/field.js";
6
6
  import { useActionsOverride } from "../../sdk/actions/actions-override-context.js";
7
7
  import { resolveAuthoredCopy } from "../../utils/resolve-authored-copy.js";
8
- import { Icon } from "../../particles/icon/icon.js";
9
8
  import { Select } from "../../particles/select/select.js";
9
+ import { Icon } from "../../particles/icon/icon.js";
10
10
  import { usePayment } from "../payment/payment.js";
11
- import { getAvailableCountries, getCountryDescriptor } from "../shipping-address/country-descriptors.js";
12
- import { useEffect, useId, useState } from "react";
11
+ import { getAvailableCountries, getCountryDescriptor, satisfiesFieldPattern } from "../shipping-address/country-descriptors.js";
12
+ import { useEffect, useId, useMemo, useState } from "react";
13
13
  import { jsx, jsxs } from "react/jsx-runtime";
14
14
  //#region src/matter/billing-address/billing-address.tsx
15
15
  /** Canonical field names the custom-address form never renders, even when a country descriptor
@@ -25,14 +25,13 @@ const OMITTED_FORM_FIELD_NAMES = /* @__PURE__ */ new Set(["recipientName"]);
25
25
  * without changing this set — the two are independent (R7, billing-address.md). */
26
26
  const OPTIONAL_FORM_FIELD_NAMES = /* @__PURE__ */ new Set(["complement"]);
27
27
  /**
28
- * English override for the descriptor's own country display names (`'Brasil'`, `'Estados Unidos'`) —
29
- * `country-descriptors.ts` is shared with `shipping-address` and out of this task's write scope
30
- * (`matter/shipping-address/` is read-only here), and its labels are Portuguese regardless of country.
31
- * T31 (specs/make-the-payment-components-authored-copy.md, Decision 5) turned the eight *field* labels
32
- * this same reasoning used to justify (`FIELD_LABELS_EN`) into schema props instead, but deliberately
33
- * left this one a plain map: a prop per ISO code does not scale the way eight named field-label props
34
- * do, and the epic block's own wording covers field labels only. Keyed by the descriptor's own ISO
35
- * code.
28
+ * English override for the descriptor's own country display names (`'Brasil'`, `'United States'`), because
29
+ * the Brazilian entry's name is Portuguese. This map is a stopgap: copy a country's form speaks belongs on
30
+ * its descriptor in `country-descriptors.ts`, as `countryLabel` and `requiredSuffix` already do. Put a new
31
+ * string there, not in another English override map here. T31
32
+ * (specs/make-the-payment-components-authored-copy.md, Decision 5) turned the eight *field* labels into
33
+ * schema props but left this one a plain map: a prop per ISO code does not scale the way eight named
34
+ * field-label props do. Keyed by the descriptor's own ISO code.
36
35
  */
37
36
  const COUNTRY_LABELS_EN = {
38
37
  BRA: "Brazil",
@@ -53,21 +52,106 @@ function resolveSameAsDelivery(billingAddressDifferent) {
53
52
  return billingAddressDifferent !== true;
54
53
  }
55
54
  /**
55
+ * The one verdict on a rendered field, read by both the submit gate (`areRenderableFieldsValid`, behind
56
+ * `isBillingAddressFormValid`) and the per-field error (the `issue` computed per field in the render), so the
57
+ * two can never disagree (T38 Decision 8). Blank (after
58
+ * trim) wins over format: `complement` (`OPTIONAL_FORM_FIELD_NAMES`) may be blank, every other field may
59
+ * not. A non-blank value is tested raw against the descriptor's `rule.pattern` — the same
60
+ * predicate the delivery form's react-hook-form rule applies, so a surrounding space is a format error
61
+ * in both. A whitespace-only value is the one divergence: it is blank here (`required`), where the
62
+ * delivery form would run the pattern on it (see `satisfiesFieldPattern`). No postal format is defined
63
+ * here: the descriptor's `rule.pattern` is the only definition.
64
+ */
65
+ function getFieldIssue(field, value) {
66
+ if (value.trim().length === 0) return OPTIONAL_FORM_FIELD_NAMES.has(field.name) ? null : "required";
67
+ return satisfiesFieldPattern(field, value) ? null : "format";
68
+ }
69
+ /**
70
+ * The message under a field whose verdict is `format`. `postalCode` keeps the authored
71
+ * `postalCodeInvalidMessage` (already resolved by the caller, so it always has an English default); every
72
+ * other field speaks with its own descriptor `rule.pattern.message`, the one the delivery form shows for the
73
+ * same rule, so a pattern a descriptor gains later never surfaces the postal-code copy. A field with no
74
+ * pattern never reaches a `format` verdict, so the empty string is not a message anyone sees.
75
+ */
76
+ function getFieldFormatMessage(field, postalCodeMessage) {
77
+ if (field.name === "postalCode") return postalCodeMessage;
78
+ return field.rule?.pattern?.message ?? "";
79
+ }
80
+ /** The descriptor's fields the custom-address form renders: everything but `OMITTED_FORM_FIELD_NAMES`. */
81
+ function getRenderableFields(descriptor) {
82
+ return descriptor.fields.filter((field) => !OMITTED_FORM_FIELD_NAMES.has(field.name));
83
+ }
84
+ /**
56
85
  * Whether the custom-address form may be submitted. Stricter than the server's own
57
86
  * `MISSING_BILLING_ADDRESS_FIELDS` floor ("sameAsDelivery is false but postalCode **or country** was
58
87
  * omitted" [source: `core.graphql:2857-2858`]) — every field the active country's descriptor renders,
59
88
  * except `complement` (`OPTIONAL_FORM_FIELD_NAMES`), must be non-blank (PR #544 N1 item 1: the
60
- * engineer's own rule that the new-address fields are required once "different" is selected). Resolves
61
- * the descriptor from `formDraft.country` itself rather than taking a second parameter, so this stays a
62
- * single self-contained fact about one `BillingAddressFormDraft` value. `country` itself is not part of
89
+ * engineer's own rule that the new-address fields are required once "different" is selected), and every
90
+ * non-blank value must match its descriptor's `rule.pattern`. Resolves the descriptor from
91
+ * `formDraft.country` itself rather than taking a second parameter, so this stays a single
92
+ * self-contained fact about one `BillingAddressFormDraft` value. `country` itself is not part of
63
93
  * `descriptor.fields` (Decision 7) and is never checked here — it always carries a non-blank value from
64
94
  * `defaultCountry` or the selector's own current value (review F12), so it can never be the field this
65
95
  * gate would fail on.
66
96
  */
67
97
  function isBillingAddressFormValid(formDraft) {
68
98
  const descriptor = getCountryDescriptor(formDraft.country);
69
- if (!descriptor) return false;
70
- return descriptor.fields.filter((field) => !OMITTED_FORM_FIELD_NAMES.has(field.name) && !OPTIONAL_FORM_FIELD_NAMES.has(field.name)).every((field) => (formDraft[field.name] ?? "").trim().length > 0);
99
+ return descriptor ? areRenderableFieldsValid(getRenderableFields(descriptor), formDraft) : false;
100
+ }
101
+ /**
102
+ * The verdict behind `isBillingAddressFormValid`, taking the renderable fields as an argument so the
103
+ * render path can pass the list it already memoises per country instead of resolving them again on every
104
+ * render. One body for both callers, so the gate can never disagree with itself.
105
+ */
106
+ function areRenderableFieldsValid(renderableFields, formDraft) {
107
+ return renderableFields.every((field) => getFieldIssue(field, formDraft[field.name] ?? "") === null);
108
+ }
109
+ /**
110
+ * Whether the submit control may fire: the active country has a descriptor and every field it renders is
111
+ * valid. Mirrors `isBillingAddressFormValid`, over the descriptor and fields the render path already holds.
112
+ */
113
+ function canSaveBillingDraft(descriptor, renderableFields, formDraft) {
114
+ return descriptor !== void 0 && areRenderableFieldsValid(renderableFields, formDraft);
115
+ }
116
+ /** The touched set with `name` added. Returns `prev` itself when it already holds `name`, so a state update
117
+ * built on it never triggers a redundant re-render. */
118
+ function withTouched(prev, name) {
119
+ return prev.has(name) ? prev : new Set(prev).add(name);
120
+ }
121
+ /**
122
+ * Takes focus for a refusal that named the billing form (T212, Decision 3): the first rendered field, in
123
+ * render order, whose value is blank and which is required, since the shopper has to fill it next; else the
124
+ * first field whose value fails its format (the submit control is disabled while one does, so it cannot
125
+ * take focus); else the submit control, since saving is then the next step. Reads the live DOM inside
126
+ * `panel`, so it never sees stale state. `country` is never a target (it always holds a value). Returns
127
+ * whether focus landed: a disabled field, or a disabled submit control while saving, takes none.
128
+ * `onFieldFocused` receives the name of a field that took focus, so the caller can mark it touched: the
129
+ * shopper is sent there to read its message, and blur would never come.
130
+ */
131
+ function focusNextBillingControl(panel, renderableFields, onFieldFocused) {
132
+ if (!panel) return false;
133
+ const fields = panel.querySelectorAll("[data-fs-billing-address-field]");
134
+ let target = null;
135
+ let malformed = null;
136
+ for (const field of fields) {
137
+ const name = field.dataset.fsBillingAddressField ?? "";
138
+ const input = field.querySelector("input");
139
+ const descriptor = renderableFields.find((candidate) => candidate.name === name);
140
+ if (!input || !descriptor) continue;
141
+ const issue = getFieldIssue(descriptor, input.value);
142
+ if (issue === "required") {
143
+ target = input;
144
+ break;
145
+ }
146
+ if (issue === "format") malformed ??= input;
147
+ }
148
+ target ??= malformed ?? panel.querySelector("[data-fs-billing-address-submit]");
149
+ if (!target) return false;
150
+ target.focus();
151
+ const landed = target.ownerDocument.activeElement === target;
152
+ const fieldName = target.closest("[data-fs-billing-address-field]")?.dataset.fsBillingAddressField;
153
+ if (landed && fieldName) onFieldFocused(fieldName);
154
+ return landed;
71
155
  }
72
156
  const BillingAddressDefinition = defineComponent({
73
157
  name: "BillingAddress",
@@ -170,6 +254,11 @@ const BillingAddressDefinition = defineComponent({
170
254
  default: "This field is required.",
171
255
  label: "Field required message"
172
256
  },
257
+ postalCodeInvalidMessage: {
258
+ type: "string",
259
+ default: "Enter a valid postal code.",
260
+ label: "Postal code format message"
261
+ },
173
262
  disabled: {
174
263
  type: "boolean",
175
264
  default: false,
@@ -178,7 +267,7 @@ const BillingAddressDefinition = defineComponent({
178
267
  },
179
268
  guideline: "Same-as-delivery toggle (default on) for the billing address; when off, mounts a country-specific address form (reusing shipping-address's country descriptors) and persists it via $actions.payment.setBillingAddress on an explicit submit control. Re-checking the toggle dispatches sameAsDelivery: true only once an address was actually persisted (otherwise it's a local no-op — there's nothing on the server to revert). Publishes only a boolean (never the address) onto the shared payment draft for usePlaceOrder to read. While the form is open and nothing has been saved yet, renders an inline status notice — the required attribute on the form's own fields is not a submit gate; Place Order can still complete billed to the delivery address if the shopper never saves. Must be inside a PaymentSectionRoot or PaymentSectionController; place as a sibling of CardEntry/SavedCards/Installments/SaveCard/PlaceOrder, never nested inside any of them. See billing-address.md."
180
269
  });
181
- function BillingAddress({ sameAsDeliveryLabel = "Billing address same as delivery address", defaultCountry = "BRA", countryLabel = "Country", submitLabel = "Save billing address", submitPendingLabel = "Saving...", requiredNoticeLabel = "This payment method requires a billing address.", unsavedAddressNoticeLabel = "No billing address has been saved yet — the delivery address will be used unless you save one below.", billingMatchNoticeLabel = "Your billing address must match the one on your card or bank statement, or your bank may decline the order.", billingMatchNoticeVisible = true, recipientNameLabel = "Recipient's name", streetLabel = "Street", numberLabel = "Number", complementLabel = "Complement (optional)", neighborhoodLabel = "Neighborhood", cityLabel = "City", stateLabel = "State", postalCodeLabel = "Postal code", fieldRequiredMessage, disabled = false, className, $actions: $actionsProp, ...props }) {
270
+ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as delivery address", defaultCountry = "BRA", countryLabel = "Country", submitLabel = "Save billing address", submitPendingLabel = "Saving...", requiredNoticeLabel = "This payment method requires a billing address.", unsavedAddressNoticeLabel = "No billing address has been saved yet — the delivery address will be used unless you save one below.", billingMatchNoticeLabel = "Your billing address must match the one on your card or bank statement, or your bank may decline the order.", billingMatchNoticeVisible = true, recipientNameLabel = "Recipient's name", streetLabel = "Street", numberLabel = "Number", complementLabel = "Complement (optional)", neighborhoodLabel = "Neighborhood", cityLabel = "City", stateLabel = "State", postalCodeLabel = "Postal code", fieldRequiredMessage, postalCodeInvalidMessage, disabled = false, className, $actions: $actionsProp, ...props }) {
182
271
  const $actions = useActionsOverride($actionsProp);
183
272
  const fieldLabels = {
184
273
  recipientName: recipientNameLabel,
@@ -190,7 +279,7 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
190
279
  state: stateLabel,
191
280
  postalCode: postalCodeLabel
192
281
  };
193
- const { draft, selectedMethod, setDraftBillingAddressDifferent, setDraftBillingAddressUnsaved, placing, cardPaymentCollapsed } = usePayment();
282
+ const { draft, selectedMethod, setDraftBillingAddressDifferent, setDraftBillingAddressUnsaved, placing, cardPaymentCollapsed, registerRefusalFocus } = usePayment();
194
283
  const instanceKey = useId();
195
284
  const panelId = useId();
196
285
  const [formDraft, setFormDraft] = useState(() => ({
@@ -220,10 +309,24 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
220
309
  unsavedAddressNoticeVisible,
221
310
  setDraftBillingAddressUnsaved
222
311
  ]);
312
+ const canTakeFocus = !cardPaymentCollapsed && formOpen;
313
+ const draftCountry = formDraft.country;
314
+ const draftDescriptor = useMemo(() => getCountryDescriptor(draftCountry), [draftCountry]);
315
+ const renderableFields = useMemo(() => draftDescriptor ? getRenderableFields(draftDescriptor) : [], [draftDescriptor]);
316
+ useEffect(() => {
317
+ if (!canTakeFocus) return;
318
+ const markTouched = (name) => setTouched((prev) => withTouched(prev, name));
319
+ return registerRefusalFocus("billing-form", () => focusNextBillingControl(document.getElementById(panelId), renderableFields, markTouched));
320
+ }, [
321
+ canTakeFocus,
322
+ renderableFields,
323
+ panelId,
324
+ registerRefusalFocus
325
+ ]);
223
326
  const billingAddressRequired = selectedMethod?.validator.billingAddressRequired ?? false;
224
327
  const fieldsDisabled = disabled || pending;
225
328
  const requiredMessage = resolveAuthoredCopy(fieldRequiredMessage, "This field is required.");
226
- const renderableFields = (getCountryDescriptor(formDraft.country)?.fields ?? []).filter((field) => !OMITTED_FORM_FIELD_NAMES.has(field.name));
329
+ const invalidMessage = resolveAuthoredCopy(postalCodeInvalidMessage, "Enter a valid postal code.");
227
330
  async function handleSameAsDeliveryChange(nextSameAsDelivery) {
228
331
  setError(null);
229
332
  if (!nextSameAsDelivery) {
@@ -257,16 +360,7 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
257
360
  /** Marks a field touched on its first blur (T38, FR-6). Idempotent on every later blur — a `Set`
258
361
  * already containing `name` is returned unchanged, so this never triggers a redundant re-render. */
259
362
  function handleFieldBlur(name) {
260
- setTouched((prev) => prev.has(name) ? prev : new Set(prev).add(name));
261
- }
262
- /**
263
- * A rendered field is invalid once the shopper has touched it, it is blank, and it is not
264
- * `complement` (T38, FR-6, INV-3/INV-4). Mirrors `isBillingAddressFormValid`'s own per-field rule —
265
- * the two are never allowed to disagree about which fields are required, since both read
266
- * `OPTIONAL_FORM_FIELD_NAMES`.
267
- */
268
- function isFieldInvalid(name) {
269
- return touched.has(name) && !OPTIONAL_FORM_FIELD_NAMES.has(name) && (formDraft[name] ?? "").trim().length === 0;
363
+ setTouched((prev) => withTouched(prev, name));
270
364
  }
271
365
  function handleCountryChange(value) {
272
366
  setFormDraft((prev) => ({
@@ -362,7 +456,8 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
362
456
  })]
363
457
  }),
364
458
  renderableFields.map((field) => {
365
- const invalid = isFieldInvalid(field.name);
459
+ const issue = touched.has(field.name) ? getFieldIssue(field, formDraft[field.name] ?? "") : null;
460
+ const invalid = issue !== null;
366
461
  return /* @__PURE__ */ jsxs(Field.Root, {
367
462
  disabled: fieldsDisabled,
368
463
  invalid,
@@ -379,7 +474,7 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
379
474
  }),
380
475
  invalid ? /* @__PURE__ */ jsx(Field.Error, {
381
476
  match: true,
382
- children: requiredMessage
477
+ children: issue === "format" ? getFieldFormatMessage(field, invalidMessage) : requiredMessage
383
478
  }) : null
384
479
  ]
385
480
  }, field.name);
@@ -387,7 +482,7 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
387
482
  /* @__PURE__ */ jsx("button", {
388
483
  type: "button",
389
484
  onClick: handleSubmit,
390
- disabled: fieldsDisabled || !isBillingAddressFormValid(formDraft),
485
+ disabled: fieldsDisabled || !canSaveBillingDraft(draftDescriptor, renderableFields, formDraft),
391
486
  "data-fs-billing-address-submit": "",
392
487
  children: pending ? submitPendingLabel : submitLabel
393
488
  })
@@ -403,6 +498,6 @@ function BillingAddress({ sameAsDeliveryLabel = "Billing address same as deliver
403
498
  });
404
499
  }
405
500
  //#endregion
406
- export { BillingAddress, BillingAddressDefinition, isBillingAddressFormValid, resolveSameAsDelivery };
501
+ export { BillingAddress, BillingAddressDefinition, getFieldFormatMessage, isBillingAddressFormValid, resolveSameAsDelivery };
407
502
 
408
503
  //# sourceMappingURL=billing-address.js.map