@vtex/faststore 0.0.8 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +0 -1
  3. package/dist/actions.json +48 -1
  4. package/dist/catalog.json +1397 -1594
  5. package/dist/cli/index.d.ts +66 -28
  6. package/dist/cli/index.js +7371 -512
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/server-runtime.js +41 -60
  9. package/dist/cli/server-runtime.js.map +1 -1
  10. package/dist/client.d.ts +3 -3
  11. package/dist/client.js +2 -2
  12. package/dist/components.d.ts +67 -56
  13. package/dist/components.js +64 -53
  14. package/dist/content-types.json +5886 -555
  15. package/dist/core/dist/define-component.d.ts +7 -2
  16. package/dist/core/dist/define-content-type.d.ts +50 -2
  17. package/dist/core/dist/define-content-type.js +107 -3
  18. package/dist/core/dist/define-content-type.js.map +1 -1
  19. package/dist/core/dist/index.d.ts +2 -2
  20. package/dist/docs/access-code-field.md +1 -1
  21. package/dist/docs/access-code-sign-in.md +126 -77
  22. package/dist/docs/account-address-book.md +210 -95
  23. package/dist/docs/account-entry-point.md +4 -4
  24. package/dist/docs/account-menu.md +16 -17
  25. package/dist/docs/account-saved-cards.md +306 -0
  26. package/dist/docs/alert-dialog.md +3 -1
  27. package/dist/docs/avatar.md +4 -2
  28. package/dist/docs/billing-address.md +99 -30
  29. package/dist/docs/binding-switcher.md +157 -0
  30. package/dist/docs/buy-button.md +7 -8
  31. package/dist/docs/card-entry.md +42 -29
  32. package/dist/docs/card-summary.md +185 -0
  33. package/dist/docs/cardholder-document.md +5 -3
  34. package/dist/docs/carousel.md +5 -4
  35. package/dist/docs/cart-destination.md +251 -0
  36. package/dist/docs/cart-item.md +48 -15
  37. package/dist/docs/cart-totalizer.md +8 -6
  38. package/dist/docs/cart.md +240 -39
  39. package/dist/docs/challenge-return.md +135 -0
  40. package/dist/docs/client-preferences-fieldset.md +10 -5
  41. package/dist/docs/client-preferences.md +31 -8
  42. package/dist/docs/client-profile-fieldset.md +20 -6
  43. package/dist/docs/client-profile.md +12 -3
  44. package/dist/docs/copy-text.md +9 -7
  45. package/dist/docs/document-field.md +1 -1
  46. package/dist/docs/email-field.md +2 -1
  47. package/dist/docs/email-identification.md +12 -2
  48. package/dist/docs/footer-copyright.md +4 -2
  49. package/dist/docs/footer-social.md +1 -1
  50. package/dist/docs/form.md +54 -18
  51. package/dist/docs/free-shipping-progress.md +18 -13
  52. package/dist/docs/identity-edit.md +8 -2
  53. package/dist/docs/identity-summary.md +18 -5
  54. package/dist/docs/incentives.md +2 -2
  55. package/dist/docs/installments.md +46 -32
  56. package/dist/docs/logo.md +1 -1
  57. package/dist/docs/my-account-profile.md +16 -11
  58. package/dist/docs/navigation-link.md +5 -3
  59. package/dist/docs/order-cancel.md +3 -1
  60. package/dist/docs/order-delivery-address.md +7 -5
  61. package/dist/docs/order-delivery-group.md +1 -3
  62. package/dist/docs/order-details-back.md +1 -1
  63. package/dist/docs/order-details-header.md +1 -4
  64. package/dist/docs/order-invoice-download.md +60 -0
  65. package/dist/docs/order-list-row.md +1 -1
  66. package/dist/docs/order-list-search.md +13 -20
  67. package/dist/docs/order-list-views.md +11 -17
  68. package/dist/docs/order-list.md +12 -5
  69. package/dist/docs/order-payment.md +9 -7
  70. package/dist/docs/order-placed-date.md +1 -1
  71. package/dist/docs/order-placed-payment-summary.md +28 -15
  72. package/dist/docs/order-placed.md +49 -14
  73. package/dist/docs/order-progress.md +1 -1
  74. package/dist/docs/order-status-badge.md +20 -9
  75. package/dist/docs/order-summary.md +2 -2
  76. package/dist/docs/order-tracking-link.md +58 -0
  77. package/dist/docs/payment-method-badges.md +32 -6
  78. package/dist/docs/payment-methods.md +2 -2
  79. package/dist/docs/payment.md +36 -17
  80. package/dist/docs/phone-field.md +4 -4
  81. package/dist/docs/place-order.md +84 -36
  82. package/dist/docs/postal-code-field.md +3 -1
  83. package/dist/docs/pricing.md +21 -23
  84. package/dist/docs/product-gallery.md +19 -20
  85. package/dist/docs/product-information.md +14 -10
  86. package/dist/docs/product-list.md +7 -6
  87. package/dist/docs/product-shelf.md +7 -1
  88. package/dist/docs/promotion.md +4 -2
  89. package/dist/docs/region.md +23 -15
  90. package/dist/docs/save-card.md +7 -6
  91. package/dist/docs/saved-cards.md +65 -36
  92. package/dist/docs/select.md +3 -4
  93. package/dist/docs/shipping-address.md +57 -21
  94. package/dist/docs/shipping-simulator.md +53 -15
  95. package/dist/docs/sign-in-disclosure.md +176 -0
  96. package/dist/docs/sign-in-form.md +78 -47
  97. package/dist/docs/sign-in-redirect.md +5 -3
  98. package/dist/docs/sign-in.md +173 -0
  99. package/dist/docs/toast.md +45 -16
  100. package/dist/docs/variant-selector.md +15 -11
  101. package/dist/graphql/types.d.ts +4 -14
  102. package/dist/index.d.ts +3 -2
  103. package/dist/internal/client.d.ts +4 -3
  104. package/dist/internal/client.js +5 -2
  105. package/dist/internal/server.d.ts +10 -5
  106. package/dist/internal/server.js +9 -4
  107. package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +250 -66
  108. package/dist/matter/access-code-sign-in/access-code-sign-in.js +459 -188
  109. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  110. package/dist/matter/account-address-book/account-address-book-delete.d.ts +78 -40
  111. package/dist/matter/account-address-book/account-address-book-delete.js +86 -50
  112. package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -1
  113. package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +21 -4
  114. package/dist/matter/account-address-book/account-address-book-deliverability.js +45 -17
  115. package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -1
  116. package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +74 -19
  117. package/dist/matter/account-address-book/account-address-book-form-parts.js +77 -26
  118. package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -1
  119. package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +27 -6
  120. package/dist/matter/account-address-book/account-address-book-profile-notice.js +55 -28
  121. package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -1
  122. package/dist/matter/account-address-book/account-address-book.d.ts +67 -14
  123. package/dist/matter/account-address-book/account-address-book.js +74 -33
  124. package/dist/matter/account-address-book/account-address-book.js.map +1 -1
  125. package/dist/matter/account-address-book/account-address-country-switch.js +3 -3
  126. package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -1
  127. package/dist/matter/account-address-book/account-address-country.d.ts +66 -20
  128. package/dist/matter/account-address-book/account-address-country.js +83 -49
  129. package/dist/matter/account-address-book/account-address-country.js.map +1 -1
  130. package/dist/matter/account-address-book/account-address-form-context.d.ts +8 -4
  131. package/dist/matter/account-address-book/account-address-form-context.js.map +1 -1
  132. package/dist/matter/account-address-book/account-address-form.d.ts +468 -45
  133. package/dist/matter/account-address-book/account-address-form.js +518 -155
  134. package/dist/matter/account-address-book/account-address-form.js.map +1 -1
  135. package/dist/matter/account-address-book/account-address-record.d.ts +27 -6
  136. package/dist/matter/account-address-book/account-address-record.js +32 -17
  137. package/dist/matter/account-address-book/account-address-record.js.map +1 -1
  138. package/dist/matter/account-menu/account-menu.d.ts +34 -17
  139. package/dist/matter/account-menu/account-menu.js +46 -54
  140. package/dist/matter/account-menu/account-menu.js.map +1 -1
  141. package/dist/matter/account-menu-identity/account-menu-identity.js +1 -1
  142. package/dist/matter/account-saved-cards/account-saved-cards.d.ts +463 -0
  143. package/dist/matter/account-saved-cards/account-saved-cards.js +1011 -0
  144. package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
  145. package/dist/matter/billing-address/billing-address.d.ts +156 -74
  146. package/dist/matter/billing-address/billing-address.js +227 -156
  147. package/dist/matter/billing-address/billing-address.js.map +1 -1
  148. package/dist/matter/breadcrumb/breadcrumb.d.ts +21 -3
  149. package/dist/matter/breadcrumb/breadcrumb.js +24 -9
  150. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
  151. package/dist/matter/buy-button/buy-button.d.ts +8 -11
  152. package/dist/matter/buy-button/buy-button.js +10 -19
  153. package/dist/matter/buy-button/buy-button.js.map +1 -1
  154. package/dist/matter/card-entry/card-capture.js +12 -4
  155. package/dist/matter/card-entry/card-capture.js.map +1 -1
  156. package/dist/matter/card-entry/card-entry.d.ts +123 -32
  157. package/dist/matter/card-entry/card-entry.js +348 -221
  158. package/dist/matter/card-entry/card-entry.js.map +1 -1
  159. package/dist/matter/cart/cart-namespace.d.ts +11 -1
  160. package/dist/matter/cart/cart-namespace.js +11 -1
  161. package/dist/matter/cart/cart-namespace.js.map +1 -1
  162. package/dist/matter/cart/cart.d.ts +416 -45
  163. package/dist/matter/cart/cart.js +782 -101
  164. package/dist/matter/cart/cart.js.map +1 -1
  165. package/dist/matter/cart-destination/cart-destination.d.ts +233 -0
  166. package/dist/matter/cart-destination/cart-destination.js +703 -0
  167. package/dist/matter/cart-destination/cart-destination.js.map +1 -0
  168. package/dist/matter/cart-item/cart-item.d.ts +145 -16
  169. package/dist/matter/cart-item/cart-item.js +230 -54
  170. package/dist/matter/cart-item/cart-item.js.map +1 -1
  171. package/dist/matter/cart-item-compositions/cart-item-compositions.js +1 -1
  172. package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -1
  173. package/dist/matter/cart-item-customizations/cart-item-customizations.js +1 -1
  174. package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -1
  175. package/dist/matter/cart-item-discounts/cart-item-discounts.js +1 -1
  176. package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -1
  177. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +1 -1
  178. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -1
  179. package/dist/matter/cart-item-variations/cart-item-variations.js +1 -1
  180. package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -1
  181. package/dist/matter/cart-totalizer/cart-totalizer.d.ts +43 -9
  182. package/dist/matter/cart-totalizer/cart-totalizer.js +49 -19
  183. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
  184. package/dist/matter/challenge-return/challenge-return.d.ts +62 -0
  185. package/dist/matter/challenge-return/challenge-return.js +241 -0
  186. package/dist/matter/challenge-return/challenge-return.js.map +1 -0
  187. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +86 -17
  188. package/dist/matter/client-preferences/client-preferences-fieldset.js +126 -54
  189. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -1
  190. package/dist/matter/client-preferences/client-preferences.d.ts +50 -7
  191. package/dist/matter/client-preferences/client-preferences.js +84 -15
  192. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  193. package/dist/matter/client-profile/client-profile.d.ts +44 -9
  194. package/dist/matter/client-profile/client-profile.js +64 -24
  195. package/dist/matter/client-profile/client-profile.js.map +1 -1
  196. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -22
  197. package/dist/matter/client-profile-form/client-profile-fieldset.js +161 -73
  198. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
  199. package/dist/matter/delivery-options/delivery-options-accordion.d.ts +49 -4
  200. package/dist/matter/delivery-options/delivery-options-accordion.js +67 -14
  201. package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -1
  202. package/dist/matter/delivery-options/delivery-options-controller.d.ts +69 -9
  203. package/dist/matter/delivery-options/delivery-options-controller.js +80 -14
  204. package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -1
  205. package/dist/matter/delivery-options/delivery-options.d.ts +37 -2
  206. package/dist/matter/delivery-options/delivery-options.js +75 -12
  207. package/dist/matter/delivery-options/delivery-options.js.map +1 -1
  208. package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +1 -0
  209. package/dist/matter/delivery-options/use-delivery-option-selection.js +1 -1
  210. package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -1
  211. package/dist/matter/email-identification/email-identification.d.ts +25 -3
  212. package/dist/matter/email-identification/email-identification.js +49 -12
  213. package/dist/matter/email-identification/email-identification.js.map +1 -1
  214. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +85 -10
  215. package/dist/matter/free-shipping-progress/free-shipping-progress.js +153 -53
  216. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
  217. package/dist/matter/identity-edit/identity-edit.d.ts +52 -10
  218. package/dist/matter/identity-edit/identity-edit.js +47 -19
  219. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  220. package/dist/matter/identity-summary/identity-summary.d.ts +76 -22
  221. package/dist/matter/identity-summary/identity-summary.js +95 -45
  222. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  223. package/dist/matter/installments/installments-select.d.ts +98 -16
  224. package/dist/matter/installments/installments-select.js +156 -48
  225. package/dist/matter/installments/installments-select.js.map +1 -1
  226. package/dist/matter/installments/installments.d.ts +96 -16
  227. package/dist/matter/installments/installments.js +115 -40
  228. package/dist/matter/installments/installments.js.map +1 -1
  229. package/dist/matter/installments/use-installments-selection.d.ts +1 -0
  230. package/dist/matter/installments/use-installments-selection.js +8 -3
  231. package/dist/matter/installments/use-installments-selection.js.map +1 -1
  232. package/dist/matter/my-account-profile/my-account-profile.d.ts +358 -103
  233. package/dist/matter/my-account-profile/my-account-profile.js +370 -174
  234. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  235. package/dist/matter/order-cancel/order-cancel.d.ts +65 -19
  236. package/dist/matter/order-cancel/order-cancel.js +118 -51
  237. package/dist/matter/order-cancel/order-cancel.js.map +1 -1
  238. package/dist/matter/order-delivery-address/order-delivery-address.d.ts +8 -18
  239. package/dist/matter/order-delivery-address/order-delivery-address.js +14 -23
  240. package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -1
  241. package/dist/matter/order-delivery-group/order-delivery-group.d.ts +40 -24
  242. package/dist/matter/order-delivery-group/order-delivery-group.js +64 -74
  243. package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -1
  244. package/dist/matter/order-details-header/order-details-header.d.ts +32 -15
  245. package/dist/matter/order-details-header/order-details-header.js +66 -58
  246. package/dist/matter/order-details-header/order-details-header.js.map +1 -1
  247. package/dist/matter/order-invoice-download/order-invoice-download.d.ts +78 -0
  248. package/dist/matter/order-invoice-download/order-invoice-download.js +173 -0
  249. package/dist/matter/order-invoice-download/order-invoice-download.js.map +1 -0
  250. package/dist/matter/order-list/order-list.d.ts +164 -19
  251. package/dist/matter/order-list/order-list.js +229 -87
  252. package/dist/matter/order-list/order-list.js.map +1 -1
  253. package/dist/matter/order-list-row/order-list-row.d.ts +6 -1
  254. package/dist/matter/order-list-row/order-list-row.js +3 -2
  255. package/dist/matter/order-list-row/order-list-row.js.map +1 -1
  256. package/dist/matter/order-list-search/order-list-search.d.ts +18 -26
  257. package/dist/matter/order-list-search/order-list-search.js +30 -69
  258. package/dist/matter/order-list-search/order-list-search.js.map +1 -1
  259. package/dist/matter/order-list-views/order-list-views.d.ts +15 -22
  260. package/dist/matter/order-list-views/order-list-views.js +22 -68
  261. package/dist/matter/order-list-views/order-list-views.js.map +1 -1
  262. package/dist/matter/order-payment/order-payment.d.ts +33 -10
  263. package/dist/matter/order-payment/order-payment.js +44 -39
  264. package/dist/matter/order-payment/order-payment.js.map +1 -1
  265. package/dist/matter/order-placed/order-placed-deliveries.d.ts +144 -12
  266. package/dist/matter/order-placed/order-placed-deliveries.js +115 -40
  267. package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -1
  268. package/dist/matter/order-placed/order-placed.d.ts +198 -31
  269. package/dist/matter/order-placed/order-placed.js +230 -139
  270. package/dist/matter/order-placed/order-placed.js.map +1 -1
  271. package/dist/matter/order-placed-date/order-placed-date.d.ts +5 -8
  272. package/dist/matter/order-placed-date/order-placed-date.js +7 -8
  273. package/dist/matter/order-placed-date/order-placed-date.js.map +1 -1
  274. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +90 -17
  275. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +93 -117
  276. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
  277. package/dist/matter/order-progress/order-progress.d.ts +19 -8
  278. package/dist/matter/order-progress/order-progress.js +37 -45
  279. package/dist/matter/order-progress/order-progress.js.map +1 -1
  280. package/dist/matter/order-summary/order-summary.d.ts +19 -9
  281. package/dist/matter/order-summary/order-summary.js +38 -44
  282. package/dist/matter/order-summary/order-summary.js.map +1 -1
  283. package/dist/matter/order-tracking-link/order-tracking-link.d.ts +43 -0
  284. package/dist/matter/order-tracking-link/order-tracking-link.js +107 -0
  285. package/dist/matter/order-tracking-link/order-tracking-link.js.map +1 -0
  286. package/dist/matter/payment/payment-card-capture.js +17 -10
  287. package/dist/matter/payment/payment-card-capture.js.map +1 -1
  288. package/dist/matter/payment/payment-controller.d.ts +4 -2
  289. package/dist/matter/payment/payment-controller.js +30 -9
  290. package/dist/matter/payment/payment-controller.js.map +1 -1
  291. package/dist/matter/payment/payment-method-badges.js +1 -1
  292. package/dist/matter/payment/payment.d.ts +69 -19
  293. package/dist/matter/payment/payment.js +101 -35
  294. package/dist/matter/payment/payment.js.map +1 -1
  295. package/dist/matter/payment/use-payment-method-selection.d.ts +25 -4
  296. package/dist/matter/payment/use-payment-method-selection.js +94 -32
  297. package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
  298. package/dist/matter/payment/use-payment-submit-gate.d.ts +14 -3
  299. package/dist/matter/payment/use-payment-submit-gate.js +47 -8
  300. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
  301. package/dist/matter/place-order/place-order.d.ts +171 -57
  302. package/dist/matter/place-order/place-order.js +376 -185
  303. package/dist/matter/place-order/place-order.js.map +1 -1
  304. package/dist/matter/pricing/pricing.d.ts +152 -13
  305. package/dist/matter/pricing/pricing.js +153 -52
  306. package/dist/matter/pricing/pricing.js.map +1 -1
  307. package/dist/matter/product-information/product-information.d.ts +27 -4
  308. package/dist/matter/product-information/product-information.js +32 -15
  309. package/dist/matter/product-information/product-information.js.map +1 -1
  310. package/dist/matter/product-list/product-list.d.ts +24 -6
  311. package/dist/matter/product-list/product-list.js +32 -26
  312. package/dist/matter/product-list/product-list.js.map +1 -1
  313. package/dist/matter/product-shelf/product-shelf.d.ts +8 -3
  314. package/dist/matter/product-shelf/product-shelf.js +111 -10
  315. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  316. package/dist/matter/region/region.d.ts +33 -16
  317. package/dist/matter/region/region.js +59 -52
  318. package/dist/matter/region/region.js.map +1 -1
  319. package/dist/matter/save-card/save-card.d.ts +43 -8
  320. package/dist/matter/save-card/save-card.js +61 -23
  321. package/dist/matter/save-card/save-card.js.map +1 -1
  322. package/dist/matter/saved-cards/saved-cards.d.ts +113 -21
  323. package/dist/matter/saved-cards/saved-cards.js +349 -77
  324. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  325. package/dist/matter/shipping-address/address-payload.js +25 -0
  326. package/dist/matter/shipping-address/address-payload.js.map +1 -0
  327. package/dist/matter/shipping-address/country-descriptors.js +71 -71
  328. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  329. package/dist/matter/shipping-address/library-country-descriptors.js +136 -0
  330. package/dist/matter/shipping-address/library-country-descriptors.js.map +1 -0
  331. package/dist/matter/shipping-address/shipping-address.d.ts +312 -45
  332. package/dist/matter/shipping-address/shipping-address.js +443 -188
  333. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  334. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +251 -25
  335. package/dist/matter/shipping-simulator/shipping-simulator.js +261 -51
  336. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  337. package/dist/matter/sign-in/sign-in.d.ts +108 -0
  338. package/dist/matter/sign-in/sign-in.js +285 -0
  339. package/dist/matter/sign-in/sign-in.js.map +1 -0
  340. package/dist/matter/sign-in-disclosure/sign-in-disclosure.d.ts +81 -0
  341. package/dist/matter/sign-in-disclosure/sign-in-disclosure.js +232 -0
  342. package/dist/matter/sign-in-disclosure/sign-in-disclosure.js.map +1 -0
  343. package/dist/matter/sign-in-form/sign-in-form.d.ts +93 -62
  344. package/dist/matter/sign-in-form/sign-in-form.js +134 -144
  345. package/dist/matter/sign-in-form/sign-in-form.js.map +1 -1
  346. package/dist/particles/binding-switcher/binding-switcher.d.ts +59 -0
  347. package/dist/particles/binding-switcher/binding-switcher.js +194 -0
  348. package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
  349. package/dist/particles/card-summary/card-network.d.ts +17 -0
  350. package/dist/particles/card-summary/card-network.js +25 -0
  351. package/dist/particles/card-summary/card-network.js.map +1 -0
  352. package/dist/particles/card-summary/card-summary.d.ts +113 -0
  353. package/dist/particles/card-summary/card-summary.js +221 -0
  354. package/dist/particles/card-summary/card-summary.js.map +1 -0
  355. package/dist/particles/carousel/carousel.d.ts +99 -11
  356. package/dist/particles/carousel/carousel.js +103 -35
  357. package/dist/particles/carousel/carousel.js.map +1 -1
  358. package/dist/particles/copy-text/copy-text.js +5 -15
  359. package/dist/particles/copy-text/copy-text.js.map +1 -1
  360. package/dist/particles/dialog/dialog.d.ts +14 -6
  361. package/dist/particles/dialog/dialog.js +6 -3
  362. package/dist/particles/dialog/dialog.js.map +1 -1
  363. package/dist/particles/drawer/drawer.js +1 -1
  364. package/dist/particles/drawer/drawer.js.map +1 -1
  365. package/dist/particles/email-field/email-field.d.ts +2 -1
  366. package/dist/particles/email-field/email-field.js +2 -1
  367. package/dist/particles/email-field/email-field.js.map +1 -1
  368. package/dist/particles/footer-link-group/footer-link-group.js +1 -0
  369. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
  370. package/dist/particles/footer-social/footer-social.d.ts +1 -1
  371. package/dist/particles/footer-social/footer-social.js +1 -1
  372. package/dist/particles/footer-social/footer-social.js.map +1 -1
  373. package/dist/particles/form/form.d.ts +85 -13
  374. package/dist/particles/form/form.js +91 -42
  375. package/dist/particles/form/form.js.map +1 -1
  376. package/dist/particles/gallery/gallery.d.ts +129 -12
  377. package/dist/particles/gallery/gallery.js +121 -34
  378. package/dist/particles/gallery/gallery.js.map +1 -1
  379. package/dist/particles/incentives/incentives.d.ts +1 -1
  380. package/dist/particles/incentives/incentives.js +1 -1
  381. package/dist/particles/incentives/incentives.js.map +1 -1
  382. package/dist/particles/order-details-back/order-details-back.d.ts +5 -3
  383. package/dist/particles/order-details-back/order-details-back.js +8 -10
  384. package/dist/particles/order-details-back/order-details-back.js.map +1 -1
  385. package/dist/particles/order-status-badge/order-status-badge.d.ts +3 -3
  386. package/dist/particles/order-status-badge/order-status-badge.js +4 -20
  387. package/dist/particles/order-status-badge/order-status-badge.js.map +1 -1
  388. package/dist/particles/password-field/password-field.d.ts +1 -1
  389. package/dist/particles/password-field/password-field.js +2 -4
  390. package/dist/particles/password-field/password-field.js.map +1 -1
  391. package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
  392. package/dist/particles/payment-methods/payment-methods.js +1 -1
  393. package/dist/particles/payment-methods/payment-methods.js.map +1 -1
  394. package/dist/particles/phone-field/phone-field.d.ts +4 -4
  395. package/dist/particles/phone-field/phone-field.js +8 -11
  396. package/dist/particles/phone-field/phone-field.js.map +1 -1
  397. package/dist/particles/spinner/spinner.d.ts +24 -4
  398. package/dist/particles/spinner/spinner.js +25 -9
  399. package/dist/particles/spinner/spinner.js.map +1 -1
  400. package/dist/particles/switch/switch.d.ts +4 -1
  401. package/dist/particles/switch/switch.js +3 -1
  402. package/dist/particles/switch/switch.js.map +1 -1
  403. package/dist/particles/toast/toast.d.ts +49 -9
  404. package/dist/particles/toast/toast.js +81 -15
  405. package/dist/particles/toast/toast.js.map +1 -1
  406. package/dist/schema.graphql +461 -89
  407. package/dist/sdk/actions/index.d.ts +3 -1
  408. package/dist/sdk/actions/index.js +3 -1
  409. package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
  410. package/dist/sdk/actions/locale-action-provider.js +20 -0
  411. package/dist/sdk/actions/locale-action-provider.js.map +1 -0
  412. package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
  413. package/dist/sdk/actions/saved-card-action-provider.js +16 -0
  414. package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
  415. package/dist/sdk/actions/types.d.ts +6 -2
  416. package/dist/sdk/address/address-fields.js +4 -4
  417. package/dist/sdk/address/address-fields.js.map +1 -1
  418. package/dist/sdk/address/constants.js +1 -6
  419. package/dist/sdk/address/constants.js.map +1 -1
  420. package/dist/sdk/address/messages.js +44 -44
  421. package/dist/sdk/address/messages.js.map +1 -1
  422. package/dist/sdk/address/postal-code.js +15 -2
  423. package/dist/sdk/address/postal-code.js.map +1 -1
  424. package/dist/sdk/address/types.d.ts +5 -3
  425. package/dist/sdk/address/validate-address.js +3 -3
  426. package/dist/sdk/address/validate-address.js.map +1 -1
  427. package/dist/sdk/analytics/use-analytics-actions.d.ts +1 -1
  428. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
  429. package/dist/sdk/cache/storefront-cache.js +2 -1
  430. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  431. package/dist/sdk/cart/operations.d.ts +2 -1
  432. package/dist/sdk/cart/operations.js +55 -1
  433. package/dist/sdk/cart/operations.js.map +1 -1
  434. package/dist/sdk/cart/optimistic.d.ts +30 -7
  435. package/dist/sdk/cart/optimistic.js +78 -41
  436. package/dist/sdk/cart/optimistic.js.map +1 -1
  437. package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
  438. package/dist/sdk/cart/use-cart-actions.js +61 -15
  439. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  440. package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
  441. package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
  442. package/dist/sdk/data/index.js +2 -2
  443. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  444. package/dist/sdk/generated/gql.js +16 -12
  445. package/dist/sdk/generated/gql.js.map +1 -1
  446. package/dist/sdk/generated/graphql.d.ts +197 -51
  447. package/dist/sdk/generated/graphql.js +2318 -91
  448. package/dist/sdk/generated/graphql.js.map +1 -1
  449. package/dist/sdk/i18n/format-error-code.js +23 -0
  450. package/dist/sdk/i18n/format-error-code.js.map +1 -0
  451. package/dist/sdk/i18n/message-formatter.d.ts +22 -0
  452. package/dist/sdk/i18n/message-formatter.js +140 -0
  453. package/dist/sdk/i18n/message-formatter.js.map +1 -0
  454. package/dist/sdk/i18n/use-message-formatter.d.ts +8 -0
  455. package/dist/sdk/i18n/use-message-formatter.js +18 -0
  456. package/dist/sdk/i18n/use-message-formatter.js.map +1 -0
  457. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  458. package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
  459. package/dist/sdk/locale/binding-switch-provider.js +20 -0
  460. package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
  461. package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
  462. package/dist/sdk/locale/use-locale-actions.js +70 -0
  463. package/dist/sdk/locale/use-locale-actions.js.map +1 -0
  464. package/dist/sdk/navigation/binding-switch.d.ts +39 -0
  465. package/dist/sdk/navigation/binding-switch.js +129 -0
  466. package/dist/sdk/navigation/binding-switch.js.map +1 -0
  467. package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
  468. package/dist/sdk/navigation/decode-route-params.js +32 -0
  469. package/dist/sdk/navigation/decode-route-params.js.map +1 -0
  470. package/dist/sdk/navigation/redirect.d.ts +2 -0
  471. package/dist/sdk/navigation/redirect.js +19 -1
  472. package/dist/sdk/navigation/redirect.js.map +1 -1
  473. package/dist/sdk/navigation/types.d.ts +13 -0
  474. package/dist/sdk/payment/bin-format.js +20 -0
  475. package/dist/sdk/payment/bin-format.js.map +1 -0
  476. package/dist/sdk/payment/challenge-return.js +37 -0
  477. package/dist/sdk/payment/challenge-return.js.map +1 -0
  478. package/dist/sdk/payment/confirmation-last-four.js +39 -0
  479. package/dist/sdk/payment/confirmation-last-four.js.map +1 -0
  480. package/dist/sdk/payment/gateway.d.ts +1 -1
  481. package/dist/sdk/payment/gateway.js +8 -2
  482. package/dist/sdk/payment/gateway.js.map +1 -1
  483. package/dist/sdk/payment/operations.d.ts +1 -0
  484. package/dist/sdk/payment/operations.js +28 -6
  485. package/dist/sdk/payment/operations.js.map +1 -1
  486. package/dist/sdk/payment/resumed-purchase.d.ts +1 -0
  487. package/dist/sdk/payment/resumed-purchase.js +119 -0
  488. package/dist/sdk/payment/resumed-purchase.js.map +1 -0
  489. package/dist/sdk/payment/security-code-mask.js +16 -23
  490. package/dist/sdk/payment/security-code-mask.js.map +1 -1
  491. package/dist/sdk/payment/submission-registry.js +6 -2
  492. package/dist/sdk/payment/submission-registry.js.map +1 -1
  493. package/dist/sdk/payment/use-payment-actions.d.ts +18 -3
  494. package/dist/sdk/payment/use-payment-actions.js +23 -3
  495. package/dist/sdk/payment/use-payment-actions.js.map +1 -1
  496. package/dist/sdk/payment/use-place-order.d.ts +10 -2
  497. package/dist/sdk/payment/use-place-order.js +138 -76
  498. package/dist/sdk/payment/use-place-order.js.map +1 -1
  499. package/dist/sdk/provider/storefront-provider.d.ts +1 -7
  500. package/dist/sdk/provider/storefront-provider.js +4 -11
  501. package/dist/sdk/provider/storefront-provider.js.map +1 -1
  502. package/dist/sdk/saved-cards/operations.d.ts +16 -0
  503. package/dist/sdk/saved-cards/operations.js +41 -0
  504. package/dist/sdk/saved-cards/operations.js.map +1 -0
  505. package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
  506. package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
  507. package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
  508. package/dist/sdk/seo/entity-landing.d.ts +24 -0
  509. package/dist/sdk/seo/entity-landing.js +30 -0
  510. package/dist/sdk/seo/entity-landing.js.map +1 -0
  511. package/dist/sdk/seo/page-alternates.d.ts +8 -5
  512. package/dist/sdk/seo/page-alternates.js +11 -14
  513. package/dist/sdk/seo/page-alternates.js.map +1 -1
  514. package/dist/sdk/seo/search-landing.d.ts +42 -0
  515. package/dist/sdk/seo/search-landing.js +85 -0
  516. package/dist/sdk/seo/search-landing.js.map +1 -0
  517. package/dist/sdk/session/mock-session.d.ts +9 -0
  518. package/dist/sdk/session/mock-session.js +31 -0
  519. package/dist/sdk/session/mock-session.js.map +1 -0
  520. package/dist/sdk/session/read-server-session.d.ts +3 -0
  521. package/dist/sdk/session/read-server-session.js +5 -0
  522. package/dist/sdk/session/read-server-session.js.map +1 -1
  523. package/dist/sdk/session/return-path-segment.d.ts +10 -0
  524. package/dist/sdk/session/return-path-segment.js +15 -0
  525. package/dist/sdk/session/return-path-segment.js.map +1 -0
  526. package/dist/sdk/session/use-session-actions.js.map +1 -1
  527. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  528. package/dist/sdk/shipping/shipping-operations.js +13 -0
  529. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  530. package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -1
  531. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
  532. package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -1
  533. package/dist/sdk/state/cart.d.ts +9 -2
  534. package/dist/sdk/state/cart.js +9 -2
  535. package/dist/sdk/state/cart.js.map +1 -1
  536. package/dist/utils/safe-href.d.ts +2 -0
  537. package/package.json +4 -3
  538. package/skills/storefront-asset/SKILL.md +2 -2
  539. package/skills/storefront-asset/references/api-side.md +27 -14
  540. package/skills/storefront-asset/references/findings.md +5 -2
  541. package/src/styles/tailwind.css +9 -2
  542. package/dist/matter/shipping-address/country-descriptors.d.ts +0 -1
  543. package/dist/message-locales.json +0 -7
  544. package/dist/sdk/i18n/client.d.ts +0 -4
  545. package/dist/sdk/i18n/client.js +0 -4
  546. package/dist/sdk/i18n/locales.d.ts +0 -8
  547. package/dist/sdk/i18n/locales.js +0 -57
  548. package/dist/sdk/i18n/locales.js.map +0 -1
  549. package/dist/sdk/i18n/messages/en-US.js +0 -164
  550. package/dist/sdk/i18n/messages/en-US.js.map +0 -1
  551. package/dist/sdk/i18n/messages/en-US.json +0 -159
  552. package/dist/sdk/i18n/messages/en-US.json.d.ts +0 -163
  553. package/dist/sdk/i18n/messages/es-ES.js +0 -164
  554. package/dist/sdk/i18n/messages/es-ES.js.map +0 -1
  555. package/dist/sdk/i18n/messages/es-ES.json +0 -159
  556. package/dist/sdk/i18n/messages/pt-BR.js +0 -164
  557. package/dist/sdk/i18n/messages/pt-BR.js.map +0 -1
  558. package/dist/sdk/i18n/messages/pt-BR.json +0 -159
  559. package/dist/sdk/i18n/provider.d.ts +0 -1
  560. package/dist/sdk/i18n/provider.js +0 -30
  561. package/dist/sdk/i18n/provider.js.map +0 -1
  562. package/dist/sdk/i18n/server.d.ts +0 -28
  563. package/dist/sdk/i18n/server.js +0 -59
  564. package/dist/sdk/i18n/server.js.map +0 -1
  565. package/dist/utils/resolve-authored-copy.js +0 -18
  566. package/dist/utils/resolve-authored-copy.js.map +0 -1
  567. package/dist/utils/substitute-template.js +0 -33
  568. package/dist/utils/substitute-template.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client-preferences-fieldset.js","names":[],"sources":["../../../src/matter/client-preferences/client-preferences-fieldset.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport { Checkbox } from '../../particles/checkbox/checkbox.js';\nimport type { FieldRule } from '../../particles/field/field.js';\nimport {\n Field,\n FieldBinding,\n FieldsetFieldContext,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { useFormRegistry } from '../../particles/form/form.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { 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 { useEntityDataResolved } from '../../sdk/data/entity-resolution-context.js';\nimport { useReactiveDataSettled } from '../../sdk/data/use-reactive-data-settled.js';\nimport type { ClientPreferenceKey, ClientPreferencesUpdateInput } from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * `ClientPreferencesFieldset` — the composable, one-Save write of the `ClientPreferences` sibling\n * entity (RFC: Composable Entity Forms, `Proposal > Design > The fieldset`). It registers itself with\n * the enclosing `FormRoot` under the `clientPreferences` namespace and dispatches\n * `$actions.identity.clientPreferencesUpdate` for its own submit slot; it renders no `<form>` of its\n * own.\n *\n * `ClientPreferencesRoot` (`client-preferences.tsx`) already reads both flags and writes on toggle; this\n * fieldset is a second, batched write timing for the same two flags. To keep the two from compiling into\n * each other's container, the shipped self-persisting matter's context is renamed to\n * `client-preferences-toggle`, freeing `client-preferences` for this fieldset. Placing\n * `NewsletterOptInControl` inside this fieldset, or `ClientPreferencesNewsletterControl` inside\n * `ClientPreferencesRoot`, is therefore a build failure rather than a surprise write.\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated on the fieldset, its own data root\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientPreferencesFieldsetData on Query {\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the ClientPreferences sibling entity, unwrapped. */\nexport type ClientPreferencesFieldsetData = {\n optinNewsLetter?: boolean | null;\n savePersonalData?: boolean | null;\n} | null;\n\n/** What the fieldset publishes to its controls. Carries no live value — react-hook-form owns those. */\ntype ClientPreferencesFieldsetContextValue = Readonly<{\n namespace: 'clientPreferences';\n /** Seeds, resolved from `$data`. `null` (not chosen yet) reads as unchecked, per the opt-in default. */\n saved: Readonly<Record<ClientPreferenceKey, boolean>>;\n /** True when the session reports `canEditData: false`. */\n readOnly: boolean;\n /** The fieldset's own validation rules, per key. Present and empty today (Decision 6). */\n rules: Readonly<Partial<Record<ClientPreferenceKey, FieldRule>>>;\n}>;\n\n/** No control publishes a rule today (Decision 6) — kept as a stable empty object so the context\n * value's identity does not churn on every render. */\nconst NO_RULES: Readonly<Partial<Record<ClientPreferenceKey, FieldRule>>> = {};\n\n/**\n * Rows `ClientPreferencesFieldsetSkeleton` draws when nobody says otherwise: one per consent flag in\n * the full anatomy. It is a default and not a derivation, because the composed children are opaque\n * here. A page that composes only one control sets `skeletonCount` to 1, or the form jumps by a row\n * when the controls take the skeleton's place.\n */\nconst CLIENT_PREFERENCES_SKELETON_ROWS = 2;\n\nconst CLIENT_PREFERENCES_FIELDSET_UNSET = Symbol('ClientPreferencesFieldsetContextUnset');\n\nconst ClientPreferencesFieldsetContext = createContext<\n ClientPreferencesFieldsetContextValue | typeof CLIENT_PREFERENCES_FIELDSET_UNSET\n>(CLIENT_PREFERENCES_FIELDSET_UNSET);\n\nfunction useClientPreferencesFieldsetContext(): ClientPreferencesFieldsetContextValue {\n const ctx = useContext(ClientPreferencesFieldsetContext);\n if (ctx === CLIENT_PREFERENCES_FIELDSET_UNSET) {\n throw new Error('ClientPreferencesFieldset controls must be used inside ClientPreferencesFieldset.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport type ClientPreferencesFieldsetProps = {\n /** Placeholder rows the loading skeleton draws. Set it to the number of controls composed here. */\n skeletonCount?: number;\n /** Announced politely while the preferences resolve. Blank means no announcement. */\n loadingLabel?: string;\n /** Announced politely once the controls mount. Blank means no announcement. */\n loadedLabel?: string;\n /** Accessible name of the `<fieldset>` group. Blank means no name is exposed. */\n groupLabel?: string;\n className?: string;\n children?: ReactNode;\n /** `ClientPreferencesFieldsetData` slice forwarded by the reactive runtime. */\n $data?: ClientPreferencesFieldsetData;\n /** Compiler-injected; carries `identity.clientPreferencesUpdate`. */\n $actions?: ComponentActions;\n};\n\ntype PreferenceControlProps = { label?: string; className?: string; children?: ReactNode };\n\nexport type ClientPreferencesNewsletterControlProps = PreferenceControlProps;\nexport type ClientPreferencesSavePersonalDataControlProps = PreferenceControlProps;\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferencesFieldsetDefinition = defineComponent<ClientPreferencesFieldsetProps>({\n name: 'ClientPreferencesFieldset',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesFieldset,\n fragment,\n fetchStrategy: 'reactive',\n skeleton: ClientPreferencesFieldsetSkeleton,\n requiresContext: ['form', 'session'],\n providesContext: 'client-preferences',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Client Preferences Fieldset', category: 'identity' },\n schema: {\n skeletonCount: { type: 'number', default: 2, label: 'Skeleton rows' },\n loadingLabel: { type: 'string', default: 'Loading your preferences', label: 'Loading announcement' },\n loadedLabel: { type: 'string', default: 'Your preferences are ready', label: 'Loaded announcement' },\n groupLabel: { type: 'string', default: 'Your preferences', label: 'Accessible group name' },\n },\n guideline:\n \"Registers a batched write of the ClientPreferences entity with the enclosing FormRoot; renders one Fieldset.Root and no <form>. Distinct from ClientPreferencesRoot (matter/client-preferences), which writes on toggle and requires client-preferences-toggle — the two cannot compile into each other's container. Must be inside a FormRoot with a SessionRoot ancestor. Compose ClientPreferencesNewsletterControl and/or ClientPreferencesSavePersonalDataControl as children. The controls mount only once the preferences have resolved, with skeletonCount placeholder rows in their place until then — set it to the number of controls composed, or the form jumps by the difference. Style the announcement sr-only. Dispatches only the flags the shopper changed. groupLabel names the group as its accessible name; blank emits no aria-label, and a composed FieldsetLegend wins over it.\",\n});\n\nexport const ClientPreferencesNewsletterControlDefinition = defineComponent<ClientPreferencesNewsletterControlProps>({\n name: 'ClientPreferencesNewsletterControl',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesNewsletterControl,\n requiresContext: 'client-preferences',\n providesContext: 'field',\n editor: { label: 'Client Preferences Newsletter Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n \"The bound newsletter opt-in control; must be a descendant of ClientPreferencesFieldset. Renders Field.Root > Field.Label > Field.Checkbox by default, or the composed children in the author's own order. Defaults to unchecked.\",\n});\n\nexport const ClientPreferencesSavePersonalDataControlDefinition =\n defineComponent<ClientPreferencesSavePersonalDataControlProps>({\n name: 'ClientPreferencesSavePersonalDataControl',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesSavePersonalDataControl,\n requiresContext: 'client-preferences',\n providesContext: 'field',\n editor: { label: 'Client Preferences Save Personal Data Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n \"The bound save-personal-data opt-in control; must be a descendant of ClientPreferencesFieldset. Renders Field.Root > Field.Label > Field.Checkbox by default, or the composed children in the author's own order. Defaults to unchecked.\",\n });\n\n// ---------------------------------------------------------------------------\n// Fieldset root\n// ---------------------------------------------------------------------------\n\n/**\n * Registers a batched write of the `ClientPreferences` entity with the enclosing `FormRoot`\n * (`registerFieldset`, namespace `clientPreferences`) on mount, unconditionally — so this fieldset keeps\n * its original dispatch slot even while its own query is still resolving. Its children — the seed values\n * and the field-name registry its controls need — render only once the entity has resolved; until then\n * the `Fieldset.Root` carries `-pending` and renders `ClientPreferencesFieldsetSkeleton` (Decision 5).\n * `dispatch` and `toPayload` are `useCallback([])`-stable and read `$actions` through a ref, so the\n * registration effect runs exactly once per mount regardless of how often the parent re-renders.\n *\n * \"Resolved\" is two conditions, because `$data` alone cannot answer it. Under the reactive runtime the\n * slice is defined from the first render — `useReactiveEntity` hands down `fallbackData` while the cache\n * read is incomplete — so an empty server answer looks exactly like a resolved one, and the checkboxes\n * would mount seeded unchecked before the shopper's saved consent arrives. `useSeedAdoption` re-seeds a\n * clean checkbox with `defaultValue` on every render, but once it turns dirty no later seed ever\n * reaches it again: a shopper who toggles it before the real consent arrives locks that unchecked\n * seed in for good, and even a shopper who does not toggle it sees the checkbox flash to the saved\n * value. `useReactiveDataSettled` supplies\n * the missing half: the page query's own in-flight state, latched so it only ever goes pending →\n * settled. The `$data === undefined` half still carries trees with no reactive root above them, where\n * the slice arrives as a plain prop.\n *\n * Both ends of that wait are spoken: the fieldset carries `aria-busy` while it lasts and holds a polite\n * live region that announces `loadingLabel` and then `loadedLabel`. Style the region `sr-only` — it is\n * text meant for a screen reader, not for the page.\n */\nexport function ClientPreferencesFieldset({\n skeletonCount = CLIENT_PREFERENCES_SKELETON_ROWS,\n loadingLabel = 'Loading your preferences',\n loadedLabel = 'Your preferences are ready',\n groupLabel = 'Your preferences',\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ClientPreferencesFieldsetProps) {\n // Nesting fieldsets has no legitimate use: useFieldsetField resolves the *nearest*\n // FieldsetFieldContext, not the one owning a control's actual namespace, so a control nested two\n // fieldsets deep would silently register under the wrong one and its write would be discarded on\n // submit. Runtime registry integrity, mirroring the namespace-collision throw FormRoot already ships\n // (form.tsx:280-288).\n useNoAncestorFieldset('ClientPreferencesFieldset');\n\n const $data = useDataOverride($dataProp);\n\n const $actions = useActionsOverride($actionsProp);\n // Three conditions, not two. `useReactiveDataSettled` latches one way and never re-arms, so on its\n // own it answers \"has this page ever resolved\", not \"is what I am holding right now the server's\n // answer\" — after the page query's entity ref moves to one this cache never stored, or its root is\n // skipped for want of a variable, the slice silently regresses to `fallbackData` while the latch\n // still reads settled. `useEntityDataResolved` is the per-entity half: unlatched, so it follows the\n // slice back down and returns this fieldset to its skeleton instead of leaving live controls seeded\n // from a placeholder.\n const settled = useReactiveDataSettled();\n const sliceResolved = useEntityDataResolved();\n const resolved = settled && sliceResolved && $data !== undefined;\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n // Runs before useFormContext() below: useFormRegistry() throws the friendly \"Form parts must be used\n // inside FormRoot.\" error when no FormRoot is above, so a FormRoot-less render fails there rather than\n // reaching the getFieldState destructure, which throws an unhelpful TypeError instead (useFormContext()\n // resolves to null outside a FormRoot, and destructuring null throws).\n const { registerFieldset } = useFormRegistry();\n\n // Decision 3, as later narrowed: this fieldset still reads dirtiness imperatively, but the rule is no\n // longer the form's. `FormRoot` subscribes `dirtyFields` in render and decides which fieldsets to\n // dispatch from it, by the fields each one has mounted, on react-hook-form's documented contract.\n //\n // The imperative read survives here because it asks a different question in a different place: which\n // of *this* fieldset's own fields changed, resolved inside `toPayload` at submit time, by full\n // registered field name — the shape `getFieldState` documents. `useFormContext()` adds no\n // `formState` subscription of its own; one is created only when a caller reads a formState key off\n // the `useForm`/`useFormState` proxy (or hands that already-subscribed object to `getFieldState`'s\n // second argument). Calling `getFieldState(name)` with no second argument reads the current internal\n // state directly, so this fieldset root still does not re-render on a keystroke.\n const { getFieldState } = useFormContext();\n\n const latest = useRef({ $actions, readOnly, getFieldState });\n useEffect(() => {\n latest.current = { $actions, readOnly, getFieldState };\n }, [$actions, readOnly, getFieldState]);\n\n const { registry: fieldsetRegistry, getFieldNames } = useFieldsetFieldNames('clientPreferences');\n\n const dispatch = useCallback(async (payload: Record<string, unknown>) => {\n // Defence-in-depth: the UI disables every input while read-only, but `FormClear` sets values (and\n // marks them dirty) on every registered field regardless of that disabled attribute — react-hook-\n // form's own `useController` calls never receive a `disabled` registration option, so it has no\n // notion of \"disabled\" of its own. Guarding here keeps the write from reaching the network even if\n // some other composition dirties this fieldset while canEditData is false (the server also refuses,\n // but a client-side guard should not depend on that).\n if (latest.current.readOnly) {\n throw new Error('ClientPreferencesFieldset cannot dispatch while the session is read-only.');\n }\n const update = latest.current.$actions?.identity?.clientPreferencesUpdate;\n // Throwing is the contract's failure path: FormRoot catches it and records this fieldset's failure\n // (form.tsx:264-266). Returning [] would report an unqualified success for a write that never\n // happened.\n if (!update) throw new Error('ClientPreferencesFieldset requires $actions.identity.clientPreferencesUpdate.');\n return update(payload as ClientPreferencesUpdateInput);\n }, []);\n\n const toPayload = useCallback((values: Record<string, unknown>): Record<string, unknown> => {\n const { getFieldState } = latest.current;\n // FR-6: a flag is emitted only when the shopper actually toggled it. `getFieldState` is called\n // with no second argument, which reads react-hook-form's current internal state without\n // subscribing to it (Decision 3).\n const isDirty = (key: ClientPreferenceKey) => getFieldState(`clientPreferences.${key}`).isDirty;\n // Boolean() coercion is defence in depth: the bound checkbox part itself now writes its own\n // field's typed empty value on Clear (false, not ''), but this fieldset should not depend on\n // every caller writing a well-typed value.\n const payload: Record<string, boolean> = {};\n if ('optinNewsLetter' in values && isDirty('optinNewsLetter')) {\n payload.optinNewsLetter = Boolean(values.optinNewsLetter);\n }\n if ('savePersonalData' in values && isDirty('savePersonalData')) {\n payload.savePersonalData = Boolean(values.savePersonalData);\n }\n return payload;\n }, []);\n\n useEffect(\n () =>\n registerFieldset({\n namespace: 'clientPreferences',\n getFieldNames,\n dispatch,\n toPayload,\n // Decision 1: the register is a machine identifier, the kebab-case ASCII rendering of this\n // registration's own `namespace` (`clientPreferences` → `client-preferences`) — not authored\n // per page (Decision 2).\n label: 'client-preferences',\n }),\n [registerFieldset, getFieldNames, dispatch, toPayload],\n );\n\n const saved = useMemo<Readonly<Record<ClientPreferenceKey, boolean>>>(\n () => ({\n optinNewsLetter: Boolean($data?.optinNewsLetter ?? false),\n savePersonalData: Boolean($data?.savePersonalData ?? false),\n }),\n [$data],\n );\n\n const contextValue = useMemo<ClientPreferencesFieldsetContextValue>(\n () => ({ namespace: 'clientPreferences', saved, readOnly, rules: NO_RULES }),\n [saved, readOnly],\n );\n\n // Assistive technology only reports a change inside a region that was already in the tree, so a\n // region mounted together with its text announces nothing. The region therefore sits in both\n // branches and starts empty, with the wait written on the pass after mount and replaced — not\n // cleared — once the controls are up: the skeleton is `aria-hidden`, so without this second\n // message the form would materialise in silence (WCAG 2.1 SC 4.1.3).\n const [announcement, setAnnouncement] = useState('');\n const announced = resolved ? loadedLabel : loadingLabel;\n useEffect(() => {\n setAnnouncement(announced);\n }, [announced]);\n\n return (\n <Fieldset.Root\n className={className}\n disabled={readOnly}\n aria-busy={resolved ? undefined : true}\n // FR-12: blank (or whitespace-only) means no name is exposed, mirroring the loadingLabel/\n // loadedLabel convention. On the root itself (FR-13), so it is identical whether the fieldset\n // is pending or resolved; a page-composed FieldsetLegend still wins via aria-labelledby.\n {...(groupLabel?.trim() ? { 'aria-label': groupLabel } : {})}\n data-fs-client-preferences-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-client-preferences-fieldset-pending': '' })}\n {...(readOnly ? { 'data-fs-client-preferences-fieldset-readonly': '' } : {})}\n >\n {resolved ? (\n <FieldsetFieldContext.Provider value={fieldsetRegistry}>\n <ClientPreferencesFieldsetContext.Provider value={contextValue}>\n {children}\n </ClientPreferencesFieldsetContext.Provider>\n </FieldsetFieldContext.Provider>\n ) : (\n <ClientPreferencesFieldsetSkeleton count={skeletonCount} />\n )}\n <output aria-live=\"polite\" data-fs-client-preferences-fieldset-announcement=\"\">\n {announcement}\n </output>\n </Fieldset.Root>\n );\n}\n\n/**\n * The loading state of the fieldset, rendered in place of the controls until the entity resolves and\n * declared as the definition's `skeleton`. Purely visual: the wait is spoken by the fieldset's own live\n * region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ClientPreferencesFieldsetSkeleton({\n count = CLIENT_PREFERENCES_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-client-preferences-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-client-preferences-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nClientPreferencesFieldset.Skeleton = ClientPreferencesFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Controls\n// ---------------------------------------------------------------------------\n\nfunction PreferenceControl({\n fieldKey,\n attr,\n defaultLabel,\n label,\n className,\n children,\n}: {\n fieldKey: ClientPreferenceKey;\n attr: string;\n defaultLabel: string;\n label?: string;\n className?: string;\n children?: ReactNode;\n}) {\n const { namespace, saved, readOnly, rules } = useClientPreferencesFieldsetContext();\n const name = useFieldsetField(namespace, fieldKey);\n const resolvedLabel = label ?? defaultLabel;\n\n return (\n <FieldBinding\n name={name}\n label={resolvedLabel}\n defaultValue={saved[fieldKey]}\n rule={rules[fieldKey]}\n disabled={readOnly}\n >\n <Field.Root className={className} data-fs-client-preferences-fieldset-field={attr}>\n {children ?? (\n <Field.Label>\n <Field.Checkbox>\n <Checkbox.Indicator>\n <Icon name=\"checked\" />\n </Checkbox.Indicator>\n </Field.Checkbox>\n {resolvedLabel}\n </Field.Label>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\nexport function ClientPreferencesNewsletterControl({\n label,\n className,\n children,\n}: ClientPreferencesNewsletterControlProps) {\n return (\n <PreferenceControl\n fieldKey=\"optinNewsLetter\"\n attr=\"newsletter\"\n defaultLabel=\"Email me with news and offers\"\n label={label}\n className={className}\n >\n {children}\n </PreferenceControl>\n );\n}\n\nexport function ClientPreferencesSavePersonalDataControl({\n label,\n className,\n children,\n}: ClientPreferencesSavePersonalDataControlProps) {\n return (\n <PreferenceControl\n fieldKey=\"savePersonalData\"\n attr=\"save-personal-data\"\n defaultLabel=\"Save my information for next time\"\n label={label}\n className={className}\n >\n {children}\n </PreferenceControl>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-preferences-fieldset.js","names":[],"sources":["../../../src/matter/client-preferences/client-preferences-fieldset.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ContentTypeDefinition,\n type ContentValue,\n defineComponent,\n defineContentType,\n type MessageFieldName,\n type MessageLocaleProp,\n} from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport { Checkbox } from '../../particles/checkbox/checkbox.js';\nimport type { FieldRule } from '../../particles/field/field.js';\nimport {\n Field,\n FieldBinding,\n FieldsetFieldContext,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { type FormUserError, useFormRegistry } from '../../particles/form/form.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { 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 { useEntityDataResolved } from '../../sdk/data/entity-resolution-context.js';\nimport { useReactiveDataSettled } from '../../sdk/data/use-reactive-data-settled.js';\nimport { formatErrorCode } from '../../sdk/i18n/format-error-code.js';\nimport type { MessageFormatter } from '../../sdk/i18n/message-formatter.js';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\nimport type {\n ClientPreferenceKey,\n ClientPreferencesUpdateInput,\n ClientProfileUserError,\n} from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * `ClientPreferencesFieldset` — the composable, one-Save write of the `ClientPreferences` sibling\n * entity (RFC: Composable Entity Forms, `Proposal > Design > The fieldset`). It registers itself with\n * the enclosing `FormRoot` under the `clientPreferences` namespace and dispatches\n * `$actions.identity.clientPreferencesUpdate` for its own submit slot; it renders no `<form>` of its\n * own.\n *\n * `ClientPreferencesRoot` (`client-preferences.tsx`) already reads both flags and writes on toggle; this\n * fieldset is a second, batched write timing for the same two flags. To keep the two from compiling into\n * each other's container, the shipped self-persisting matter's context is renamed to\n * `client-preferences-toggle`, freeing `client-preferences` for this fieldset. Placing\n * `NewsletterOptInControl` inside this fieldset, or `ClientPreferencesNewsletterControl` inside\n * `ClientPreferencesRoot`, is therefore a build failure rather than a surprise write.\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated on the fieldset, its own data root\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientPreferencesFieldsetData on Query {\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Content model\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferencesFieldsetContent = defineContentType({\n id: 'client-preferences-fieldset',\n title: 'Client Preferences Fieldset',\n description: \"The preferences fieldset's loading and loaded announcements and its accessible group name.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n loadingLabel: {\n type: 'string',\n title: 'Loading announcement',\n format: 'icu-message',\n messageSource: 'Loading your preferences',\n },\n loadedLabel: {\n type: 'string',\n title: 'Loaded announcement',\n format: 'icu-message',\n messageSource: 'Your preferences are ready',\n },\n groupLabel: {\n type: 'string',\n title: 'Accessible group name',\n format: 'icu-message',\n messageSource: 'Your preferences',\n messageOptional: true,\n },\n genericErrorMessage: {\n type: 'string',\n title: 'Generic error message',\n description: 'Shown by FormError when the preferences could not be saved.',\n format: 'icu-message',\n messageSource: 'Unable to save your preferences. Please try again.',\n },\n },\n },\n});\n\ntype ClientPreferencesUpdateErrorCode = 'MISSING_CART_CONTEXT' | 'CART_NOT_FOUND' | 'NO_PREFERENCE_PROVIDED';\n\n/**\n * The message for each refusal of the preferences write: every `ClientPreferencesUpdateErrorCode` plus\n * the client-minted transport failure. None is a fault the shopper can fix, so all share one message.\n * `dispatch` hands `FormError` this copy, and genericErrorMessage for an unknown code.\n */\nexport const CLIENT_PREFERENCES_FIELDSET_ERROR_FIELDS = {\n MISSING_CART_CONTEXT: 'genericErrorMessage',\n CART_NOT_FOUND: 'genericErrorMessage',\n NO_PREFERENCE_PROVIDED: 'genericErrorMessage',\n NETWORK_ERROR: 'genericErrorMessage',\n} as const satisfies Record<\n ClientPreferencesUpdateErrorCode | 'NETWORK_ERROR',\n MessageFieldName<typeof ClientPreferencesFieldsetContent>\n>;\n\nfunction wordClientPreferencesError(\n error: ClientProfileUserError,\n { format }: MessageFormatter<typeof ClientPreferencesFieldsetContent>,\n): FormUserError {\n return {\n code: error.code,\n message: formatErrorCode(\n ClientPreferencesFieldsetContent,\n CLIENT_PREFERENCES_FIELDSET_ERROR_FIELDS,\n error,\n format,\n 'genericErrorMessage',\n ),\n };\n}\n\nexport const ClientPreferencesNewsletterControlContent = defineContentType({\n id: 'client-preferences-newsletter',\n title: 'Client Preferences Newsletter Control',\n description: \"The newsletter opt-in's label.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label', format: 'icu-message', messageSource: 'Email me with news and offers' },\n },\n },\n});\n\nexport const ClientPreferencesSavePersonalDataControlContent = defineContentType({\n id: 'client-preferences-save-data',\n title: 'Client Preferences Save Personal Data Control',\n description: \"The save-personal-data opt-in's label.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: {\n type: 'string',\n title: 'Label',\n format: 'icu-message',\n messageSource: 'Save my information for next time',\n },\n },\n },\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the ClientPreferences sibling entity, unwrapped. */\nexport type ClientPreferencesFieldsetData = {\n optinNewsLetter?: boolean | null;\n savePersonalData?: boolean | null;\n} | null;\n\n/** What the fieldset publishes to its controls. Carries no live value — react-hook-form owns those. */\ntype ClientPreferencesFieldsetContextValue = Readonly<{\n namespace: 'clientPreferences';\n /** Seeds, resolved from `$data`. `null` (not chosen yet) reads as unchecked, per the opt-in default. */\n saved: Readonly<Record<ClientPreferenceKey, boolean>>;\n /** True when the session reports `canEditData: false`. */\n readOnly: boolean;\n /** The fieldset's own validation rules, per key. Present and empty today (Decision 6). */\n rules: Readonly<Partial<Record<ClientPreferenceKey, FieldRule>>>;\n}>;\n\n/** No control publishes a rule today (Decision 6) — kept as a stable empty object so the context\n * value's identity does not churn on every render. */\nconst NO_RULES: Readonly<Partial<Record<ClientPreferenceKey, FieldRule>>> = {};\n\n/**\n * Rows `ClientPreferencesFieldsetSkeleton` draws when nobody says otherwise: one per consent flag in\n * the full anatomy. It is a default and not a derivation, because the composed children are opaque\n * here. A page that composes only one control sets `skeletonCount` to 1, or the form jumps by a row\n * when the controls take the skeleton's place.\n */\nconst CLIENT_PREFERENCES_SKELETON_ROWS = 2;\n\nconst CLIENT_PREFERENCES_FIELDSET_UNSET = Symbol('ClientPreferencesFieldsetContextUnset');\n\nconst ClientPreferencesFieldsetContext = createContext<\n ClientPreferencesFieldsetContextValue | typeof CLIENT_PREFERENCES_FIELDSET_UNSET\n>(CLIENT_PREFERENCES_FIELDSET_UNSET);\n\nfunction useClientPreferencesFieldsetContext(): ClientPreferencesFieldsetContextValue {\n const ctx = useContext(ClientPreferencesFieldsetContext);\n if (ctx === CLIENT_PREFERENCES_FIELDSET_UNSET) {\n throw new Error('ClientPreferencesFieldset controls must be used inside ClientPreferencesFieldset.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport type ClientPreferencesFieldsetProps = MessageLocaleProp & {\n /** Placeholder rows the loading skeleton draws. Set it to the number of controls composed here. */\n skeletonCount?: number;\n /** The loading and loaded announcements and the accessible group name. */\n $content?: ContentValue<typeof ClientPreferencesFieldsetContent>;\n className?: string;\n children?: ReactNode;\n /** `ClientPreferencesFieldsetData` slice forwarded by the reactive runtime. */\n $data?: ClientPreferencesFieldsetData;\n /** Compiler-injected; carries `identity.clientPreferencesUpdate`. */\n $actions?: ComponentActions;\n};\n\ntype PreferenceControlProps<T extends ContentTypeDefinition> = MessageLocaleProp & {\n /** The control's label. */\n $content?: ContentValue<T>;\n className?: string;\n children?: ReactNode;\n};\n\nexport type ClientPreferencesNewsletterControlProps = PreferenceControlProps<\n typeof ClientPreferencesNewsletterControlContent\n>;\nexport type ClientPreferencesSavePersonalDataControlProps = PreferenceControlProps<\n typeof ClientPreferencesSavePersonalDataControlContent\n>;\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferencesFieldsetDefinition = defineComponent<ClientPreferencesFieldsetProps>({\n name: 'ClientPreferencesFieldset',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesFieldset,\n content: ClientPreferencesFieldsetContent,\n fragment,\n fetchStrategy: 'reactive',\n skeleton: ClientPreferencesFieldsetSkeleton,\n requiresContext: ['form', 'session'],\n providesContext: 'client-preferences',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Client Preferences Fieldset', category: 'identity' },\n schema: {\n skeletonCount: { type: 'number', default: 2, label: 'Skeleton rows' },\n },\n guideline:\n \"Registers a batched write of the ClientPreferences entity with the enclosing FormRoot; renders one Fieldset.Root and no <form>. Distinct from ClientPreferencesRoot (matter/client-preferences), which writes on toggle and requires client-preferences-toggle — the two cannot compile into each other's container. Must be inside a FormRoot with a SessionRoot ancestor. Compose ClientPreferencesNewsletterControl and/or ClientPreferencesSavePersonalDataControl as children. The controls mount only once the preferences have resolved, with skeletonCount placeholder rows in their place until then — set it to the number of controls composed, or the form jumps by the difference. Style the announcement sr-only; it reads the $content fields loadingLabel and loadedLabel. Dispatches only the flags the shopper changed. The $content field groupLabel names the group as its accessible name; an unauthored one emits no aria-label, and a composed FieldsetLegend wins over it.\",\n});\n\nexport const ClientPreferencesNewsletterControlDefinition = defineComponent<ClientPreferencesNewsletterControlProps>({\n name: 'ClientPreferencesNewsletterControl',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesNewsletterControl,\n content: ClientPreferencesNewsletterControlContent,\n requiresContext: 'client-preferences',\n providesContext: 'field',\n editor: { label: 'Client Preferences Newsletter Control', category: 'identity' },\n schema: {},\n guideline:\n \"The bound newsletter opt-in control, labelled by the $content field label; must be a descendant of ClientPreferencesFieldset. Renders Field.Root > Field.Label > Field.Checkbox by default, or the composed children in the author's own order. Defaults to unchecked.\",\n});\n\nexport const ClientPreferencesSavePersonalDataControlDefinition =\n defineComponent<ClientPreferencesSavePersonalDataControlProps>({\n name: 'ClientPreferencesSavePersonalDataControl',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesSavePersonalDataControl,\n content: ClientPreferencesSavePersonalDataControlContent,\n requiresContext: 'client-preferences',\n providesContext: 'field',\n editor: { label: 'Client Preferences Save Personal Data Control', category: 'identity' },\n schema: {},\n guideline:\n \"The bound save-personal-data opt-in control, labelled by the $content field label; must be a descendant of ClientPreferencesFieldset. Renders Field.Root > Field.Label > Field.Checkbox by default, or the composed children in the author's own order. Defaults to unchecked.\",\n });\n\n// ---------------------------------------------------------------------------\n// Fieldset root\n// ---------------------------------------------------------------------------\n\n/**\n * Registers a batched write of the `ClientPreferences` entity with the enclosing `FormRoot`\n * (`registerFieldset`, namespace `clientPreferences`) on mount, unconditionally — so this fieldset keeps\n * its original dispatch slot even while its own query is still resolving. Its children — the seed values\n * and the field-name registry its controls need — render only once the entity has resolved; until then\n * the `Fieldset.Root` carries `-pending` and renders `ClientPreferencesFieldsetSkeleton` (Decision 5).\n * `dispatch` and `toPayload` are `useCallback([])`-stable and read `$actions` through a ref, so the\n * registration effect runs exactly once per mount regardless of how often the parent re-renders.\n *\n * \"Resolved\" is two conditions, because `$data` alone cannot answer it. Under the reactive runtime the\n * slice is defined from the first render — `useReactiveEntity` hands down `fallbackData` while the cache\n * read is incomplete — so an empty server answer looks exactly like a resolved one, and the checkboxes\n * would mount seeded unchecked before the shopper's saved consent arrives. `useSeedAdoption` re-seeds a\n * clean checkbox with `defaultValue` on every render, but once it turns dirty no later seed ever\n * reaches it again: a shopper who toggles it before the real consent arrives locks that unchecked\n * seed in for good, and even a shopper who does not toggle it sees the checkbox flash to the saved\n * value. `useReactiveDataSettled` supplies\n * the missing half: the page query's own in-flight state, latched so it only ever goes pending →\n * settled. The `$data === undefined` half still carries trees with no reactive root above them, where\n * the slice arrives as a plain prop.\n *\n * Both ends of that wait are spoken: the fieldset carries `aria-busy` while it lasts and holds a polite\n * live region that announces the `loadingLabel` and then the `loadedLabel` message. Style the region `sr-only` — it is\n * text meant for a screen reader, not for the page.\n */\nexport function ClientPreferencesFieldset({\n skeletonCount = CLIENT_PREFERENCES_SKELETON_ROWS,\n $content,\n $locale,\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ClientPreferencesFieldsetProps) {\n // Nesting fieldsets has no legitimate use: useFieldsetField resolves the *nearest*\n // FieldsetFieldContext, not the one owning a control's actual namespace, so a control nested two\n // fieldsets deep would silently register under the wrong one and its write would be discarded on\n // submit. Runtime registry integrity, mirroring the namespace-collision throw FormRoot already ships\n // (form.tsx:280-288).\n useNoAncestorFieldset('ClientPreferencesFieldset');\n\n const $data = useDataOverride($dataProp);\n\n const $actions = useActionsOverride($actionsProp);\n const messages = useMessageFormatter(ClientPreferencesFieldsetContent, $content);\n const { format } = messages;\n const groupLabel = format('groupLabel');\n // Three conditions, not two. `useReactiveDataSettled` latches one way and never re-arms, so on its\n // own it answers \"has this page ever resolved\", not \"is what I am holding right now the server's\n // answer\" — after the page query's entity ref moves to one this cache never stored, or its root is\n // skipped for want of a variable, the slice silently regresses to `fallbackData` while the latch\n // still reads settled. `useEntityDataResolved` is the per-entity half: unlatched, so it follows the\n // slice back down and returns this fieldset to its skeleton instead of leaving live controls seeded\n // from a placeholder.\n const settled = useReactiveDataSettled();\n const sliceResolved = useEntityDataResolved();\n const resolved = settled && sliceResolved && $data !== undefined;\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n // Runs before useFormContext() below: useFormRegistry() throws the friendly \"Form parts must be used\n // inside FormRoot.\" error when no FormRoot is above, so a FormRoot-less render fails there rather than\n // reaching the getFieldState destructure, which throws an unhelpful TypeError instead (useFormContext()\n // resolves to null outside a FormRoot, and destructuring null throws).\n const { registerFieldset } = useFormRegistry();\n\n // Decision 3, as later narrowed: this fieldset still reads dirtiness imperatively, but the rule is no\n // longer the form's. `FormRoot` subscribes `dirtyFields` in render and decides which fieldsets to\n // dispatch from it, by the fields each one has mounted, on react-hook-form's documented contract.\n //\n // The imperative read survives here because it asks a different question in a different place: which\n // of *this* fieldset's own fields changed, resolved inside `toPayload` at submit time, by full\n // registered field name — the shape `getFieldState` documents. `useFormContext()` adds no\n // `formState` subscription of its own; one is created only when a caller reads a formState key off\n // the `useForm`/`useFormState` proxy (or hands that already-subscribed object to `getFieldState`'s\n // second argument). Calling `getFieldState(name)` with no second argument reads the current internal\n // state directly, so this fieldset root still does not re-render on a keystroke.\n const { getFieldState } = useFormContext();\n\n const latest = useRef({ $actions, readOnly, getFieldState, messages });\n useEffect(() => {\n latest.current = { $actions, readOnly, getFieldState, messages };\n }, [$actions, readOnly, getFieldState, messages]);\n\n const { registry: fieldsetRegistry, getFieldNames } = useFieldsetFieldNames('clientPreferences');\n\n const dispatch = useCallback(async (payload: Record<string, unknown>) => {\n // Defence-in-depth: the UI disables every input while read-only, but `FormClear` sets values (and\n // marks them dirty) on every registered field regardless of that disabled attribute — react-hook-\n // form's own `useController` calls never receive a `disabled` registration option, so it has no\n // notion of \"disabled\" of its own. Guarding here keeps the write from reaching the network even if\n // some other composition dirties this fieldset while canEditData is false (the server also refuses,\n // but a client-side guard should not depend on that).\n if (latest.current.readOnly) {\n throw new Error('ClientPreferencesFieldset cannot dispatch while the session is read-only.');\n }\n const update = latest.current.$actions?.identity?.clientPreferencesUpdate;\n // Throwing is the contract's failure path: FormRoot catches it and records this fieldset's failure\n // (form.tsx:264-266). Returning [] would report an unqualified success for a write that never\n // happened.\n if (!update) throw new Error('ClientPreferencesFieldset requires $actions.identity.clientPreferencesUpdate.');\n const userErrors = await update(payload as ClientPreferencesUpdateInput);\n return userErrors.map((error) => wordClientPreferencesError(error, latest.current.messages));\n }, []);\n\n const toPayload = useCallback((values: Record<string, unknown>): Record<string, unknown> => {\n const { getFieldState } = latest.current;\n // FR-6: a flag is emitted only when the shopper actually toggled it. `getFieldState` is called\n // with no second argument, which reads react-hook-form's current internal state without\n // subscribing to it (Decision 3).\n const isDirty = (key: ClientPreferenceKey) => getFieldState(`clientPreferences.${key}`).isDirty;\n // Boolean() coercion is defence in depth: the bound checkbox part itself now writes its own\n // field's typed empty value on Clear (false, not ''), but this fieldset should not depend on\n // every caller writing a well-typed value.\n const payload: Record<string, boolean> = {};\n if ('optinNewsLetter' in values && isDirty('optinNewsLetter')) {\n payload.optinNewsLetter = Boolean(values.optinNewsLetter);\n }\n if ('savePersonalData' in values && isDirty('savePersonalData')) {\n payload.savePersonalData = Boolean(values.savePersonalData);\n }\n return payload;\n }, []);\n\n useEffect(\n () =>\n registerFieldset({\n namespace: 'clientPreferences',\n getFieldNames,\n dispatch,\n toPayload,\n // Decision 1: the register is a machine identifier, the kebab-case ASCII rendering of this\n // registration's own `namespace` (`clientPreferences` → `client-preferences`) — not authored\n // per page (Decision 2).\n label: 'client-preferences',\n }),\n [registerFieldset, getFieldNames, dispatch, toPayload],\n );\n\n const saved = useMemo<Readonly<Record<ClientPreferenceKey, boolean>>>(\n () => ({\n optinNewsLetter: Boolean($data?.optinNewsLetter ?? false),\n savePersonalData: Boolean($data?.savePersonalData ?? false),\n }),\n [$data],\n );\n\n const contextValue = useMemo<ClientPreferencesFieldsetContextValue>(\n () => ({ namespace: 'clientPreferences', saved, readOnly, rules: NO_RULES }),\n [saved, readOnly],\n );\n\n // Assistive technology only reports a change inside a region that was already in the tree, so a\n // region mounted together with its text announces nothing. The region therefore sits in both\n // branches and starts empty, with the wait written on the pass after mount and replaced — not\n // cleared — once the controls are up: the skeleton is `aria-hidden`, so without this second\n // message the form would materialise in silence (WCAG 2.1 SC 4.1.3).\n const [announcement, setAnnouncement] = useState('');\n const announced = format(resolved ? 'loadedLabel' : 'loadingLabel');\n useEffect(() => {\n setAnnouncement(announced);\n }, [announced]);\n\n return (\n <Fieldset.Root\n className={className}\n disabled={readOnly}\n aria-busy={resolved ? undefined : true}\n // FR-12: a missing message means no name is exposed. On the root itself (FR-13), so it is identical whether the fieldset\n // is pending or resolved; a page-composed FieldsetLegend still wins via aria-labelledby.\n {...(groupLabel.trim() ? { 'aria-label': groupLabel } : {})}\n data-fs-client-preferences-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-client-preferences-fieldset-pending': '' })}\n {...(readOnly ? { 'data-fs-client-preferences-fieldset-readonly': '' } : {})}\n >\n {resolved ? (\n <FieldsetFieldContext.Provider value={fieldsetRegistry}>\n <ClientPreferencesFieldsetContext.Provider value={contextValue}>\n {children}\n </ClientPreferencesFieldsetContext.Provider>\n </FieldsetFieldContext.Provider>\n ) : (\n <ClientPreferencesFieldsetSkeleton count={skeletonCount} />\n )}\n <output aria-live=\"polite\" data-fs-client-preferences-fieldset-announcement=\"\">\n {announcement}\n </output>\n </Fieldset.Root>\n );\n}\n\n/**\n * The loading state of the fieldset, rendered in place of the controls until the entity resolves and\n * declared as the definition's `skeleton`. Purely visual: the wait is spoken by the fieldset's own live\n * region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ClientPreferencesFieldsetSkeleton({\n count = CLIENT_PREFERENCES_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-client-preferences-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-client-preferences-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nClientPreferencesFieldset.Skeleton = ClientPreferencesFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Controls\n// ---------------------------------------------------------------------------\n\nfunction PreferenceControl({\n fieldKey,\n attr,\n label,\n className,\n children,\n}: Readonly<{\n fieldKey: ClientPreferenceKey;\n attr: string;\n /** Formatted by the owning control. */\n label: string;\n className?: string;\n children?: ReactNode;\n}>) {\n const { namespace, saved, readOnly, rules } = useClientPreferencesFieldsetContext();\n const name = useFieldsetField(namespace, fieldKey);\n\n return (\n <FieldBinding name={name} label={label} defaultValue={saved[fieldKey]} rule={rules[fieldKey]} disabled={readOnly}>\n <Field.Root className={className} data-fs-client-preferences-fieldset-field={attr}>\n {children ?? (\n <Field.Label>\n <Field.Checkbox>\n <Checkbox.Indicator>\n <Icon name=\"checked\" />\n </Checkbox.Indicator>\n </Field.Checkbox>\n {label}\n </Field.Label>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\nexport function ClientPreferencesNewsletterControl({\n $content,\n $locale,\n className,\n children,\n}: ClientPreferencesNewsletterControlProps) {\n const { format } = useMessageFormatter(ClientPreferencesNewsletterControlContent, $content);\n return (\n <PreferenceControl fieldKey=\"optinNewsLetter\" attr=\"newsletter\" label={format('label')} className={className}>\n {children}\n </PreferenceControl>\n );\n}\n\nexport function ClientPreferencesSavePersonalDataControl({\n $content,\n $locale,\n className,\n children,\n}: ClientPreferencesSavePersonalDataControlProps) {\n const { format } = useMessageFormatter(ClientPreferencesSavePersonalDataControlContent, $content);\n return (\n <PreferenceControl\n fieldKey=\"savePersonalData\"\n attr=\"save-personal-data\"\n label={format('label')}\n className={className}\n >\n {children}\n </PreferenceControl>\n );\n}\n"],"mappings":"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"}
@@ -1,8 +1,45 @@
1
+ import { ContentValue, MessageLocaleProp } from "../../core/dist/define-content-type.js";
1
2
  import { ComponentDefinition } from "../../core/dist/define-component.js";
2
3
  import "../../core/dist/index.js";
3
4
  import { ComponentActions } from "../../sdk/actions/types.js";
4
5
  import { ReactNode } from "react";
5
6
  //#region src/matter/client-preferences/client-preferences.d.ts
7
+ export declare const NewsletterOptInControlContent: {
8
+ readonly id: "newsletter-opt-in-control";
9
+ readonly title: "Newsletter Opt-In Control";
10
+ readonly description: "The inline message shown when saving the newsletter opt-in fails.";
11
+ readonly schema: {
12
+ readonly type: "object";
13
+ readonly additionalProperties: false;
14
+ readonly properties: {
15
+ readonly genericErrorMessage: {
16
+ readonly type: "string";
17
+ readonly title: "Save failure message";
18
+ readonly description: "Shown for a network failure and for any refusal the shopper cannot act on.";
19
+ readonly format: "icu-message";
20
+ readonly messageSource: "Unable to save your preference. Please try again.";
21
+ };
22
+ };
23
+ };
24
+ };
25
+ export declare const SavePersonalDataOptInControlContent: {
26
+ readonly id: "save-personal-data-opt-in-control";
27
+ readonly title: "Save Personal Data Opt-In Control";
28
+ readonly description: "The inline message shown when saving the save-personal-data opt-in fails.";
29
+ readonly schema: {
30
+ readonly type: "object";
31
+ readonly additionalProperties: false;
32
+ readonly properties: {
33
+ readonly genericErrorMessage: {
34
+ readonly type: "string";
35
+ readonly title: "Save failure message";
36
+ readonly description: "Shown for a network failure and for any refusal the shopper cannot act on.";
37
+ readonly format: "icu-message";
38
+ readonly messageSource: "Unable to save your preference. Please try again.";
39
+ };
40
+ };
41
+ };
42
+ };
6
43
  /** The `$data` slice forwarded by the reactive runtime — the `ClientPreferences` sibling entity, unwrapped. */
7
44
  export type ClientPreferencesData = {
8
45
  optinNewsLetter?: boolean | null;
@@ -14,17 +51,23 @@ export type ClientPreferencesRootProps = {
14
51
  className?: string;
15
52
  children?: ReactNode;
16
53
  };
17
- export type ClientPreferencesControlProps = {
54
+ export type ClientPreferencesControlProps = MessageLocaleProp & {
18
55
  label: string;
19
56
  className?: string;
20
57
  /** Injected by the compiler from `actions: { identity: ['clientPreferencesUpdate'] }`; the write surface. */
21
58
  $actions?: ComponentActions;
22
59
  };
23
- export type NewsletterOptInControlProps = ClientPreferencesControlProps;
24
- export type SavePersonalDataOptInControlProps = ClientPreferencesControlProps;
60
+ export type NewsletterOptInControlProps = ClientPreferencesControlProps & {
61
+ /** The inline message for a refused save. */
62
+ $content?: ContentValue<typeof NewsletterOptInControlContent>;
63
+ };
64
+ export type SavePersonalDataOptInControlProps = ClientPreferencesControlProps & {
65
+ /** The inline message for a refused save. */
66
+ $content?: ContentValue<typeof SavePersonalDataOptInControlContent>;
67
+ };
25
68
  export declare const ClientPreferencesRootDefinition: ComponentDefinition<ClientPreferencesRootProps>;
26
- export declare const NewsletterOptInControlDefinition: ComponentDefinition<ClientPreferencesControlProps>;
27
- export declare const SavePersonalDataOptInControlDefinition: ComponentDefinition<ClientPreferencesControlProps>;
69
+ export declare const NewsletterOptInControlDefinition: ComponentDefinition<NewsletterOptInControlProps>;
70
+ export declare const SavePersonalDataOptInControlDefinition: ComponentDefinition<SavePersonalDataOptInControlProps>;
28
71
  /**
29
72
  * Renders the client-preferences section Root: reads `$data` (the `ClientPreferences` sibling entity),
30
73
  * reads `useSession()` (which also enforces the `SessionRoot` ancestor, mirroring
@@ -37,8 +80,8 @@ export declare const SavePersonalDataOptInControlDefinition: ComponentDefinition
37
80
  * `data-fs-*` attribute, mirroring `EmailIdentificationControl`.
38
81
  */
39
82
  export declare function ClientPreferencesRoot({ $data: $dataProp, className, children }: ClientPreferencesRootProps): import("react/jsx-runtime").JSX.Element;
40
- export declare function NewsletterOptInControl(props: NewsletterOptInControlProps): import("react/jsx-runtime").JSX.Element;
41
- export declare function SavePersonalDataOptInControl(props: SavePersonalDataOptInControlProps): import("react/jsx-runtime").JSX.Element;
83
+ export declare function NewsletterOptInControl({ $locale, ...props }: NewsletterOptInControlProps): import("react/jsx-runtime").JSX.Element;
84
+ export declare function SavePersonalDataOptInControl({ $locale, ...props }: SavePersonalDataOptInControlProps): import("react/jsx-runtime").JSX.Element;
42
85
  export declare const ClientPreferences: {
43
86
  Root: typeof ClientPreferencesRoot;
44
87
  NewsletterOptInControl: typeof NewsletterOptInControl;
@@ -1,19 +1,31 @@
1
1
  "use client";
2
2
  import { defineComponent } from "../../core/dist/define-component.js";
3
+ import { defineContentType } from "../../core/dist/define-content-type.js";
3
4
  import "../../core/dist/index.js";
5
+ import { useMessageFormatter } from "../../sdk/i18n/use-message-formatter.js";
4
6
  import { Checkbox } from "../../particles/checkbox/checkbox.js";
5
7
  import { Field } from "../../particles/field/field.js";
6
8
  import { useActionsOverride } from "../../sdk/actions/actions-override-context.js";
9
+ import { formatErrorCode } from "../../sdk/i18n/format-error-code.js";
7
10
  import { useDataOverride } from "../../sdk/data/data-override-context.js";
8
11
  import { useSession } from "../session/session.js";
9
12
  import { Icon } from "../../particles/icon/icon.js";
10
13
  import { createContext, useCallback, useContext, useMemo, useState } from "react";
11
14
  import { jsx, jsxs } from "react/jsx-runtime";
12
- const ClientPreferencesRootDefinition = defineComponent({
13
- name: "ClientPreferencesRoot",
14
- importPath: "@vtex/faststore/components",
15
- component: ClientPreferencesRoot,
16
- fragment: `
15
+ //#region src/matter/client-preferences/client-preferences.tsx
16
+ /**
17
+ * The `client-preferences` section matter (per ADR-0011: a matter is decomposed by DATA OWNERSHIP,
18
+ * not per field). Both opt-ins — newsletter (`optinNewsLetter`) and save-personal-data
19
+ * (`savePersonalData`) — are light booleans owned by the User Identity `ClientPreferences` entity
20
+ * (a SIBLING of `Cart`, not nested under it, per the identity RFC), so they live under ONE
21
+ * `ClientPreferencesRoot` that declares a single section fragment on `Query` selecting both fields.
22
+ * The two merchant-facing Controls consume that one section context (ADR-0011 governs data
23
+ * ownership, not the editor palette) and share one internal `OptInControl` implementation: the
24
+ * section context, the `$data` → values seeding, the per-field pending/error tracking, the inlined
25
+ * `Checkbox` + `Field` Control render, and dispatch via `$actions.identity.clientPreferencesUpdate`
26
+ * (mirrors the `email-identification` matter; reads/writes follow ADR-0006 / ADR-0010 / ADR-0011).
27
+ */
28
+ const fragment = `
17
29
  fragment ClientPreferencesData on Query {
18
30
  clientPreferences {
19
31
  __typename
@@ -22,7 +34,55 @@ const ClientPreferencesRootDefinition = defineComponent({
22
34
  savePersonalData
23
35
  }
24
36
  }
25
- `,
37
+ `;
38
+ const NewsletterOptInControlContent = defineContentType({
39
+ id: "newsletter-opt-in-control",
40
+ title: "Newsletter Opt-In Control",
41
+ description: "The inline message shown when saving the newsletter opt-in fails.",
42
+ schema: {
43
+ type: "object",
44
+ additionalProperties: false,
45
+ properties: { genericErrorMessage: {
46
+ type: "string",
47
+ title: "Save failure message",
48
+ description: "Shown for a network failure and for any refusal the shopper cannot act on.",
49
+ format: "icu-message",
50
+ messageSource: "Unable to save your preference. Please try again."
51
+ } }
52
+ }
53
+ });
54
+ const SavePersonalDataOptInControlContent = defineContentType({
55
+ id: "save-personal-data-opt-in-control",
56
+ title: "Save Personal Data Opt-In Control",
57
+ description: "The inline message shown when saving the save-personal-data opt-in fails.",
58
+ schema: {
59
+ type: "object",
60
+ additionalProperties: false,
61
+ properties: { genericErrorMessage: {
62
+ type: "string",
63
+ title: "Save failure message",
64
+ description: "Shown for a network failure and for any refusal the shopper cannot act on.",
65
+ format: "icu-message",
66
+ messageSource: "Unable to save your preference. Please try again."
67
+ } }
68
+ }
69
+ });
70
+ /**
71
+ * `ClientPreferencesUpdateErrorCode` of API Core's schema plus the client-minted transport failure. None
72
+ * is something the shopper can fix by toggling again, so all share the generic message.
73
+ */
74
+ const NEWSLETTER_OPT_IN_ERROR_FIELDS = {
75
+ MISSING_CART_CONTEXT: "genericErrorMessage",
76
+ CART_NOT_FOUND: "genericErrorMessage",
77
+ NO_PREFERENCE_PROVIDED: "genericErrorMessage",
78
+ NETWORK_ERROR: "genericErrorMessage"
79
+ };
80
+ const SAVE_PERSONAL_DATA_OPT_IN_ERROR_FIELDS = { ...NEWSLETTER_OPT_IN_ERROR_FIELDS };
81
+ const ClientPreferencesRootDefinition = defineComponent({
82
+ name: "ClientPreferencesRoot",
83
+ importPath: "@vtex/faststore/components",
84
+ component: ClientPreferencesRoot,
85
+ fragment,
26
86
  fetchStrategy: "reactive",
27
87
  providesContext: "client-preferences-toggle",
28
88
  requiresContext: "session",
@@ -37,6 +97,7 @@ const NewsletterOptInControlDefinition = defineComponent({
37
97
  name: "NewsletterOptInControl",
38
98
  importPath: "@vtex/faststore/components",
39
99
  component: NewsletterOptInControl,
100
+ content: NewsletterOptInControlContent,
40
101
  requiresContext: "client-preferences-toggle",
41
102
  actions: { identity: ["clientPreferencesUpdate"] },
42
103
  editor: {
@@ -47,12 +108,13 @@ const NewsletterOptInControlDefinition = defineComponent({
47
108
  type: "string",
48
109
  label: "Label"
49
110
  } },
50
- guideline: "The bound newsletter opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the optinNewsLetter preference via $actions.identity.clientPreferencesUpdate. Defaults to unchecked."
111
+ guideline: "The bound newsletter opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the optinNewsLetter preference via $actions.identity.clientPreferencesUpdate; a refused save shows the $content field genericErrorMessage. Defaults to unchecked."
51
112
  });
52
113
  const SavePersonalDataOptInControlDefinition = defineComponent({
53
114
  name: "SavePersonalDataOptInControl",
54
115
  importPath: "@vtex/faststore/components",
55
116
  component: SavePersonalDataOptInControl,
117
+ content: SavePersonalDataOptInControlContent,
56
118
  requiresContext: "client-preferences-toggle",
57
119
  actions: { identity: ["clientPreferencesUpdate"] },
58
120
  editor: {
@@ -63,7 +125,7 @@ const SavePersonalDataOptInControlDefinition = defineComponent({
63
125
  type: "string",
64
126
  label: "Label"
65
127
  } },
66
- guideline: "The bound save-personal-data opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the savePersonalData preference via $actions.identity.clientPreferencesUpdate. Defaults to unchecked."
128
+ guideline: "The bound save-personal-data opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the savePersonalData preference via $actions.identity.clientPreferencesUpdate; a refused save shows the $content field genericErrorMessage. Defaults to unchecked."
67
129
  });
68
130
  const CLIENT_PREFERENCES_UNSET = Symbol("ClientPreferencesContextUnset");
69
131
  const ClientPreferencesContext = createContext(CLIENT_PREFERENCES_UNSET);
@@ -141,11 +203,14 @@ function ClientPreferencesRoot({ $data: $dataProp, className, children }) {
141
203
  * particle). Reads ITS field's value, pending, and error from the section context and dispatches the
142
204
  * write through `$actions.identity.clientPreferencesUpdate({ [key]: value })`, handing the promise to
143
205
  * the section so the in-flight key and returned userErrors are tracked per field. The `fieldKey`,
144
- * `dataAttr`, `pendingAttr`, and `readonlyAttr` are fixed by each registered Control; only
145
- * `label`/`className` are merchant-configurable.
206
+ * `dataAttr`, `pendingAttr`, `readonlyAttr`, content type and error map are fixed by each registered
207
+ * Control; only `label`/`className` and the `$content` message are merchant-configurable. A refusal is
208
+ * worded by the Control's message for its code; a code the map does not know shows the Control's
209
+ * genericErrorMessage.
146
210
  */
147
- function OptInControl({ fieldKey, dataAttr, pendingAttr, readonlyAttr, label, className, $actions: $actionsProp }) {
211
+ function OptInControl({ fieldKey, dataAttr, pendingAttr, readonlyAttr, contentType, errorFields, label, className, $content, $actions: $actionsProp }) {
148
212
  const $actions = useActionsOverride($actionsProp);
213
+ const { format } = useMessageFormatter(contentType, $content);
149
214
  const { values, trackWrite, pendingKeys, errorByKey, readOnly } = useClientPreferencesContext();
150
215
  const fieldErrors = errorByKey[fieldKey] ?? [];
151
216
  const value = values[fieldKey];
@@ -174,23 +239,27 @@ function OptInControl({ fieldKey, dataAttr, pendingAttr, readonlyAttr, label, cl
174
239
  children: /* @__PURE__ */ jsx(Checkbox.Indicator, { children: /* @__PURE__ */ jsx(Icon, { name: "checked" }) })
175
240
  }), label] }), invalid && firstError ? /* @__PURE__ */ jsx(Field.Error, {
176
241
  match: true,
177
- children: firstError.message
242
+ children: formatErrorCode(contentType, errorFields, firstError, format, "genericErrorMessage")
178
243
  }) : null]
179
244
  })
180
245
  });
181
246
  }
182
- function NewsletterOptInControl(props) {
247
+ function NewsletterOptInControl({ $locale, ...props }) {
183
248
  return /* @__PURE__ */ jsx(OptInControl, {
184
249
  ...props,
250
+ contentType: NewsletterOptInControlContent,
251
+ errorFields: NEWSLETTER_OPT_IN_ERROR_FIELDS,
185
252
  fieldKey: "optinNewsLetter",
186
253
  dataAttr: "data-fs-newsletter-opt-in",
187
254
  pendingAttr: "data-fs-newsletter-opt-in-pending",
188
255
  readonlyAttr: "data-fs-newsletter-opt-in-readonly"
189
256
  });
190
257
  }
191
- function SavePersonalDataOptInControl(props) {
258
+ function SavePersonalDataOptInControl({ $locale, ...props }) {
192
259
  return /* @__PURE__ */ jsx(OptInControl, {
193
260
  ...props,
261
+ contentType: SavePersonalDataOptInControlContent,
262
+ errorFields: SAVE_PERSONAL_DATA_OPT_IN_ERROR_FIELDS,
194
263
  fieldKey: "savePersonalData",
195
264
  dataAttr: "data-fs-save-personal-data-opt-in",
196
265
  pendingAttr: "data-fs-save-personal-data-opt-in-pending",
@@ -203,6 +272,6 @@ const ClientPreferences = {
203
272
  SavePersonalDataOptInControl
204
273
  };
205
274
  //#endregion
206
- export { ClientPreferences, ClientPreferencesRoot, ClientPreferencesRootDefinition, NewsletterOptInControl, NewsletterOptInControlDefinition, SavePersonalDataOptInControl, SavePersonalDataOptInControlDefinition };
275
+ export { ClientPreferences, ClientPreferencesRoot, ClientPreferencesRootDefinition, NEWSLETTER_OPT_IN_ERROR_FIELDS, NewsletterOptInControl, NewsletterOptInControlContent, NewsletterOptInControlDefinition, SAVE_PERSONAL_DATA_OPT_IN_ERROR_FIELDS, SavePersonalDataOptInControl, SavePersonalDataOptInControlContent, SavePersonalDataOptInControlDefinition };
207
276
 
208
277
  //# sourceMappingURL=client-preferences.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-preferences.js","names":[],"sources":["../../../src/matter/client-preferences/client-preferences.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from 'react';\nimport { Checkbox } from '../../particles/checkbox/checkbox.js';\nimport { Field } from '../../particles/field/field.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { 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 type { ClientPreferenceKey, ClientProfileUserError } from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * The `client-preferences` section matter (per ADR-0011: a matter is decomposed by DATA OWNERSHIP,\n * not per field). Both opt-ins — newsletter (`optinNewsLetter`) and save-personal-data\n * (`savePersonalData`) — are light booleans owned by the User Identity `ClientPreferences` entity\n * (a SIBLING of `Cart`, not nested under it, per the identity RFC), so they live under ONE\n * `ClientPreferencesRoot` that declares a single section fragment on `Query` selecting both fields.\n * The two merchant-facing Controls consume that one section context (ADR-0011 governs data\n * ownership, not the editor palette) and share one internal `OptInControl` implementation: the\n * section context, the `$data` → values seeding, the per-field pending/error tracking, the inlined\n * `Checkbox` + `Field` Control render, and dispatch via `$actions.identity.clientPreferencesUpdate`\n * (mirrors the `email-identification` matter; reads/writes follow ADR-0006 / ADR-0010 / ADR-0011).\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated (ADR-0011), reads the ClientPreferences sibling\n// entity via Query. Authored as a raw string (not the codegen graphql() factory),\n// mirroring the EmailIdentification matter: the compiler derives the entity fragment\n// on `clientPreferences` and subscribes reactively. One section fragment owns both\n// opt-in fields (ADR-0011).\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientPreferencesData on Query {\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the `ClientPreferences` sibling entity, unwrapped. */\nexport type ClientPreferencesData = {\n optinNewsLetter?: boolean | null;\n savePersonalData?: boolean | null;\n} | null;\n\nexport type ClientPreferencesRootProps = {\n /** `Query` slice forwarded by the reactive runtime (value of the section fragment). */\n $data?: ClientPreferencesData;\n className?: string;\n children?: ReactNode;\n};\n\nexport type ClientPreferencesControlProps = {\n label: string;\n className?: string;\n /** Injected by the compiler from `actions: { identity: ['clientPreferencesUpdate'] }`; the write surface. */\n $actions?: ComponentActions;\n};\n\nexport type NewsletterOptInControlProps = ClientPreferencesControlProps;\nexport type SavePersonalDataOptInControlProps = ClientPreferencesControlProps;\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferencesRootDefinition = defineComponent<ClientPreferencesRootProps>({\n name: 'ClientPreferencesRoot',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesRoot,\n fragment,\n fetchStrategy: 'reactive',\n providesContext: 'client-preferences-toggle',\n requiresContext: 'session',\n editor: { label: 'Client Preferences Root', category: 'identity' },\n schema: {},\n guideline:\n 'Binding provider for the consent opt-in section; reads both opt-in values (optinNewsLetter, savePersonalData) from the ClientPreferences identity entity (a sibling of Cart, via Query.clientPreferences) and exposes them to its Controls. Reads session state from useSession(); must be inside SessionRoot. Writes flow through $actions.identity.clientPreferencesUpdate. Wrap a NewsletterOptInControl and/or a SavePersonalDataOptInControl.',\n});\n\nexport const NewsletterOptInControlDefinition = defineComponent<NewsletterOptInControlProps>({\n name: 'NewsletterOptInControl',\n importPath: '@vtex/faststore/components',\n component: NewsletterOptInControl,\n requiresContext: 'client-preferences-toggle',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Newsletter Opt-In Control', category: 'identity' },\n schema: {\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n 'The bound newsletter opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the optinNewsLetter preference via $actions.identity.clientPreferencesUpdate. Defaults to unchecked.',\n});\n\nexport const SavePersonalDataOptInControlDefinition = defineComponent<SavePersonalDataOptInControlProps>({\n name: 'SavePersonalDataOptInControl',\n importPath: '@vtex/faststore/components',\n component: SavePersonalDataOptInControl,\n requiresContext: 'client-preferences-toggle',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Save Personal Data Opt-In Control', category: 'identity' },\n schema: {\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n 'The bound save-personal-data opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the savePersonalData preference via $actions.identity.clientPreferencesUpdate. Defaults to unchecked.',\n});\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ntype ClientPreferencesContextValue = Readonly<{\n /** Current value of each opt-in, seeded from the query response (null → unchecked). */\n values: Readonly<Record<ClientPreferenceKey, boolean>>;\n /**\n * Records that a write for `key` is in flight and stores its returned userErrors under that key so\n * each Control surfaces ITS OWN pending/error. The Control owns the actual dispatch (it holds\n * `$actions`); it hands the resulting promise here for the section to track.\n */\n trackWrite: (key: ClientPreferenceKey, write: Promise<readonly ClientProfileUserError[]>) => void;\n /**\n * The fields whose writes are currently in flight. A per-key set, not a single slot: concurrent\n * writes on different fields must each keep their own Control disabled until THEIR write settles.\n */\n pendingKeys: ReadonlySet<ClientPreferenceKey>;\n /** The userErrors returned by the most recent write, keyed by the field that produced them. */\n errorByKey: Readonly<Partial<Record<ClientPreferenceKey, readonly ClientProfileUserError[]>>>;\n /**\n * True when the session reports `canEditData: false` — VTEX refuses profile-data edits for an\n * identified-but-unauthenticated claimed profile, so the Controls render disabled instead of\n * accepting writes that are doomed server-side (mirrors the email control).\n */\n readOnly: boolean;\n}>;\n\nconst CLIENT_PREFERENCES_UNSET = Symbol('ClientPreferencesContextUnset');\n\nconst ClientPreferencesContext = createContext<ClientPreferencesContextValue | typeof CLIENT_PREFERENCES_UNSET>(\n CLIENT_PREFERENCES_UNSET,\n);\n\nfunction useClientPreferencesContext(): ClientPreferencesContextValue {\n const ctx = useContext(ClientPreferencesContext);\n if (ctx === CLIENT_PREFERENCES_UNSET) {\n throw new Error('A client-preferences Control must be used inside a ClientPreferencesRoot.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Root\n// ---------------------------------------------------------------------------\n\n/**\n * Renders the client-preferences section Root: reads `$data` (the `ClientPreferences` sibling entity),\n * reads `useSession()` (which also enforces the `SessionRoot` ancestor, mirroring\n * `EmailIdentificationControl`), seeds both opt-in values from the section fragment, and publishes a\n * section context exposing both values plus per-field pending/error tracking. The write itself flows\n * through the Control's `$actions.identity.clientPreferencesUpdate` (ADR-0010); this Root tracks which\n * keys are in flight and stores the returned userErrors under each key so each Control surfaces ITS OWN\n * pending/error. When the session reports `canEditData: false` (identified but unauthenticated claimed\n * profile — VTEX refuses the write server-side) every Control renders disabled with its readonly\n * `data-fs-*` attribute, mirroring `EmailIdentificationControl`.\n */\nexport function ClientPreferencesRoot({ $data: $dataProp, className, children }: ClientPreferencesRootProps) {\n const $data = useDataOverride($dataProp);\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n const optinNewsLetter = Boolean($data?.optinNewsLetter ?? false);\n const savePersonalData = Boolean($data?.savePersonalData ?? false);\n\n const [pendingKeys, setPendingKeys] = useState<ReadonlySet<ClientPreferenceKey>>(new Set());\n const [errorByKey, setErrorByKey] = useState<Partial<Record<ClientPreferenceKey, readonly ClientProfileUserError[]>>>(\n {},\n );\n\n const trackWrite = useCallback((key: ClientPreferenceKey, write: Promise<readonly ClientProfileUserError[]>) => {\n // Clear the key's stale error at the start of a retry (parity with the email control clearing\n // its serverError on a new write).\n setErrorByKey((prev) => ({ ...prev, [key]: [] }));\n setPendingKeys((prev) => new Set(prev).add(key));\n void write\n .then((userErrors) => {\n setErrorByKey((prev) => ({ ...prev, [key]: userErrors }));\n })\n .finally(() => {\n setPendingKeys((prev) => {\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n });\n }, []);\n\n const values = useMemo(() => ({ optinNewsLetter, savePersonalData }) as const, [optinNewsLetter, savePersonalData]);\n\n const contextValue = useMemo<ClientPreferencesContextValue>(\n () => ({ values, trackWrite, pendingKeys, errorByKey, readOnly }),\n [values, trackWrite, pendingKeys, errorByKey, readOnly],\n );\n\n return (\n <ClientPreferencesContext value={contextValue}>\n <div className={className} data-fs-client-preferences-root=\"\">\n {children}\n </div>\n </ClientPreferencesContext>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Controls\n// ---------------------------------------------------------------------------\n\n/**\n * Renders one bound opt-in checkbox by inlining `Field` + `Checkbox` + `Icon` (no `CheckboxField`\n * particle). Reads ITS field's value, pending, and error from the section context and dispatches the\n * write through `$actions.identity.clientPreferencesUpdate({ [key]: value })`, handing the promise to\n * the section so the in-flight key and returned userErrors are tracked per field. The `fieldKey`,\n * `dataAttr`, `pendingAttr`, and `readonlyAttr` are fixed by each registered Control; only\n * `label`/`className` are merchant-configurable.\n */\nfunction OptInControl({\n fieldKey,\n dataAttr,\n pendingAttr,\n readonlyAttr,\n label,\n className,\n $actions: $actionsProp,\n}: ClientPreferencesControlProps & {\n fieldKey: ClientPreferenceKey;\n dataAttr: string;\n pendingAttr: string;\n readonlyAttr: string;\n}) {\n const $actions = useActionsOverride($actionsProp);\n const { values, trackWrite, pendingKeys, errorByKey, readOnly } = useClientPreferencesContext();\n const fieldErrors = errorByKey[fieldKey] ?? [];\n const value = values[fieldKey];\n const pending = pendingKeys.has(fieldKey);\n const disabled = pending || readOnly;\n const [firstError] = fieldErrors;\n const invalid = Boolean(firstError);\n\n function handleCheckedChange(checked: boolean) {\n const update = $actions?.identity?.clientPreferencesUpdate;\n if (!update) return;\n trackWrite(fieldKey, update({ [fieldKey]: checked }));\n }\n\n return (\n <div\n className={className}\n {...{ [dataAttr]: '' }}\n {...(pending ? { [pendingAttr]: '' } : {})}\n {...(readOnly ? { [readonlyAttr]: '' } : {})}\n >\n <Field.Root invalid={invalid} disabled={disabled} data-fs-field-root=\"\">\n <Field.Label>\n <Checkbox.Root checked={value} onCheckedChange={handleCheckedChange} disabled={disabled}>\n <Checkbox.Indicator>\n <Icon name=\"checked\" />\n </Checkbox.Indicator>\n </Checkbox.Root>\n {label}\n </Field.Label>\n {invalid && firstError ? <Field.Error match>{firstError.message}</Field.Error> : null}\n </Field.Root>\n </div>\n );\n}\n\nexport function NewsletterOptInControl(props: NewsletterOptInControlProps) {\n return (\n <OptInControl\n {...props}\n fieldKey=\"optinNewsLetter\"\n dataAttr=\"data-fs-newsletter-opt-in\"\n pendingAttr=\"data-fs-newsletter-opt-in-pending\"\n readonlyAttr=\"data-fs-newsletter-opt-in-readonly\"\n />\n );\n}\n\nexport function SavePersonalDataOptInControl(props: SavePersonalDataOptInControlProps) {\n return (\n <OptInControl\n {...props}\n fieldKey=\"savePersonalData\"\n dataAttr=\"data-fs-save-personal-data-opt-in\"\n pendingAttr=\"data-fs-save-personal-data-opt-in-pending\"\n readonlyAttr=\"data-fs-save-personal-data-opt-in-readonly\"\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferences = {\n Root: ClientPreferencesRoot,\n NewsletterOptInControl,\n SavePersonalDataOptInControl,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-preferences.js","names":[],"sources":["../../../src/matter/client-preferences/client-preferences.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ContentValue,\n defineComponent,\n defineContentType,\n type MessageFieldName,\n type MessageLocaleProp,\n} from '@vtex/fs-core';\nimport { createContext, type ReactNode, useCallback, useContext, useMemo, useState } from 'react';\nimport { Checkbox } from '../../particles/checkbox/checkbox.js';\nimport { Field } from '../../particles/field/field.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { 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 { formatErrorCode } from '../../sdk/i18n/format-error-code.js';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\nimport type { ClientPreferenceKey, ClientProfileUserError } from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * The `client-preferences` section matter (per ADR-0011: a matter is decomposed by DATA OWNERSHIP,\n * not per field). Both opt-ins — newsletter (`optinNewsLetter`) and save-personal-data\n * (`savePersonalData`) — are light booleans owned by the User Identity `ClientPreferences` entity\n * (a SIBLING of `Cart`, not nested under it, per the identity RFC), so they live under ONE\n * `ClientPreferencesRoot` that declares a single section fragment on `Query` selecting both fields.\n * The two merchant-facing Controls consume that one section context (ADR-0011 governs data\n * ownership, not the editor palette) and share one internal `OptInControl` implementation: the\n * section context, the `$data` → values seeding, the per-field pending/error tracking, the inlined\n * `Checkbox` + `Field` Control render, and dispatch via `$actions.identity.clientPreferencesUpdate`\n * (mirrors the `email-identification` matter; reads/writes follow ADR-0006 / ADR-0010 / ADR-0011).\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated (ADR-0011), reads the ClientPreferences sibling\n// entity via Query. Authored as a raw string (not the codegen graphql() factory),\n// mirroring the EmailIdentification matter: the compiler derives the entity fragment\n// on `clientPreferences` and subscribes reactively. One section fragment owns both\n// opt-in fields (ADR-0011).\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientPreferencesData on Query {\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Content models\n// ---------------------------------------------------------------------------\n\nexport const NewsletterOptInControlContent = defineContentType({\n id: 'newsletter-opt-in-control',\n title: 'Newsletter Opt-In Control',\n description: 'The inline message shown when saving the newsletter opt-in fails.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n genericErrorMessage: {\n type: 'string',\n title: 'Save failure message',\n description: 'Shown for a network failure and for any refusal the shopper cannot act on.',\n format: 'icu-message',\n messageSource: 'Unable to save your preference. Please try again.',\n },\n },\n },\n});\n\nexport const SavePersonalDataOptInControlContent = defineContentType({\n id: 'save-personal-data-opt-in-control',\n title: 'Save Personal Data Opt-In Control',\n description: 'The inline message shown when saving the save-personal-data opt-in fails.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n genericErrorMessage: {\n type: 'string',\n title: 'Save failure message',\n description: 'Shown for a network failure and for any refusal the shopper cannot act on.',\n format: 'icu-message',\n messageSource: 'Unable to save your preference. Please try again.',\n },\n },\n },\n});\n\n/**\n * `ClientPreferencesUpdateErrorCode` of API Core's schema plus the client-minted transport failure. None\n * is something the shopper can fix by toggling again, so all share the generic message.\n */\nexport const NEWSLETTER_OPT_IN_ERROR_FIELDS = {\n MISSING_CART_CONTEXT: 'genericErrorMessage',\n CART_NOT_FOUND: 'genericErrorMessage',\n NO_PREFERENCE_PROVIDED: 'genericErrorMessage',\n NETWORK_ERROR: 'genericErrorMessage',\n} as const satisfies Record<string, MessageFieldName<typeof NewsletterOptInControlContent>>;\n\nexport const SAVE_PERSONAL_DATA_OPT_IN_ERROR_FIELDS = {\n ...NEWSLETTER_OPT_IN_ERROR_FIELDS,\n} as const satisfies Record<string, MessageFieldName<typeof SavePersonalDataOptInControlContent>>;\n\ntype OptInErrorFields = typeof NEWSLETTER_OPT_IN_ERROR_FIELDS;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the `ClientPreferences` sibling entity, unwrapped. */\nexport type ClientPreferencesData = {\n optinNewsLetter?: boolean | null;\n savePersonalData?: boolean | null;\n} | null;\n\nexport type ClientPreferencesRootProps = {\n /** `Query` slice forwarded by the reactive runtime (value of the section fragment). */\n $data?: ClientPreferencesData;\n className?: string;\n children?: ReactNode;\n};\n\nexport type ClientPreferencesControlProps = MessageLocaleProp & {\n label: string;\n className?: string;\n /** Injected by the compiler from `actions: { identity: ['clientPreferencesUpdate'] }`; the write surface. */\n $actions?: ComponentActions;\n};\n\nexport type NewsletterOptInControlProps = ClientPreferencesControlProps & {\n /** The inline message for a refused save. */\n $content?: ContentValue<typeof NewsletterOptInControlContent>;\n};\nexport type SavePersonalDataOptInControlProps = ClientPreferencesControlProps & {\n /** The inline message for a refused save. */\n $content?: ContentValue<typeof SavePersonalDataOptInControlContent>;\n};\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferencesRootDefinition = defineComponent<ClientPreferencesRootProps>({\n name: 'ClientPreferencesRoot',\n importPath: '@vtex/faststore/components',\n component: ClientPreferencesRoot,\n fragment,\n fetchStrategy: 'reactive',\n providesContext: 'client-preferences-toggle',\n requiresContext: 'session',\n editor: { label: 'Client Preferences Root', category: 'identity' },\n schema: {},\n guideline:\n 'Binding provider for the consent opt-in section; reads both opt-in values (optinNewsLetter, savePersonalData) from the ClientPreferences identity entity (a sibling of Cart, via Query.clientPreferences) and exposes them to its Controls. Reads session state from useSession(); must be inside SessionRoot. Writes flow through $actions.identity.clientPreferencesUpdate. Wrap a NewsletterOptInControl and/or a SavePersonalDataOptInControl.',\n});\n\nexport const NewsletterOptInControlDefinition = defineComponent<NewsletterOptInControlProps>({\n name: 'NewsletterOptInControl',\n importPath: '@vtex/faststore/components',\n component: NewsletterOptInControl,\n content: NewsletterOptInControlContent,\n requiresContext: 'client-preferences-toggle',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Newsletter Opt-In Control', category: 'identity' },\n schema: {\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n 'The bound newsletter opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the optinNewsLetter preference via $actions.identity.clientPreferencesUpdate; a refused save shows the $content field genericErrorMessage. Defaults to unchecked.',\n});\n\nexport const SavePersonalDataOptInControlDefinition = defineComponent<SavePersonalDataOptInControlProps>({\n name: 'SavePersonalDataOptInControl',\n importPath: '@vtex/faststore/components',\n component: SavePersonalDataOptInControl,\n content: SavePersonalDataOptInControlContent,\n requiresContext: 'client-preferences-toggle',\n actions: { identity: ['clientPreferencesUpdate'] },\n editor: { label: 'Save Personal Data Opt-In Control', category: 'identity' },\n schema: {\n label: { type: 'string', label: 'Label' },\n },\n guideline:\n 'The bound save-personal-data opt-in checkbox; must be a descendant of ClientPreferencesRoot. Toggling writes the savePersonalData preference via $actions.identity.clientPreferencesUpdate; a refused save shows the $content field genericErrorMessage. Defaults to unchecked.',\n});\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ntype ClientPreferencesContextValue = Readonly<{\n /** Current value of each opt-in, seeded from the query response (null → unchecked). */\n values: Readonly<Record<ClientPreferenceKey, boolean>>;\n /**\n * Records that a write for `key` is in flight and stores its returned userErrors under that key so\n * each Control surfaces ITS OWN pending/error. The Control owns the actual dispatch (it holds\n * `$actions`); it hands the resulting promise here for the section to track.\n */\n trackWrite: (key: ClientPreferenceKey, write: Promise<readonly ClientProfileUserError[]>) => void;\n /**\n * The fields whose writes are currently in flight. A per-key set, not a single slot: concurrent\n * writes on different fields must each keep their own Control disabled until THEIR write settles.\n */\n pendingKeys: ReadonlySet<ClientPreferenceKey>;\n /** The userErrors returned by the most recent write, keyed by the field that produced them. */\n errorByKey: Readonly<Partial<Record<ClientPreferenceKey, readonly ClientProfileUserError[]>>>;\n /**\n * True when the session reports `canEditData: false` — VTEX refuses profile-data edits for an\n * identified-but-unauthenticated claimed profile, so the Controls render disabled instead of\n * accepting writes that are doomed server-side (mirrors the email control).\n */\n readOnly: boolean;\n}>;\n\nconst CLIENT_PREFERENCES_UNSET = Symbol('ClientPreferencesContextUnset');\n\nconst ClientPreferencesContext = createContext<ClientPreferencesContextValue | typeof CLIENT_PREFERENCES_UNSET>(\n CLIENT_PREFERENCES_UNSET,\n);\n\nfunction useClientPreferencesContext(): ClientPreferencesContextValue {\n const ctx = useContext(ClientPreferencesContext);\n if (ctx === CLIENT_PREFERENCES_UNSET) {\n throw new Error('A client-preferences Control must be used inside a ClientPreferencesRoot.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Root\n// ---------------------------------------------------------------------------\n\n/**\n * Renders the client-preferences section Root: reads `$data` (the `ClientPreferences` sibling entity),\n * reads `useSession()` (which also enforces the `SessionRoot` ancestor, mirroring\n * `EmailIdentificationControl`), seeds both opt-in values from the section fragment, and publishes a\n * section context exposing both values plus per-field pending/error tracking. The write itself flows\n * through the Control's `$actions.identity.clientPreferencesUpdate` (ADR-0010); this Root tracks which\n * keys are in flight and stores the returned userErrors under each key so each Control surfaces ITS OWN\n * pending/error. When the session reports `canEditData: false` (identified but unauthenticated claimed\n * profile — VTEX refuses the write server-side) every Control renders disabled with its readonly\n * `data-fs-*` attribute, mirroring `EmailIdentificationControl`.\n */\nexport function ClientPreferencesRoot({ $data: $dataProp, className, children }: ClientPreferencesRootProps) {\n const $data = useDataOverride($dataProp);\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n const optinNewsLetter = Boolean($data?.optinNewsLetter ?? false);\n const savePersonalData = Boolean($data?.savePersonalData ?? false);\n\n const [pendingKeys, setPendingKeys] = useState<ReadonlySet<ClientPreferenceKey>>(new Set());\n const [errorByKey, setErrorByKey] = useState<Partial<Record<ClientPreferenceKey, readonly ClientProfileUserError[]>>>(\n {},\n );\n\n const trackWrite = useCallback((key: ClientPreferenceKey, write: Promise<readonly ClientProfileUserError[]>) => {\n // Clear the key's stale error at the start of a retry (parity with the email control clearing\n // its serverError on a new write).\n setErrorByKey((prev) => ({ ...prev, [key]: [] }));\n setPendingKeys((prev) => new Set(prev).add(key));\n void write\n .then((userErrors) => {\n setErrorByKey((prev) => ({ ...prev, [key]: userErrors }));\n })\n .finally(() => {\n setPendingKeys((prev) => {\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n });\n }, []);\n\n const values = useMemo(() => ({ optinNewsLetter, savePersonalData }) as const, [optinNewsLetter, savePersonalData]);\n\n const contextValue = useMemo<ClientPreferencesContextValue>(\n () => ({ values, trackWrite, pendingKeys, errorByKey, readOnly }),\n [values, trackWrite, pendingKeys, errorByKey, readOnly],\n );\n\n return (\n <ClientPreferencesContext value={contextValue}>\n <div className={className} data-fs-client-preferences-root=\"\">\n {children}\n </div>\n </ClientPreferencesContext>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Controls\n// ---------------------------------------------------------------------------\n\n/**\n * Renders one bound opt-in checkbox by inlining `Field` + `Checkbox` + `Icon` (no `CheckboxField`\n * particle). Reads ITS field's value, pending, and error from the section context and dispatches the\n * write through `$actions.identity.clientPreferencesUpdate({ [key]: value })`, handing the promise to\n * the section so the in-flight key and returned userErrors are tracked per field. The `fieldKey`,\n * `dataAttr`, `pendingAttr`, `readonlyAttr`, content type and error map are fixed by each registered\n * Control; only `label`/`className` and the `$content` message are merchant-configurable. A refusal is\n * worded by the Control's message for its code; a code the map does not know shows the Control's\n * genericErrorMessage.\n */\nfunction OptInControl({\n fieldKey,\n dataAttr,\n pendingAttr,\n readonlyAttr,\n contentType,\n errorFields,\n label,\n className,\n $content,\n $actions: $actionsProp,\n}: ClientPreferencesControlProps & {\n fieldKey: ClientPreferenceKey;\n dataAttr: string;\n pendingAttr: string;\n readonlyAttr: string;\n contentType: typeof NewsletterOptInControlContent | typeof SavePersonalDataOptInControlContent;\n errorFields: OptInErrorFields;\n $content?: ContentValue<typeof NewsletterOptInControlContent>;\n}) {\n const $actions = useActionsOverride($actionsProp);\n // Both content types declare the same field, so one type serves either control's formatter.\n const { format } = useMessageFormatter(contentType as typeof NewsletterOptInControlContent, $content);\n const { values, trackWrite, pendingKeys, errorByKey, readOnly } = useClientPreferencesContext();\n const fieldErrors = errorByKey[fieldKey] ?? [];\n const value = values[fieldKey];\n const pending = pendingKeys.has(fieldKey);\n const disabled = pending || readOnly;\n const [firstError] = fieldErrors;\n const invalid = Boolean(firstError);\n\n function handleCheckedChange(checked: boolean) {\n const update = $actions?.identity?.clientPreferencesUpdate;\n if (!update) return;\n trackWrite(fieldKey, update({ [fieldKey]: checked }));\n }\n\n return (\n <div\n className={className}\n {...{ [dataAttr]: '' }}\n {...(pending ? { [pendingAttr]: '' } : {})}\n {...(readOnly ? { [readonlyAttr]: '' } : {})}\n >\n <Field.Root invalid={invalid} disabled={disabled} data-fs-field-root=\"\">\n <Field.Label>\n <Checkbox.Root checked={value} onCheckedChange={handleCheckedChange} disabled={disabled}>\n <Checkbox.Indicator>\n <Icon name=\"checked\" />\n </Checkbox.Indicator>\n </Checkbox.Root>\n {label}\n </Field.Label>\n {invalid && firstError ? (\n <Field.Error match>\n {formatErrorCode(contentType, errorFields, firstError, format, 'genericErrorMessage')}\n </Field.Error>\n ) : null}\n </Field.Root>\n </div>\n );\n}\n\nexport function NewsletterOptInControl({ $locale, ...props }: NewsletterOptInControlProps) {\n return (\n <OptInControl\n {...props}\n contentType={NewsletterOptInControlContent}\n errorFields={NEWSLETTER_OPT_IN_ERROR_FIELDS}\n fieldKey=\"optinNewsLetter\"\n dataAttr=\"data-fs-newsletter-opt-in\"\n pendingAttr=\"data-fs-newsletter-opt-in-pending\"\n readonlyAttr=\"data-fs-newsletter-opt-in-readonly\"\n />\n );\n}\n\nexport function SavePersonalDataOptInControl({ $locale, ...props }: SavePersonalDataOptInControlProps) {\n return (\n <OptInControl\n {...props}\n contentType={SavePersonalDataOptInControlContent}\n errorFields={SAVE_PERSONAL_DATA_OPT_IN_ERROR_FIELDS}\n fieldKey=\"savePersonalData\"\n dataAttr=\"data-fs-save-personal-data-opt-in\"\n pendingAttr=\"data-fs-save-personal-data-opt-in-pending\"\n readonlyAttr=\"data-fs-save-personal-data-opt-in-readonly\"\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace export\n// ---------------------------------------------------------------------------\n\nexport const ClientPreferences = {\n Root: ClientPreferencesRoot,\n NewsletterOptInControl,\n SavePersonalDataOptInControl,\n};\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { ContentValue, MessageLocaleProp } from "../../core/dist/define-content-type.js";
1
2
  import { ComponentDefinition } from "../../core/dist/define-component.js";
2
3
  import "../../core/dist/index.js";
3
4
  import { ComponentActions } from "../../sdk/actions/types.js";
@@ -23,17 +24,50 @@ export declare const ClientProfileRootDefinition: ComponentDefinition<ClientProf
23
24
  */
24
25
  export declare function ClientProfileRoot({ $data: $dataProp, className, children }: ClientProfileRootProps): import("react/jsx-runtime").JSX.Element;
25
26
  type PhoneFieldRequirement = 'mandatory' | 'optional';
26
- export type ClientProfilePhoneControlProps = {
27
- /** Visible field label. */
28
- label?: string;
27
+ export declare const ClientProfilePhoneControlContent: {
28
+ readonly id: "client-profile-phone-control";
29
+ readonly title: "Client Profile Phone Control";
30
+ readonly description: "The phone field's label, its validation messages and the message for a refused save.";
31
+ readonly schema: {
32
+ readonly type: "object";
33
+ readonly additionalProperties: false;
34
+ readonly properties: {
35
+ readonly label: {
36
+ readonly type: "string";
37
+ readonly title: "Label";
38
+ readonly format: "icu-message";
39
+ readonly messageSource: "Phone";
40
+ };
41
+ readonly errorInvalid: {
42
+ readonly type: "string";
43
+ readonly title: "Invalid error message";
44
+ readonly format: "icu-message";
45
+ readonly messageSource: "Invalid phone number";
46
+ };
47
+ readonly errorRequired: {
48
+ readonly type: "string";
49
+ readonly title: "Required error message";
50
+ readonly format: "icu-message";
51
+ readonly messageSource: "Phone number is required";
52
+ };
53
+ readonly genericErrorMessage: {
54
+ readonly type: "string";
55
+ readonly title: "Save failure message";
56
+ readonly description: "Shown for a network failure and for any refusal the shopper cannot act on.";
57
+ readonly format: "icu-message";
58
+ readonly messageSource: "Unable to save your details. Please try again.";
59
+ };
60
+ };
61
+ };
62
+ };
63
+ export type ClientProfilePhoneControlProps = MessageLocaleProp & {
29
64
  /** Selects the phone mask and validation rule. */
30
65
  country?: PhoneCountry;
31
66
  /** Controls required validation. */
32
67
  requirement?: PhoneFieldRequirement;
33
- /** Error string shown when the input format is invalid. */
34
- errorInvalid?: string;
35
- /** Error string shown when the mandatory field is left empty. */
36
- errorRequired?: string;
68
+ /** The visible label, the messages for an invalid format and a mandatory field left empty, and the
69
+ * message for a refused save. */
70
+ $content?: ContentValue<typeof ClientProfilePhoneControlContent>;
37
71
  className?: string;
38
72
  /** Injected by the compiler from `actions: { identity: ['clientProfileUpdate'] }`; the write surface. */
39
73
  $actions?: ComponentActions;
@@ -46,9 +80,10 @@ export declare const ClientProfilePhoneControlDefinition: ComponentDefinition<Cl
46
80
  * mirroring `EmailIdentificationControl`). While the write is in flight the field is disabled and
47
81
  * `data-fs-client-profile-phone-pending` is present so a checkout-CTA guard can block. When the
48
82
  * session reports `canEditData: false` the field renders disabled with
49
- * `data-fs-client-profile-phone-readonly`. Server `userErrors` are surfaced inline.
83
+ * `data-fs-client-profile-phone-readonly`. Server `userErrors` are surfaced inline, worded by the
84
+ * `$content` field for their code (genericErrorMessage for a code it does not know).
50
85
  */
51
- export declare function ClientProfilePhoneControl({ label, country, requirement, errorInvalid, errorRequired, className, $actions: $actionsProp }: Readonly<ClientProfilePhoneControlProps>): import("react/jsx-runtime").JSX.Element;
86
+ export declare function ClientProfilePhoneControl({ country, requirement, $content, $locale, className, $actions: $actionsProp }: Readonly<ClientProfilePhoneControlProps>): import("react/jsx-runtime").JSX.Element;
52
87
  export declare const ClientProfile: {
53
88
  Root: typeof ClientProfileRoot;
54
89
  PhoneControl: typeof ClientProfilePhoneControl;