@vtex/faststore 0.0.5 → 0.0.6

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 (232) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/actions.json +181 -0
  3. package/dist/catalog.json +1543 -495
  4. package/dist/client.d.ts +2 -1
  5. package/dist/client.js +2 -1
  6. package/dist/components.d.ts +28 -7
  7. package/dist/components.js +31 -12
  8. package/dist/docs/access-code-sign-in.md +1 -1
  9. package/dist/docs/address-summary.md +24 -3
  10. package/dist/docs/alert-dialog.md +204 -0
  11. package/dist/docs/billing-address.md +284 -0
  12. package/dist/docs/card-entry.md +250 -0
  13. package/dist/docs/cardholder-document.md +142 -0
  14. package/dist/docs/client-preferences-fieldset.md +148 -0
  15. package/dist/docs/client-preferences.md +2 -1
  16. package/dist/docs/client-profile-fieldset.md +184 -0
  17. package/dist/docs/client-profile.md +1 -1
  18. package/dist/docs/document-field.md +58 -4
  19. package/dist/docs/field.md +317 -0
  20. package/dist/docs/form.md +307 -0
  21. package/dist/docs/identity-edit.md +6 -6
  22. package/dist/docs/identity-summary.md +5 -5
  23. package/dist/docs/installments.md +248 -0
  24. package/dist/docs/my-account-profile.md +1 -0
  25. package/dist/docs/order-placed-payment-summary.md +138 -0
  26. package/dist/docs/payment-method-badges.md +232 -0
  27. package/dist/docs/payment-methods.md +1 -0
  28. package/dist/docs/payment.md +218 -0
  29. package/dist/docs/phone-field.md +58 -4
  30. package/dist/docs/place-order.md +157 -0
  31. package/dist/docs/save-card.md +186 -0
  32. package/dist/docs/saved-cards.md +218 -0
  33. package/dist/docs/select.md +465 -0
  34. package/dist/docs/shipping-address.md +110 -258
  35. package/dist/index.d.ts +4 -1
  36. package/dist/internal/client.d.ts +3 -1
  37. package/dist/internal/client.js +3 -1
  38. package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
  39. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  40. package/dist/matter/billing-address/billing-address.d.ts +165 -0
  41. package/dist/matter/billing-address/billing-address.js +408 -0
  42. package/dist/matter/billing-address/billing-address.js.map +1 -0
  43. package/dist/matter/card-entry/card-capture.d.ts +25 -0
  44. package/dist/matter/card-entry/card-capture.js +25 -0
  45. package/dist/matter/card-entry/card-capture.js.map +1 -0
  46. package/dist/matter/card-entry/card-entry.d.ts +120 -0
  47. package/dist/matter/card-entry/card-entry.js +832 -0
  48. package/dist/matter/card-entry/card-entry.js.map +1 -0
  49. package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
  50. package/dist/matter/cardholder-document/cardholder-document.js +70 -0
  51. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
  52. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
  53. package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
  54. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
  55. package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
  56. package/dist/matter/client-preferences/client-preferences.js +6 -6
  57. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  58. package/dist/matter/client-profile/client-profile.d.ts +4 -6
  59. package/dist/matter/client-profile/client-profile.js +9 -6
  60. package/dist/matter/client-profile/client-profile.js.map +1 -1
  61. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
  62. package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
  63. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
  64. package/dist/matter/identity-edit/identity-edit.js +2 -2
  65. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  66. package/dist/matter/identity-summary/identity-summary.js +2 -2
  67. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  68. package/dist/matter/installments/installments-select.d.ts +42 -0
  69. package/dist/matter/installments/installments-select.js +167 -0
  70. package/dist/matter/installments/installments-select.js.map +1 -0
  71. package/dist/matter/installments/installments.d.ts +58 -0
  72. package/dist/matter/installments/installments.js +176 -0
  73. package/dist/matter/installments/installments.js.map +1 -0
  74. package/dist/matter/installments/use-installments-selection.d.ts +29 -0
  75. package/dist/matter/installments/use-installments-selection.js +95 -0
  76. package/dist/matter/installments/use-installments-selection.js.map +1 -0
  77. package/dist/matter/my-account-profile/my-account-profile.js +4 -4
  78. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  79. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
  80. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
  81. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
  82. package/dist/matter/payment/payment-card-capture.d.ts +19 -0
  83. package/dist/matter/payment/payment-card-capture.js +129 -0
  84. package/dist/matter/payment/payment-card-capture.js.map +1 -0
  85. package/dist/matter/payment/payment-controller.d.ts +24 -0
  86. package/dist/matter/payment/payment-controller.js +107 -0
  87. package/dist/matter/payment/payment-controller.js.map +1 -0
  88. package/dist/matter/payment/payment-method-badges.d.ts +57 -0
  89. package/dist/matter/payment/payment-method-badges.js +192 -0
  90. package/dist/matter/payment/payment-method-badges.js.map +1 -0
  91. package/dist/matter/payment/payment.d.ts +89 -0
  92. package/dist/matter/payment/payment.js +263 -0
  93. package/dist/matter/payment/payment.js.map +1 -0
  94. package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
  95. package/dist/matter/payment/use-payment-method-selection.js +458 -0
  96. package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
  97. package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
  98. package/dist/matter/payment/use-payment-submit-gate.js +144 -0
  99. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
  100. package/dist/matter/place-order/place-order.d.ts +74 -0
  101. package/dist/matter/place-order/place-order.js +379 -0
  102. package/dist/matter/place-order/place-order.js.map +1 -0
  103. package/dist/matter/product-list/product-list.d.ts +1 -0
  104. package/dist/matter/product-list/product-list.js.map +1 -1
  105. package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
  106. package/dist/matter/product-shelf/product-shelf.js +2 -0
  107. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  108. package/dist/matter/region/region.js +1 -1
  109. package/dist/matter/region/region.js.map +1 -1
  110. package/dist/matter/save-card/save-card.d.ts +49 -0
  111. package/dist/matter/save-card/save-card.js +188 -0
  112. package/dist/matter/save-card/save-card.js.map +1 -0
  113. package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
  114. package/dist/matter/saved-cards/saved-cards.js +387 -0
  115. package/dist/matter/saved-cards/saved-cards.js.map +1 -0
  116. package/dist/matter/shipping-address/country-descriptors.js +20 -10
  117. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  118. package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
  119. package/dist/matter/shipping-address/shipping-address.js +480 -791
  120. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  121. package/dist/matter/variant-selector/variant-selector.js +1 -1
  122. package/dist/particles/address-summary/address-summary.d.ts +24 -0
  123. package/dist/particles/address-summary/address-summary.js +83 -2
  124. package/dist/particles/address-summary/address-summary.js.map +1 -1
  125. package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
  126. package/dist/particles/alert-dialog/alert-dialog.js +187 -0
  127. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
  128. package/dist/particles/checkbox/checkbox.d.ts +7 -3
  129. package/dist/particles/checkbox/checkbox.js +4 -1
  130. package/dist/particles/checkbox/checkbox.js.map +1 -1
  131. package/dist/particles/document-field/document-field.d.ts +48 -5
  132. package/dist/particles/document-field/document-field.js +189 -32
  133. package/dist/particles/document-field/document-field.js.map +1 -1
  134. package/dist/particles/field/bound-field-registry.js +52 -0
  135. package/dist/particles/field/bound-field-registry.js.map +1 -0
  136. package/dist/particles/field/field.d.ts +116 -0
  137. package/dist/particles/field/field.js +497 -6
  138. package/dist/particles/field/field.js.map +1 -1
  139. package/dist/particles/fieldset/fieldset.js +2 -2
  140. package/dist/particles/fieldset/fieldset.js.map +1 -1
  141. package/dist/particles/form/form.d.ts +104 -0
  142. package/dist/particles/form/form.js +485 -0
  143. package/dist/particles/form/form.js.map +1 -0
  144. package/dist/particles/phone-field/phone-field.d.ts +38 -10
  145. package/dist/particles/phone-field/phone-field.js +183 -39
  146. package/dist/particles/phone-field/phone-field.js.map +1 -1
  147. package/dist/particles/postal-code-field/postal-code-field.js +2 -2
  148. package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
  149. package/dist/particles/select/field-select.d.ts +43 -0
  150. package/dist/particles/select/field-select.js +150 -0
  151. package/dist/particles/select/field-select.js.map +1 -0
  152. package/dist/particles/select/select.d.ts +2 -0
  153. package/dist/particles/select/select.js.map +1 -1
  154. package/dist/particles/shared/compose-refs.js +21 -0
  155. package/dist/particles/shared/compose-refs.js.map +1 -0
  156. package/dist/schema.graphql +701 -2
  157. package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
  158. package/dist/sdk/actions/analytics-action-provider.js +19 -0
  159. package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
  160. package/dist/sdk/actions/index.d.ts +3 -1
  161. package/dist/sdk/actions/index.js +3 -1
  162. package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
  163. package/dist/sdk/actions/payment-action-provider.js +26 -0
  164. package/dist/sdk/actions/payment-action-provider.js.map +1 -0
  165. package/dist/sdk/actions/types.d.ts +6 -2
  166. package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
  167. package/dist/sdk/analytics/analytics-destination.js +90 -0
  168. package/dist/sdk/analytics/analytics-destination.js.map +1 -0
  169. package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
  170. package/dist/sdk/analytics/use-analytics-actions.js +108 -0
  171. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
  172. package/dist/sdk/cart/use-cart-actions.js +1 -1
  173. package/dist/sdk/data/entity-resolution-context.js +31 -0
  174. package/dist/sdk/data/entity-resolution-context.js.map +1 -0
  175. package/dist/sdk/data/entity-subscriber.js +18 -8
  176. package/dist/sdk/data/entity-subscriber.js.map +1 -1
  177. package/dist/sdk/data/index.js +1 -0
  178. package/dist/sdk/data/page-reactive-data-root.d.ts +36 -0
  179. package/dist/sdk/data/page-reactive-data-root.js +4 -2
  180. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  181. package/dist/sdk/data/reactive-data-provider.js +7 -3
  182. package/dist/sdk/data/reactive-data-provider.js.map +1 -1
  183. package/dist/sdk/data/reactive-list-item-data-provider.js +12 -4
  184. package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
  185. package/dist/sdk/data/use-reactive-data-settled.js +39 -0
  186. package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
  187. package/dist/sdk/data/use-reactive-entity.js +5 -1
  188. package/dist/sdk/data/use-reactive-entity.js.map +1 -1
  189. package/dist/sdk/generated/fragment-types.js +2 -0
  190. package/dist/sdk/generated/fragment-types.js.map +1 -1
  191. package/dist/sdk/generated/graphql.js.map +1 -1
  192. package/dist/sdk/i18n/messages/en-US.js +3 -0
  193. package/dist/sdk/i18n/messages/en-US.json +3 -0
  194. package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
  195. package/dist/sdk/i18n/messages/es-ES.js +3 -0
  196. package/dist/sdk/i18n/messages/es-ES.json +3 -0
  197. package/dist/sdk/i18n/messages/pt-BR.js +3 -0
  198. package/dist/sdk/i18n/messages/pt-BR.json +3 -0
  199. package/dist/sdk/identity/use-identity-actions.js +3 -2
  200. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  201. package/dist/sdk/payment/gateway-origin.js +35 -0
  202. package/dist/sdk/payment/gateway-origin.js.map +1 -0
  203. package/dist/sdk/payment/gateway.d.ts +85 -0
  204. package/dist/sdk/payment/gateway.js +183 -0
  205. package/dist/sdk/payment/gateway.js.map +1 -0
  206. package/dist/sdk/payment/operations.d.ts +52 -0
  207. package/dist/sdk/payment/operations.js +223 -0
  208. package/dist/sdk/payment/operations.js.map +1 -0
  209. package/dist/sdk/payment/security-code-mask.js +71 -0
  210. package/dist/sdk/payment/security-code-mask.js.map +1 -0
  211. package/dist/sdk/payment/submission-registry.d.ts +33 -0
  212. package/dist/sdk/payment/submission-registry.js +58 -0
  213. package/dist/sdk/payment/submission-registry.js.map +1 -0
  214. package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
  215. package/dist/sdk/payment/use-payment-actions.js +276 -0
  216. package/dist/sdk/payment/use-payment-actions.js.map +1 -0
  217. package/dist/sdk/payment/use-place-order.d.ts +65 -0
  218. package/dist/sdk/payment/use-place-order.js +640 -0
  219. package/dist/sdk/payment/use-place-order.js.map +1 -0
  220. package/dist/sdk/shipping/use-shipping-actions.js +1 -1
  221. package/dist/utils/loggable-error-name.js +49 -0
  222. package/dist/utils/loggable-error-name.js.map +1 -0
  223. package/dist/utils/resolve-authored-copy.js +18 -0
  224. package/dist/utils/resolve-authored-copy.js.map +1 -0
  225. package/dist/utils/substitute-template.js +33 -0
  226. package/dist/utils/substitute-template.js.map +1 -0
  227. package/package.json +2 -1
  228. package/src/styles/tailwind.css +34 -0
  229. package/dist/docs/client-profile-form.md +0 -192
  230. package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
  231. package/dist/matter/client-profile-form/client-profile-form.js +0 -662
  232. package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  # ShippingAddress
2
2
 
3
3
  **Category:** commerce
4
- **Purpose:** Country-adaptive single-address delivery form. Batches all address fields and writes them once via `shipping.setAddress`; optionally lets a logged-in shopper pick a saved address instead of typing one.
4
+ **Purpose:** Country-adaptive single-address delivery form. Batches all address fields and dispatches them once, at form-submit time, via `shipping.setAddress`.
5
5
 
6
6
  ---
7
7
 
@@ -12,309 +12,164 @@ Use these signals to detect that a ShippingAddress block is present. Position on
12
12
  A ShippingAddress block contains any combination of:
13
13
 
14
14
  - A **country dropdown** listing country names (e.g. "Brazil", "United States").
15
- - An optional **"select a saved address"** button (drawer trigger) — shown only for logged-in shoppers; opens a drawer listing saved addresses to select quickly without typing the full form.
16
- - A list of **saved-address options** above or alongside the form, each rendered as a radio button or selectable card showing a street + number summary — shown only for logged-in shoppers (in the drawer or inline).
17
15
  - Labeled **input fields** for street, number, city, state, and postal code.
18
16
  - A **recipient name** field, often showing a pre-filled name as its value.
19
17
  - An optional **"Complement"** field (apartment, suite, unit).
20
18
  - A **"Neighborhood"** field — present only for Brazil-shaped forms, absent for US-shaped forms.
21
- - A **"Save address"** (or similar) submit button, possibly showing a "Saving..." pending label.
22
- - An **error banner** with either a specific validation message (e.g. "Saved address is no longer available") or a generic retry message (e.g. "We couldn't save this address. Please review and retry.").
19
+ - A **submit button** shared with the rest of the page's form, possibly showing a pending label while a write is in flight.
20
+ - An **error banner** showing domain validation messages or a generic failure state.
23
21
 
24
- If the image shows **any one** of the above, use `ShippingAddressRoot`. Pick only the sub-components that match what's visible — never include a sub-component for data that isn't shown.
22
+ If the image shows **any one** of the above, use `ShippingAddressFieldset` inside a `FormRoot`. Pick only the sub-components that match what's visible — never include a sub-component for data that isn't shown.
25
23
 
26
24
  ---
27
25
 
28
26
  ## When to use
29
27
 
30
28
  - The delivery/shipping step of checkout where a shopper enters or confirms a single delivery address for the whole order.
31
- - Anywhere a shopper needs to choose between a saved address and a manually-entered one before proceeding to delivery-option selection.
29
+ - Composed alongside other entities (e.g. the shopper's profile) behind one shared submit button.
32
30
 
33
31
  ## When NOT to use
34
32
 
35
33
  - Address autocomplete, postal-code lookup, or search-as-you-type flows — this form is manual entry only; no lookup provider is wired in.
36
- - Profile management screens (editing a shopper's saved addresses in account settings) — this form is order-scoped; selecting or editing a saved address here never writes back to the saved profile.
34
+ - Profile management screens (editing a shopper's saved addresses in account settings) — this form is order-scoped.
37
35
  - Per-item / per-line delivery address selection — this component addresses the whole cart with one address, not split shipments.
38
36
  - The delivery-options (shipping method) selection step → that is a separate section that extends the same `shipping` action namespace with `selectOption`.
37
+ - Letting a logged-in shopper pick from a list of saved addresses — there is no saved-address UI in this catalog; every address is typed into the form.
39
38
 
40
39
  ---
41
40
 
42
41
  ## Composition
43
42
 
44
- `ShippingAddressRoot` is the only entry point. All Controls, the saved-address list, the submit, and the error banner must be descendants of it.
45
-
46
- The **summary/form toggle** (`EditController`, `SummaryView`, `EditForm`, `EditButton`) is an optional composable layer that splits the Controls and SelectedSummary into a summary branch and a form branch, letting a shopper review a saved address before deciding to edit it. There is one component per state rather than one component taking a state name, so a page cannot misspell the state it means. See the dedicated section below.
43
+ `ShippingAddressFieldset` is the only entry point, and it must be a descendant of `FormRoot`. Compose `FormSubmit`/`FormError` as siblings of the fieldset, not inside it — the fieldset renders no submit or error part of its own.
47
44
 
48
45
  ```
49
- ShippingAddressRoot
50
- ├── EditController (optional; owns the summary/form state; compose its two panels inside)
51
- │ ├── SummaryView (optional; renders only while the section shows the summary)
52
- │ │ ├── SelectedSummary (read-only formatted address)
53
- │ │ └── EditButton (CTA to open the form)
54
- │ └── EditForm (optional; renders only while the section shows the form)
55
- │ ├── [form controls/submit/error]
56
- │ └── CancelButton (returns to the summary without writing)
57
- ├── CountryControl (selector; lists only countries with a descriptor)
58
- ├── SavedAddressDrawerController (optional; wraps a DrawerRoot for the saved-address selection drawer — US-8)
59
- │ └── DrawerRoot (generic Drawer particle; composed directly, no wrapper)
60
- │ ├── DrawerTrigger (button labeled "selecione um endereço salvo", etc.)
61
- │ └── DrawerPortal
62
- │ ├── DrawerBackdrop
63
- │ └── DrawerPopup
64
- │ ├── DrawerTitle
65
- │ ├── DrawerClose
66
- │ ├── SavedList (renders only when savedAddresses is non-empty)
67
- │ │ └── SavedOption (one per saved address; id required; isCurrent variant marks current address)
68
- │ ├── Error
69
- │ └── SavedAddressSubmit (dispatches drawer submit; no-op if reselecting current address — US-8)
70
- ├── RecipientNameControl (required; defaults from ClientProfile)
71
- ├── StreetControl
72
- ├── NumberControl
73
- ├── ComplementControl
74
- ├── NeighborhoodControl (renders only for countries whose descriptor includes it, e.g. Brazil)
75
- ├── CityControl
76
- ├── StateControl
77
- ├── PostalCodeControl
78
- ├── SavedList (optional; renders only when savedAddresses is non-empty)
79
- │ └── SavedOption (one per saved address; id required)
80
- ├── Submit (dispatches the batched write; exposes pending state)
81
- ├── SelectedSummary (optional; read-only formatted current address; self-gates to null when there is none)
82
- └── Error (domain userErrors inline, or a generic upstream-error state)
46
+ FormRoot
47
+ ├── ShippingAddressFieldset
48
+ │ ├── CountryControl (selector; lists only countries with a descriptor)
49
+ │ ├── RecipientNameControl (required; defaults from ClientProfile)
50
+ │ ├── StreetControl
51
+ │ ├── NumberControl
52
+ │ ├── ComplementControl
53
+ │ ├── NeighborhoodControl (renders only for countries whose descriptor includes it, e.g. Brazil)
54
+ │ ├── CityControl
55
+ │ └── StateControl / PostalCodeControl
56
+ ├── FormError (sibling of the fieldset, not a child)
57
+ └── FormSubmit (sibling of the fieldset, not a child)
83
58
  ```
84
59
 
85
60
  Child order reflects visual order — place Controls in the same sequence they appear in the image. The country descriptor also governs field order (see Common mistakes for what happens when a field is descriptor-less for the active country).
86
61
 
87
62
  **Composition rules:**
88
63
 
89
- - Every Control, `SavedList`, `Submit`, `SelectedSummary`, and `Error` must be a descendant of `ShippingAddressRoot` — each throws if rendered outside it.
90
- - `SavedAddressDrawerController` (optional, US-8) wraps a `DrawerRoot` and must be a descendant of `ShippingAddressRoot`. The drawer trigger and popup (including `SavedList`, `SavedAddressSubmit`, and error/state) are `DrawerRoot` descendants inside `SavedAddressDrawerController`.
91
- - `SavedOption` must be a descendant of `SavedList` (which itself renders only when `savedAddresses` is non-empty).
92
- - `SavedAddressSubmit` (US-8) must be a descendant of the `SavedAddressDrawerController`'s `DrawerRoot` (typically inside `DrawerPopup`).
64
+ - Every Control must be a descendant of `ShippingAddressFieldset` — each throws if rendered outside it.
65
+ - `ShippingAddressFieldset` must be a descendant of `FormRoot` — it throws its own named error otherwise.
93
66
  - `NeighborhoodControl` renders `null` when the active country's descriptor omits it (e.g. United States in v1) — safe to include speculatively, but only place it in the schema if the target country is expected to show it.
94
- - Only one `ShippingAddressRoot` per section; do not nest a second one inside it.
67
+ - Only one `ShippingAddressFieldset` per `FormRoot`; a second one under the same `shippingAddress` namespace throws at mount.
95
68
 
96
69
  ---
97
70
 
98
71
  ## Components
99
72
 
100
- ### ShippingAddressRoot
73
+ ### ShippingAddressFieldset
101
74
 
102
- Root container. Owns the batched draft state (keyed by canonical field name, not by descriptor), the current country descriptor, saved-address list, submit/error state, and provides context to all descendants. Declares `actions: { shipping: ['setAddress'] }`.
75
+ Registers under the `shippingAddress` namespace with an ancestor `FormRoot`; renders one `<fieldset>` and no submit or error part of its own — compose `FormSubmit`/`FormError` as siblings of the fieldset instead of inside it. Declares `actions: { shipping: ['setAddress'] }`.
103
76
 
104
77
  | Prop | Type | Default | Notes |
105
78
  |------|------|---------|-------|
106
79
  | `defaultCountry` | string | `"BRA"` | ISO alpha-3 country code used when no address exists yet |
80
+ | `skeletonCount` | number | `9` | Placeholder rows drawn while the address resolves. Set it to the number of Controls composed. |
81
+ | `loadingLabel` | string | `"Loading your delivery address"` | Announced politely while the address resolves. Blank means no announcement. |
82
+ | `loadedLabel` | string | `"Your delivery address is ready"` | Announced politely once the Controls mount. Blank means no announcement. |
83
+ | `groupLabel` | string | `"Your delivery address"` | Accessible name of the `<fieldset>` group. Blank means no name is exposed. |
107
84
 
108
- **Data:** declares `fragment ShippingAddressData on Query` (`shipping { address savedAddresses }` + `clientProfile { firstName lastName }`), `fetchStrategy: 'reactive'`. The compiler merges it into the page query — no explicit `dataSources` entry needed.
109
-
110
- ### RecipientNameControl
111
-
112
- The recipient-name input. The only client-validated field: submit is blocked while it is blank. Defaults from `clientProfile.firstName`/`lastName` (joined) as a real, editable value — not a placeholder hint — whenever the address (current or a selected saved address) has no recipient name yet; degrades to an empty required field when the profile has neither part. No props beyond `className`.
113
-
114
- ### StreetControl / NumberControl / CityControl / StateControl / PostalCodeControl / ComplementControl
115
-
116
- Thin field Controls; each renders `null` when the active country's descriptor omits that field. No props beyond `className`.
117
-
118
- ### NeighborhoodControl
119
-
120
- Same shape as the other field Controls. Renders only for countries whose descriptor includes a neighborhood field (Brazil in v1); renders `null` for others (United States in v1). Its draft value is retained (not cleared) when hidden, so it reappears with the same value if the shopper switches back to a country that shows it.
121
-
122
- ### CountryControl
123
-
124
- Country selector. Lists only countries with an implemented descriptor (Brazil and United States in v1) — a descriptor-less country is unreachable. Switching country preserves the values of fields the two descriptors share (keyed by canonical field name) and only adds/removes country-specific fields. Disabled while a submit is in flight. No props beyond `className`.
125
-
126
- ### SavedList
127
-
128
- Container for saved-address options. Renders only when `savedAddresses` is non-empty — this is the logged-in signal; anonymous shoppers get an empty list and the container renders nothing. No props beyond `className`.
129
-
130
- ### SavedOption
131
-
132
- A single selectable saved address. Selecting it populates the batched draft (still editable before submit) and retains its ID through submit so VTEX maintains the saved-address reference for this order.
133
-
134
- Renders the saved address using the same formatted display as `SelectedSummary` — both compose the `AddressSummary` particle (recipient, street/number/complement, neighborhood/city/state/postal code) via its own `AddressSummaryRoot` context provider, so they share one formatting implementation without code duplication. Falls back to a generic "Endereço {id}" label only when the saved record has no recognizable content (no recipient name, street, city, or neighborhood).
135
-
136
- Includes an `isCurrent` state: when the saved address's ID matches `currentAddressId` (the current cart address), it renders the `data-fs-shipping-address-saved-option-current` attribute, signaling that this is the already-selected delivery address. The component renders no default visual styling for this state itself — it's a pure styling hook, left to the merchant/page to style (or not) via that attribute.
85
+ **Data:** declares `fragment ShippingAddressFieldsetData on Query` (`shipping { address }` + `clientProfile { id firstName lastName }`), `fetchStrategy: 'reactive'`. The compiler merges it into the page query — no explicit `dataSources` entry needed.
137
86
 
138
- | Prop | Type | Default | Notes |
139
- |------|------|---------|-------|
140
- | `id` | string | — | Required. The saved address's ID; must match an entry in `savedAddresses` |
141
-
142
- ### SavedAddressDrawerController
143
-
144
- Wraps a single `DrawerRoot` child (the saved-address selection drawer) and makes it controlled by a dedicated drawer-flow context, kept separate from the main `ShippingAddressContext` that every field Control reads (so the Root's data/actions context stays unaware of this one downstream UI surface). Open state and blocked dismissal while submitting are handled here. Do not set raw `open` or `onOpenChange` on the wrapped `DrawerRoot` — pass them through `SavedAddressDrawerController` instead (the same pattern as `CartOpenOnAdd` in the mini-cart).
145
-
146
- Blocks drawer dismissal (Escape, backdrop click, close button) while a drawer submit is in flight (`drawerSubmitting` is true) to prevent accidental loss of an in-flight submission.
87
+ **Loading:** the Controls mount once, after the entity has resolved; until then the `<fieldset>` carries `data-fs-shipping-address-fieldset-pending` and renders `ShippingAddressFieldsetSkeleton` itself, in their place. Each Control hands its seed to react-hook-form as a field-level `defaultValue`, re-applied on every render for as long as the field stays clean — mounting before the answer arrives would seed `''`, and a shopper who starts typing before it lands makes the field dirty on that empty seed, permanently locking their saved address out of it; even a shopper who does not type sees the field flash from `''` to the real data. Resolution is the page query settling, latched, and this entity actually resolving: a later refetch never takes the Controls down, so nothing the shopper typed is lost, but if the entity itself stops resolving the fieldset returns to its skeleton and dispatches nothing until it resolves again.
147
88
 
148
- | Prop | Type | Default | Notes |
149
- |------|------|---------|-------|
150
- | `children` | ReactNode | — | Required. A single `DrawerRoot` element; other elements are passed through unchanged. |
89
+ `skeletonCount` sizes the wait. The skeleton draws nine rows by default, one per Control in the full anatomy, and it cannot do better on its own — it renders before any address exists, so there is no descriptor to read, and the composed Controls are opaque children. A page composing the eight BRA fields sets `skeletonCount: 8`, or the form jumps by a row when the Controls take the skeleton's place. The skeleton is `aria-hidden` — the wait is spoken instead by a polite live region the fieldset keeps mounted in both states, carrying `loadingLabel` and then `loadedLabel`, with `aria-busy` on the `<fieldset>` for as long as it lasts.
151
90
 
152
91
  **Composition rules:**
92
+ - Must be a descendant of `FormRoot`; throws its own named error otherwise.
93
+ - Compose `FormSubmit` and `FormError` as siblings, not children — the fieldset renders no submit or error part.
94
+ - Only one `ShippingAddressFieldset` per `FormRoot`; a second one under the same `shippingAddress` namespace throws at mount.
153
95
 
154
- - Must be a descendant of `ShippingAddressRoot`.
155
- - Must be the parent of `DrawerRoot` (the drawer trigger and popup are `DrawerRoot` descendants).
156
- - The wrapped `DrawerRoot` must have `DrawerTrigger`, `DrawerPortal`, `DrawerBackdrop`, `DrawerPopup`, `DrawerTitle`, and `DrawerClose` descendants inside it, using the standard `Drawer` particle architecture.
157
-
158
- ### SavedAddressSubmit
159
-
160
- The drawer's "selecionar" (select) submit button; independent submitting state from the main form's `Submit` button (Decision 7 in the spec). Dispatches the drawer submit via `handleDrawerSubmit`.
161
-
162
- **Special behavior (Decision 8 in the spec):** when a saved address is selected and submitted, if it is already the current cart address (its ID matches `currentAddressId`), the drawer closes silently with no action — reselecting the current address is a no-op.
163
-
164
- **Special behavior (Decision 9 in the spec):** when the selected saved address has a blank `recipientName`, no mutation is dispatched either — the drawer closes and the main form (already populated with that address's fields, since selecting a saved option always seeds the draft) is left for the shopper to add the missing name and submit themselves, rather than auto-submitting into a guaranteed `MISSING_RECIPIENT_NAME` rejection.
165
-
166
- | Prop | Type | Default | Notes |
167
- |------|------|---------|-------|
168
- | `label` | string | `"selecionar"` | Button label shown when not submitting |
169
- | `pendingLabel` | string | `"selecionando..."` | Button label shown while the drawer submit is in flight |
170
-
171
- ### Submit
172
-
173
- Dispatches the batched write through `shipping.setAddress` exactly once per click, including when the shopper changed nothing: the component cannot tell whether the stored address would be accepted, so it lets the server decide rather than deciding on its behalf. Disabled while the recipient name is blank or a submit is already in flight; shows a pending label/attribute while in flight, and re-enables once the write resolves.
174
-
175
- | Prop | Type | Default | Notes |
176
- |------|------|---------|-------|
177
- | `label` | string | `"salvar endereço"` | Button label shown when not submitting |
178
- | `pendingLabel` | string | `"salvando..."` | Button label shown while the submit is in flight |
179
-
180
- ### SelectedSummary
96
+ **Overriding a control's text:** every field Control also takes optional `label` and `placeholder` props. Absence means the platform's value — the active country descriptor's label where one exists (e.g. "cidade" for `CityControl`), the control's own copy where none does (`CountryControl`'s "país"). Neither has a schema default, so an author only sets one when the platform copy is wrong for their store.
181
97
 
182
- Provides the current delivery address to the generic `AddressSummary` particle via `AddressSummaryRoot` context, and renders it by default. Self-gates to `null` when there is none yet (e.g. a first-time order with an empty `Shipping.address`), rather than an empty provider.
98
+ **Recomposing a control's anatomy:** every field Control declares `providesContext: 'field'` (RFC:503), so a `Field.*` part composed inside one is not a context-constraint-violation. Given children, a field Control renders them in place of its default `Field.Label` / `Field.Control` / `Field.Error` (or, for `CountryControl`, `Field.Label` / `FieldSelect.Root` / `Field.Error`) — useful to reorder the label against the input or insert an icon. The binding underneath is unchanged either way.
183
99
 
184
- The `AddressSummary` particle it composes displays the address in read-only format (recipient name, street/number/complement, neighborhood/city/state/postal code). `SavedOption` uses the same `AddressSummary` particle (with its own `AddressSummaryRoot`) so both the "current address" display and each saved-address option in the list/drawer share one formatting implementation without duplication.
185
-
186
- A future alternative presentation component (e.g., `LeanAddressSummary`) could read the same `AddressSummaryRoot` context and be composed as a child, without any change to this component — exemplifying the Free Particle Model.
187
-
188
- | Prop | Type | Default | Notes |
189
- |------|------|---------|-------|
190
- | `className` | string | — | Optional CSS classes applied to the `AddressSummary` container, whether the lines are the default ones or composed |
191
- | `children` | ReactNode | — | Optional line composition, rendered *inside* the `AddressSummary` container in place of its default lines. Must be a descendant of the provided `AddressSummaryRoot` context. |
192
-
193
- ### EditController
194
-
195
- Optional composable component that owns the summary/form toggle. Opens on the summary when a current address exists, on the form otherwise. When a successful `setAddress` completes (via the main form's `Submit` or the drawer's `SavedAddressSubmit`), it returns to the summary on its own without either submit component needing to know this section collapses around it (mirrors the `cartLastAddVar` pulse-signal pattern in the mini-cart). Everything it does it decides from its own data and the shopper's own presses; it reports to nothing, so finishing it opens no other section, and no other section opens it.
196
-
197
- Once a shopper explicitly opens the form (via `EditButton`), the explicit choice takes over until either a successful submit or a press of `CancelButton` returns the section to the summary. Does not render any DOM itself; wraps children and provides the `shipping-address-section` context to descendant `SummaryView`, `EditForm`, `EditButton` and `CancelButton` components.
198
-
199
- | Prop | Type | Default | Notes |
200
- |------|------|---------|-------|
201
- | `children` | ReactNode | — | Required. Typically holds a `SummaryView` and an `EditForm`. |
202
-
203
- **Composition rules:**
204
- - Must be a descendant of `ShippingAddressRoot`.
205
- - Typically wraps the whole delivery-address section (all form Controls, Submit, Error, SelectedSummary) so all of it can be split between the two panels.
206
- - Compose `SummaryView` and `EditForm` children to place the parts that belong to each state.
207
-
208
- ### SummaryView / EditForm
209
-
210
- The section's two panels. `SummaryView` renders its children only while the section shows the saved-address summary; `EditForm` only while it shows the editable form. Neither takes a state prop — which state it gates is which component it is, so a page cannot name a state that has no branch and blank the section.
211
-
212
- | Prop | Type | Default | Notes |
213
- |------|------|---------|-------|
214
- | `children` | ReactNode | — | Rendered only while the section is in this component's state. |
215
-
216
- **Composition rules:**
217
- - Both must be descendants of `EditController`.
218
- - Typically, `SummaryView` holds `SelectedSummary` + `EditButton` (read-only branch) and `EditForm` holds the form Controls, Submit, Error, and `CancelButton`.
219
-
220
- ### EditButton
100
+ ### RecipientNameControl
221
101
 
222
- CTA that opens the form. Has no knowledge of why the section might currently be on the summary (a current address exists, or a just-completed submit returned to it) — it only writes the state forward. Usually placed inside a `SummaryView`, next to `SelectedSummary`.
102
+ The recipient-name input. The only required field: submit is blocked while it is blank. Defaults from `clientProfile.firstName`/`lastName` (joined) as a real, editable value — not a placeholder hint — whenever the stored address has no recipient name yet; degrades to an empty required field when the profile has neither part. No props beyond `className`, `label`, `placeholder`.
223
103
 
224
- | Prop | Type | Default | Notes |
225
- |------|------|---------|-------|
226
- | `label` | string | `"editar"` | Button label shown when no children are composed |
227
-
228
- ### CancelButton
104
+ ### StreetControl / NumberControl / CityControl / StateControl / PostalCodeControl / ComplementControl
229
105
 
230
- Returns the section to its summary without writing. Compose it inside the `EditForm` whenever the
231
- `EditButton` is reachable: a shopper who opens the form otherwise has no way back except a successful
232
- `setAddress`, and blanking the recipient name disables Submit, which strands them on a form covering the
233
- summary they came from.
106
+ Thin field Controls; each renders `null` when the active country's descriptor omits that field. `PostalCodeControl` is additionally client-validated against the active country's format (CEP for Brazil, ZIP/ZIP+4 for the United States) — a malformed value blocks submit even though the field is not required. No props beyond `className`, `label`, `placeholder`.
234
107
 
235
- | Prop | Type | Default | Notes |
236
- |------|------|---------|-------|
237
- | `label` | string | `"cancelar"` | Button label shown when no children are composed |
238
- | `children` | ReactNode | — | Custom content, e.g. an `Icon` plus text; falls back to `label` |
239
- | `className` | string | — | Optional CSS classes |
108
+ ### NeighborhoodControl
240
109
 
241
- **Composition rules:**
242
- - Must be a descendant of `EditController`.
243
- - Compose it inside the `EditForm`. Inside a `SummaryView` it renders only while the form is closed,
244
- which is precisely when there is nothing to cancel.
110
+ Same shape as the other field Controls. Renders only for countries whose descriptor includes a neighborhood field (Brazil in v1); renders `null` for others (United States in v1). Its draft value is retained (not cleared) when hidden, so it reappears with the same value if the shopper switches back to a country that shows it.
245
111
 
246
- ### Error
112
+ ### CountryControl
247
113
 
248
- Renders domain `userErrors` returned by `setAddress` (e.g. `MISSING_RECIPIENT_NAME`, `INVALID_SAVED_ADDRESS_ID`) as an inline list, or a single generic message when the mutation throws (surfaced as a synthetic upstream/network error). Form values are retained in either case. No props beyond `className`.
114
+ Country selector. Lists only countries with an implemented descriptor (Brazil and United States in v1) — a descriptor-less country is unreachable. Switching country preserves the values of fields the two descriptors share (keyed by canonical field name) and only adds/removes country-specific fields. No props beyond `className`, `label`, `placeholder`.
249
115
 
250
116
  ---
251
117
 
252
118
  ## Canonical schema example
253
119
 
254
- A full delivery-address step with saved addresses, all field Controls, and the error/submit pair:
120
+ The nine field Controls, batched behind a form-level submit:
255
121
 
256
122
  ```json
257
123
  {
258
- "shipping-address": {
259
- "type": "ShippingAddressRoot",
260
- "props": { "defaultCountry": "BRA" },
124
+ "checkout-form": {
125
+ "type": "FormRoot",
126
+ "children": ["shipping-address-fieldset", "form-error", "form-submit"]
127
+ },
128
+ "shipping-address-fieldset": {
129
+ "type": "ShippingAddressFieldset",
261
130
  "children": [
262
- "shipping-address-saved-list",
263
- "shipping-address-country",
264
- "shipping-address-recipient",
265
- "shipping-address-street",
266
- "shipping-address-number",
267
- "shipping-address-complement",
268
- "shipping-address-neighborhood",
269
- "shipping-address-city",
270
- "shipping-address-state",
271
- "shipping-address-postal-code",
272
- "shipping-address-error",
273
- "shipping-address-submit"
131
+ "fieldset-country",
132
+ "fieldset-recipient",
133
+ "fieldset-street",
134
+ "fieldset-number",
135
+ "fieldset-complement",
136
+ "fieldset-neighborhood",
137
+ "fieldset-city",
138
+ "fieldset-state",
139
+ "fieldset-postal-code"
274
140
  ]
275
141
  },
276
- "shipping-address-saved-list": {
277
- "type": "ShippingAddressSavedList",
278
- "children": ["shipping-address-saved-option"]
279
- },
280
- "shipping-address-saved-option": {
281
- "type": "ShippingAddressSavedOption",
282
- "props": { "id": "addr-1" }
283
- },
284
- "shipping-address-country": { "type": "ShippingAddressCountryControl" },
285
- "shipping-address-recipient": { "type": "ShippingAddressRecipientNameControl" },
286
- "shipping-address-street": { "type": "ShippingAddressStreetControl" },
287
- "shipping-address-number": { "type": "ShippingAddressNumberControl" },
288
- "shipping-address-complement": { "type": "ShippingAddressComplementControl" },
289
- "shipping-address-neighborhood": { "type": "ShippingAddressNeighborhoodControl" },
290
- "shipping-address-city": { "type": "ShippingAddressCityControl" },
291
- "shipping-address-state": { "type": "ShippingAddressStateControl" },
292
- "shipping-address-postal-code": { "type": "ShippingAddressPostalCodeControl" },
293
- "shipping-address-error": { "type": "ShippingAddressError" },
294
- "shipping-address-submit": {
295
- "type": "ShippingAddressSubmit",
296
- "props": { "label": "Save address" }
297
- }
142
+ "fieldset-country": { "type": "ShippingAddressCountryControl" },
143
+ "fieldset-recipient": { "type": "ShippingAddressRecipientNameControl" },
144
+ "fieldset-street": { "type": "ShippingAddressStreetControl" },
145
+ "fieldset-number": { "type": "ShippingAddressNumberControl" },
146
+ "fieldset-complement": { "type": "ShippingAddressComplementControl" },
147
+ "fieldset-neighborhood": { "type": "ShippingAddressNeighborhoodControl" },
148
+ "fieldset-city": { "type": "ShippingAddressCityControl" },
149
+ "fieldset-state": { "type": "ShippingAddressStateControl" },
150
+ "fieldset-postal-code": { "type": "ShippingAddressPostalCodeControl" },
151
+ "form-error": { "type": "FormError" },
152
+ "form-submit": { "type": "FormSubmit", "props": { "label": "Continue" } }
298
153
  }
299
154
  ```
300
155
 
301
- ### Minimal variant (manual entry only, no saved addresses visible)
156
+ ### Minimal variant (manual entry only)
302
157
 
303
158
  ```json
304
159
  {
305
- "shipping-address": {
306
- "type": "ShippingAddressRoot",
307
- "children": [
308
- "shipping-address-recipient",
309
- "shipping-address-street",
310
- "shipping-address-postal-code",
311
- "shipping-address-submit"
312
- ]
160
+ "checkout-form": {
161
+ "type": "FormRoot",
162
+ "children": ["shipping-address-fieldset", "form-submit"]
313
163
  },
314
- "shipping-address-recipient": { "type": "ShippingAddressRecipientNameControl" },
315
- "shipping-address-street": { "type": "ShippingAddressStreetControl" },
316
- "shipping-address-postal-code": { "type": "ShippingAddressPostalCodeControl" },
317
- "shipping-address-submit": { "type": "ShippingAddressSubmit" }
164
+ "shipping-address-fieldset": {
165
+ "type": "ShippingAddressFieldset",
166
+ "props": { "skeletonCount": 3 },
167
+ "children": ["fieldset-recipient", "fieldset-street", "fieldset-postal-code"]
168
+ },
169
+ "fieldset-recipient": { "type": "ShippingAddressRecipientNameControl" },
170
+ "fieldset-street": { "type": "ShippingAddressStreetControl" },
171
+ "fieldset-postal-code": { "type": "ShippingAddressPostalCodeControl" },
172
+ "form-submit": { "type": "FormSubmit" }
318
173
  }
319
174
  ```
320
175
 
@@ -322,37 +177,40 @@ A full delivery-address step with saved addresses, all field Controls, and the e
322
177
 
323
178
  ## Common mistakes
324
179
 
325
- - **Inventing `ShippingAddressSaveOption`.** The correct name is `ShippingAddressSavedOption`.
326
- - **Inventing `ShippingAddressForm`.** There is no separate `Form` sub-component — `ShippingAddressRoot` is the form container.
327
- - **Putting `SavedOption` directly under `ShippingAddressRoot`.** It must be inside `SavedList`, which itself only renders when `savedAddresses` is non-empty.
180
+ - **Inventing a `ShippingAddressRoot`, `ShippingAddressSubmit` or `ShippingAddressError`.** There is no standalone root or submit/error part for this entity — `ShippingAddressFieldset` is the only entry point, and the shared `FormSubmit`/`FormError` cover submit and errors.
181
+ - **Inventing a saved-address list or drawer.** There is no saved-address UI in this catalog; every address is typed into the form.
328
182
  - **Including `NeighborhoodControl` for a form that only ever shows US fields.** It renders `null` for countries without a neighborhood field, but including it still signals wrong intent when the image never shows it.
329
- - **Assuming this form writes back to the shopper's saved-address book.** It never does — edits, including edits to a selected saved address, apply to this order only.
330
- - **Using this component for address autocomplete or postal-code-only entry.** No lookup provider is wired in; all fields are manual, and field-format validation is deferred to the backend.
331
- - **Placing field Controls outside `ShippingAddressRoot`.** Every Control throws if rendered without an ancestor `ShippingAddressRoot`.
183
+ - **Assuming this form writes back to the shopper's saved-address book.** It never does — it writes the order's own address only.
184
+ - **Using this component for address autocomplete or postal-code-only entry.** No lookup provider is wired in; all fields are manual, and the postal code's format is validated on the client against the active country's descriptor — it is not deferred to the backend.
185
+ - **Placing field Controls outside `ShippingAddressFieldset`.** Every Control throws if rendered without an ancestor `ShippingAddressFieldset`.
186
+ - **Composing `ShippingAddressFieldset` outside a `FormRoot`.** It throws its own named error at mount rather than rendering an inert form region.
187
+ - **Composing `FormSubmit`/`FormError` inside `ShippingAddressFieldset`.** They are siblings of the fieldset, not children — the fieldset renders no submit or error part of its own.
332
188
 
333
189
  ---
334
190
 
335
191
  ## Styling
336
192
 
337
- Style `ShippingAddressRoot` as a vertical form stack; field Controls each pair a label above an input. Saved-address options read as a short selectable list above the manual-entry fields.
193
+ Field Controls each pair a label above an input.
338
194
 
339
195
  | Component | What you style | Plausible classes |
340
196
  |---|---|---|
341
- | `ShippingAddressRoot` | Stacks the whole form vertically | `flex flex-col gap-[16px] w-full` |
342
197
  | Field Controls (`RecipientNameControl`, `StreetControl`, `NumberControl`, `CityControl`, `StateControl`, `PostalCodeControl`, `ComplementControl`, `NeighborhoodControl`, `CountryControl`) | Label-above-input field wrapper | `flex flex-col gap-[6px]` |
343
- | `ShippingAddressSavedList` | Stacks saved-address options with spacing between them | `flex flex-col gap-[8px] mb-[16px]` |
344
- | `ShippingAddressSavedOption` | A single selectable row: radio + summary label | `flex items-center gap-[8px] rounded-[6px] border border-[#E2E2E2] p-[12px]` |
345
- | `ShippingAddressSubmit` | The primary call-to-action button | `px-[16px] py-[10px] bg-[#1D4ED8] text-white font-semibold rounded-[6px] disabled:opacity-50` |
346
- | `ShippingAddressError` | Inline error/alert banner | `rounded-[6px] border border-[#FCA5A5] bg-[#FEF2F2] p-[12px] text-[13px] text-[#991B1B]` |
198
+ | `ShippingAddressFieldsetSkeleton` | `data-fs-shipping-address-fieldset-skeleton` and its `-skeleton-field` rows, `skeletonCount` of them | `flex flex-col gap-[16px]`, rows `h-[44px] rounded-[6px] bg-[#F0F0F0] animate-pulse` |
199
+ | Fieldset announcement | `data-fs-shipping-address-fieldset-announcement` reaches the live region carrying `loadingLabel`/`loadedLabel`. Hide it with a clipping technique, never `display:none` — that drops it from the accessibility tree and defeats the announcement | `sr-only` |
347
200
 
348
- Styled minimal example (recipient name + street + submit):
201
+ Styled minimal example (recipient name + street, shared submit):
349
202
 
350
203
  ```json
351
204
  {
352
- "shipping-address": {
353
- "type": "ShippingAddressRoot",
354
- "children": ["shipping-address-recipient", "shipping-address-street", "shipping-address-submit"],
355
- "style": ["flex", "flex-col", "gap-[16px]", "w-full"]
205
+ "checkout-form": {
206
+ "type": "FormRoot",
207
+ "children": ["shipping-address-fieldset", "form-submit"]
208
+ },
209
+ "shipping-address-fieldset": {
210
+ "type": "ShippingAddressFieldset",
211
+ "props": { "skeletonCount": 2 },
212
+ "style": ["flex", "flex-col", "gap-[16px]", "w-full"],
213
+ "children": ["shipping-address-recipient", "shipping-address-street"]
356
214
  },
357
215
  "shipping-address-recipient": {
358
216
  "type": "ShippingAddressRecipientNameControl",
@@ -362,8 +220,8 @@ Styled minimal example (recipient name + street + submit):
362
220
  "type": "ShippingAddressStreetControl",
363
221
  "style": ["flex", "flex-col", "gap-[6px]"]
364
222
  },
365
- "shipping-address-submit": {
366
- "type": "ShippingAddressSubmit",
223
+ "form-submit": {
224
+ "type": "FormSubmit",
367
225
  "props": { "label": "Save address" },
368
226
  "style": ["px-[16px]", "py-[10px]", "bg-[#1D4ED8]", "text-white", "font-semibold", "rounded-[6px]"]
369
227
  }
@@ -374,17 +232,11 @@ Styled minimal example (recipient name + street + submit):
374
232
 
375
233
  ## Known gaps
376
234
 
377
- Found by review and deliberately left for the dedicated revision of these components, rather than patched
378
- here. Read this before assuming a behaviour is intentional.
235
+ Found by review and deliberately left for the dedicated revision of these components, rather than patched here. Read this before assuming a behaviour is intentional.
379
236
 
380
- - **The controller and the summary disagree about what "has an address" means.** `EditController` derives its
381
- initial mode from `address.id` alone, while `SelectedSummary` gates on the formatted address object. An
382
- address carrying an `id` but almost no content — the shape a postcode-only shipping simulation returns —
383
- therefore opens on the summary and renders a near-empty one, with no form and no way to complete it. The
384
- inverse also fails: an address object with `id: null` holds the section in `edit` forever, so a successful
385
- save never collapses it.
237
+ - **There is no view/edit toggle for this section.** A page that wants a summary-first delivery section, reviewed before the shopper commits to editing it, has no composable component here for that — the fieldset always renders its form.
386
238
 
387
239
  ## Related
388
240
 
389
- - [[client-profile-form]] — collects identity fields (first name, phone, email) that feed the recipient-name default here. Distinct block; do not nest.
241
+ - [[client-profile-fieldset]] — collects identity fields (first name, phone) that feed the recipient-name default here. Distinct block; do not nest.
390
242
  - [[shipping-simulator]] — a separate delivery-estimate/rate lookup surface keyed by postal code, used before an address is saved. `ShippingAddress` persists the full address for the order; `ShippingSimulator` only estimates rates for a candidate postal code.
package/dist/index.d.ts CHANGED
@@ -8,6 +8,9 @@ import { CartUserError } from "./sdk/cart/operations.js";
8
8
  import { AddItemPayload, CartActions, CartCouponPayload, CartLinePayload, CartLinesPayload, CartQuantityPayload } from "./sdk/cart/use-cart-actions.js";
9
9
  import { ClientPreferenceKey, ClientProfileUserError, CustomerProfileUserError } from "./sdk/identity/operations.js";
10
10
  import { ClientPreferencesUpdatePayload, ClientProfileUpdatePayload, CustomerProfileUpdatePayload, IdentityActions } from "./sdk/identity/use-identity-actions.js";
11
+ import { PaymentBillingAddressUpdateInput, PaymentMethodSelectInput, PaymentMoney, PaymentUserError } from "./sdk/payment/operations.js";
12
+ import { PaymentGatewayCard, PaymentGatewayNewCard, PaymentGatewaySavedCard, PaymentGatewayTransaction, SendPaymentsRequest } from "./sdk/payment/gateway.js";
13
+ import { PaymentActions, PaymentGatewayCallbackResult, PaymentStartTransactionResult } from "./sdk/payment/use-payment-actions.js";
11
14
  import { RegionUserError } from "./sdk/region/region-operations.js";
12
15
  import { RegionActions } from "./sdk/region/use-region-actions.js";
13
16
  import { SessionAccessCodeRequestResult, SessionPasswordLoginPayload, SessionRequestAccessCodePayload, SessionUserError, SessionValidateAccessCodePayload } from "./sdk/session/auth-operations.js";
@@ -16,4 +19,4 @@ import { ShippingOptionSelectUserError } from "./sdk/shipping/option-select-oper
16
19
  import { ShippingAddressInput, ShippingAddressUpdateErrorEntity } from "./sdk/shipping/shipping-operations.js";
17
20
  import { ShippingActions } from "./sdk/shipping/use-shipping-actions.js";
18
21
  import { ComponentActions } from "./sdk/actions/types.js";
19
- export { type ActionSelector, type AddItemPayload, type CartActions, type CartCouponPayload, type CartLinePayload, type CartLinesPayload, type CartQuantityPayload, type CartUserError, type ClientPreferenceKey, type ClientPreferencesUpdatePayload, type ClientProfileUpdatePayload, type ClientProfileUserError, type ComponentActions, type ComponentDefinition, type ContentArraySchema, type ContentNestedObjectShape, type ContentObjectPropertySchema, type ContentObjectSchema, type ContentPropertySchema, type ContentPropertyType, type ContentScalarSchema, type ContentScalarType, type ContentTypeDefinition, type ContentValue, type CustomerProfileUpdatePayload, type CustomerProfileUserError, type EditorMetadata, type FetchStrategy, type IdentityActions, type JsonValue, type MockActions, type PropSchema, type PropSchemaField, type PropType, type RegionActions, type RegionUserError, type SessionAccessCodeRequestResult, type SessionActions, type SessionPasswordLoginPayload, type SessionRequestAccessCodePayload, type SessionUserError, type SessionValidateAccessCodePayload, type ShippingActions, type ShippingAddressInput, type ShippingAddressUpdateErrorEntity, type ShippingOptionSelectUserError, type StorefrontContext, defineComponent, defineContentType, mockAction };
22
+ export { type ActionSelector, type AddItemPayload, type CartActions, type CartCouponPayload, type CartLinePayload, type CartLinesPayload, type CartQuantityPayload, type CartUserError, type ClientPreferenceKey, type ClientPreferencesUpdatePayload, type ClientProfileUpdatePayload, type ClientProfileUserError, type ComponentActions, type ComponentDefinition, type ContentArraySchema, type ContentNestedObjectShape, type ContentObjectPropertySchema, type ContentObjectSchema, type ContentPropertySchema, type ContentPropertyType, type ContentScalarSchema, type ContentScalarType, type ContentTypeDefinition, type ContentValue, type CustomerProfileUpdatePayload, type CustomerProfileUserError, type EditorMetadata, type FetchStrategy, type IdentityActions, type JsonValue, type MockActions, type PaymentActions, type PaymentBillingAddressUpdateInput, type PaymentGatewayCallbackResult, type PaymentGatewayCard, type PaymentGatewayNewCard, type PaymentGatewaySavedCard, type PaymentGatewayTransaction, type PaymentMethodSelectInput, type PaymentMoney, type PaymentStartTransactionResult, type PaymentUserError, type PropSchema, type PropSchemaField, type PropType, type RegionActions, type RegionUserError, type SendPaymentsRequest, type SessionAccessCodeRequestResult, type SessionActions, type SessionPasswordLoginPayload, type SessionRequestAccessCodePayload, type SessionUserError, type SessionValidateAccessCodePayload, type ShippingActions, type ShippingAddressInput, type ShippingAddressUpdateErrorEntity, type ShippingOptionSelectUserError, type StorefrontContext, defineComponent, defineContentType, mockAction };
@@ -1,8 +1,10 @@
1
1
  import { MessageId, Messages } from "../sdk/i18n/locales.js";
2
2
  import "../sdk/i18n/client.js";
3
3
  import { gql } from "../sdk/graphql-tag.js";
4
+ import { AnalyticsActionProvider, AnalyticsActionProviderProps } from "../sdk/actions/analytics-action-provider.js";
4
5
  import { CartActionProvider, CartActionProviderProps } from "../sdk/actions/cart-action-provider.js";
5
6
  import { IdentityActionProvider, IdentityActionProviderProps } from "../sdk/actions/identity-action-provider.js";
7
+ import { PaymentActionProvider, PaymentActionProviderProps } from "../sdk/actions/payment-action-provider.js";
6
8
  import { RegionActionProvider, RegionActionProviderProps } from "../sdk/actions/region-action-provider.js";
7
9
  import { SessionActionProvider, SessionActionProviderProps } from "../sdk/actions/session-action-provider.js";
8
10
  import { ShippingActionProvider, ShippingActionProviderProps } from "../sdk/actions/shipping-action-provider.js";
@@ -21,4 +23,4 @@ import { StorefrontProvider, StorefrontProviderProps } from "../sdk/provider/sto
21
23
  import "../sdk/provider/index.js";
22
24
  import { cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, miniCartOpenVar, orderFormIdVar } from "../sdk/state/cart.js";
23
25
  import { SelectedVariant, publishedVariantIdFor, selectedVariantVar } from "../sdk/state/variant-selector.js";
24
- export { CartActionProvider, type CartActionProviderProps, type ClientVariablesMap, DataOverrideContext, HotDataProvider, type HotDataProviderProps, IdentityActionProvider, type IdentityActionProviderProps, type ListItemRef, ListItemRefContext, type MessageId, type Messages, MultipleReactiveDataProvider, type MultipleReactiveDataProviderEntity, type MultipleReactiveDataProviderProps, PageReactiveDataRoot, type PageReactiveDataRootProps, ReactiveDataProvider, type ReactiveDataProviderProps, ReactiveListItemDataProvider, type ReactiveListItemDataProviderProps, ReactiveRootContext, type ReactiveRootContextValue, RegionActionProvider, type RegionActionProviderProps, type SelectedVariant, SessionActionProvider, type SessionActionProviderProps, ShippingActionProvider, type ShippingActionProviderProps, StorefrontProvider, type StorefrontProviderProps, buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove, buildStorefrontContextHeaders, cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, gql, miniCartOpenVar, orderFormIdVar, publishedVariantIdFor, selectedVariantVar, useDataOverride, useListItemRef };
26
+ export { AnalyticsActionProvider, type AnalyticsActionProviderProps, CartActionProvider, type CartActionProviderProps, type ClientVariablesMap, DataOverrideContext, HotDataProvider, type HotDataProviderProps, IdentityActionProvider, type IdentityActionProviderProps, type ListItemRef, ListItemRefContext, type MessageId, type Messages, MultipleReactiveDataProvider, type MultipleReactiveDataProviderEntity, type MultipleReactiveDataProviderProps, PageReactiveDataRoot, type PageReactiveDataRootProps, PaymentActionProvider, type PaymentActionProviderProps, ReactiveDataProvider, type ReactiveDataProviderProps, ReactiveListItemDataProvider, type ReactiveListItemDataProviderProps, ReactiveRootContext, type ReactiveRootContextValue, RegionActionProvider, type RegionActionProviderProps, type SelectedVariant, SessionActionProvider, type SessionActionProviderProps, ShippingActionProvider, type ShippingActionProviderProps, StorefrontProvider, type StorefrontProviderProps, buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove, buildStorefrontContextHeaders, cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, gql, miniCartOpenVar, orderFormIdVar, publishedVariantIdFor, selectedVariantVar, useDataOverride, useListItemRef };
@@ -6,8 +6,10 @@ import { cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, miniCartOpenVar
6
6
  import { buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove } from "../sdk/cart/optimistic.js";
7
7
  import { ListItemRefContext, useListItemRef } from "../sdk/data/list-item-ref-context.js";
8
8
  import { PageReactiveDataRoot, ReactiveRootContext } from "../sdk/data/page-reactive-data-root.js";
9
+ import { AnalyticsActionProvider } from "../sdk/actions/analytics-action-provider.js";
9
10
  import { CartActionProvider } from "../sdk/actions/cart-action-provider.js";
10
11
  import { IdentityActionProvider } from "../sdk/actions/identity-action-provider.js";
12
+ import { PaymentActionProvider } from "../sdk/actions/payment-action-provider.js";
11
13
  import { RegionActionProvider } from "../sdk/actions/region-action-provider.js";
12
14
  import { SessionActionProvider } from "../sdk/actions/session-action-provider.js";
13
15
  import { ShippingActionProvider } from "../sdk/actions/shipping-action-provider.js";
@@ -20,4 +22,4 @@ import "../sdk/data/index.js";
20
22
  import { StorefrontProvider } from "../sdk/provider/storefront-provider.js";
21
23
  import "../sdk/provider/index.js";
22
24
  import "../sdk/state/index.js";
23
- export { CartActionProvider, DataOverrideContext, HotDataProvider, IdentityActionProvider, ListItemRefContext, MultipleReactiveDataProvider, PageReactiveDataRoot, ReactiveDataProvider, ReactiveListItemDataProvider, ReactiveRootContext, RegionActionProvider, SessionActionProvider, ShippingActionProvider, StorefrontProvider, buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove, buildStorefrontContextHeaders, cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, gql, miniCartOpenVar, orderFormIdVar, publishedVariantIdFor, selectedVariantVar, useDataOverride, useListItemRef };
25
+ export { AnalyticsActionProvider, CartActionProvider, DataOverrideContext, HotDataProvider, IdentityActionProvider, ListItemRefContext, MultipleReactiveDataProvider, PageReactiveDataRoot, PaymentActionProvider, ReactiveDataProvider, ReactiveListItemDataProvider, ReactiveRootContext, RegionActionProvider, SessionActionProvider, ShippingActionProvider, StorefrontProvider, buildOptimisticDecrease, buildOptimisticIncrease, buildOptimisticRemove, buildStorefrontContextHeaders, cartCouponErrorsVar, cartLastAddVar, cartUserErrorsVar, gql, miniCartOpenVar, orderFormIdVar, publishedVariantIdFor, selectedVariantVar, useDataOverride, useListItemRef };