@vtex/faststore 0.0.7 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/dist/actions.json +194 -1
- package/dist/catalog.json +3449 -1612
- package/dist/cli/index.d.ts +512 -63
- package/dist/cli/index.js +2098 -686
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/server-runtime.js +44 -24
- package/dist/cli/server-runtime.js.map +1 -1
- package/dist/client.d.ts +5 -1
- package/dist/client.js +5 -1
- package/dist/components.d.ts +42 -10
- package/dist/components.js +47 -15
- package/dist/content-types.json +823 -0
- package/dist/core/dist/define-component.d.ts +12 -2
- package/dist/docs/account-access-gate.md +4 -4
- package/dist/docs/account-address-book.md +519 -0
- package/dist/docs/account-entry-point.md +5 -5
- package/dist/docs/account-menu.md +7 -7
- package/dist/docs/account-saved-cards.md +301 -0
- package/dist/docs/alert-dialog.md +2 -2
- package/dist/docs/billing-address.md +17 -9
- package/dist/docs/binding-switcher.md +154 -0
- package/dist/docs/card-entry.md +38 -7
- package/dist/docs/card-summary.md +175 -0
- package/dist/docs/cardholder-document.md +16 -14
- package/dist/docs/cart-destination.md +238 -0
- package/dist/docs/cart-item.md +22 -4
- package/dist/docs/cart-totalizer.md +1 -1
- package/dist/docs/cart.md +126 -19
- package/dist/docs/client-profile-fieldset.md +7 -5
- package/dist/docs/copy-text.md +84 -0
- package/dist/docs/document-field.md +8 -8
- package/dist/docs/footer-link-group.md +2 -2
- package/dist/docs/footer-social.md +1 -1
- package/dist/docs/free-shipping-progress.md +13 -9
- package/dist/docs/header-root.md +1 -1
- package/dist/docs/incentives.md +4 -4
- package/dist/docs/logo.md +6 -6
- package/dist/docs/my-account-profile.md +4 -4
- package/dist/docs/navigation-link-list.md +2 -2
- package/dist/docs/navigation-link.md +3 -3
- package/dist/docs/order-cancel.md +52 -0
- package/dist/docs/order-delivery-address.md +63 -0
- package/dist/docs/order-delivery-group.md +83 -0
- package/dist/docs/order-details-back.md +41 -0
- package/dist/docs/order-details-header.md +48 -0
- package/dist/docs/order-list-row.md +46 -0
- package/dist/docs/order-list-search.md +101 -0
- package/dist/docs/order-list-views.md +97 -0
- package/dist/docs/order-list.md +94 -0
- package/dist/docs/order-payment.md +94 -0
- package/dist/docs/order-placed-date.md +49 -0
- package/dist/docs/order-placed-payment-summary.md +13 -15
- package/dist/docs/order-placed.md +225 -0
- package/dist/docs/order-progress.md +88 -0
- package/dist/docs/order-status-badge.md +91 -0
- package/dist/docs/order-summary.md +53 -0
- package/dist/docs/payment-method-badges.md +16 -5
- package/dist/docs/payment-methods.md +1 -1
- package/dist/docs/place-order.md +13 -9
- package/dist/docs/product-information.md +2 -2
- package/dist/docs/product-shelf.md +7 -0
- package/dist/docs/saved-cards.md +2 -2
- package/dist/docs/select.md +22 -10
- package/dist/docs/session.md +1 -1
- package/dist/docs/shipping-address.md +1 -1
- package/dist/docs/sign-in-redirect.md +7 -7
- package/dist/docs/toast.md +35 -13
- package/dist/index.d.ts +7 -2
- package/dist/index.js +2 -1
- package/dist/internal/client.d.ts +9 -1
- package/dist/internal/client.js +10 -2
- package/dist/internal/server.d.ts +8 -2
- package/dist/internal/server.js +8 -2
- package/dist/matter/account-access-gate/account-access-gate.d.ts +2 -1
- package/dist/matter/account-access-gate/account-access-gate.js +19 -16
- package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-delete.d.ts +60 -0
- package/dist/matter/account-address-book/account-address-book-delete.js +184 -0
- package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +19 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.js +50 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +42 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.js +146 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +25 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.js +72 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book.d.ts +120 -0
- package/dist/matter/account-address-book/account-address-book.js +469 -0
- package/dist/matter/account-address-book/account-address-book.js.map +1 -0
- package/dist/matter/account-address-book/account-address-country-switch.js +59 -0
- package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -0
- package/dist/matter/account-address-book/account-address-country.d.ts +36 -0
- package/dist/matter/account-address-book/account-address-country.js +151 -0
- package/dist/matter/account-address-book/account-address-country.js.map +1 -0
- package/dist/matter/account-address-book/account-address-first-line.js +11 -0
- package/dist/matter/account-address-book/account-address-first-line.js.map +1 -0
- package/dist/matter/account-address-book/account-address-form-context.d.ts +55 -0
- package/dist/matter/account-address-book/account-address-form-context.js +14 -0
- package/dist/matter/account-address-book/account-address-form-context.js.map +1 -0
- package/dist/matter/account-address-book/account-address-form.d.ts +85 -0
- package/dist/matter/account-address-book/account-address-form.js +946 -0
- package/dist/matter/account-address-book/account-address-form.js.map +1 -0
- package/dist/matter/account-address-book/account-address-postal-autofill.js +189 -0
- package/dist/matter/account-address-book/account-address-postal-autofill.js.map +1 -0
- package/dist/matter/account-address-book/account-address-record.d.ts +26 -0
- package/dist/matter/account-address-book/account-address-record.js +138 -0
- package/dist/matter/account-address-book/account-address-record.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.js +11 -11
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +7 -3
- package/dist/matter/account-menu/account-menu.js +69 -28
- package/dist/matter/account-menu/account-menu.js.map +1 -1
- package/dist/matter/account-saved-cards/account-saved-cards.d.ts +383 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js +956 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
- package/dist/matter/billing-address/billing-address.d.ts +30 -17
- package/dist/matter/billing-address/billing-address.js +128 -33
- package/dist/matter/billing-address/billing-address.js.map +1 -1
- package/dist/matter/breadcrumb/breadcrumb.js +2 -2
- package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/matter/card-entry/card-capture.js +4 -3
- package/dist/matter/card-entry/card-capture.js.map +1 -1
- package/dist/matter/card-entry/card-entry.d.ts +5 -3
- package/dist/matter/card-entry/card-entry.js +77 -27
- package/dist/matter/card-entry/card-entry.js.map +1 -1
- package/dist/matter/cardholder-document/cardholder-document.d.ts +10 -9
- package/dist/matter/cardholder-document/cardholder-document.js +36 -16
- package/dist/matter/cardholder-document/cardholder-document.js.map +1 -1
- package/dist/matter/cart/cart-namespace.d.ts +5 -1
- package/dist/matter/cart/cart-namespace.js +5 -1
- package/dist/matter/cart/cart-namespace.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +41 -6
- package/dist/matter/cart/cart.js +267 -54
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-destination/cart-destination.d.ts +222 -0
- package/dist/matter/cart-destination/cart-destination.js +613 -0
- package/dist/matter/cart-destination/cart-destination.js.map +1 -0
- package/dist/matter/cart-item/cart-item.d.ts +4 -2
- package/dist/matter/cart-item/cart-item.js +76 -17
- package/dist/matter/cart-item/cart-item.js.map +1 -1
- package/dist/matter/cart-totalizer/cart-totalizer.js +3 -2
- package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences-fieldset.js +1 -1
- package/dist/matter/client-profile-form/client-profile-fieldset.js +8 -5
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
- package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +6 -3
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +76 -33
- package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.js +3 -3
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.js +2 -2
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/my-account-profile/my-account-profile.d.ts +3 -3
- package/dist/matter/my-account-profile/my-account-profile.js +4 -4
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-cancel/order-cancel.d.ts +110 -0
- package/dist/matter/order-cancel/order-cancel.js +344 -0
- package/dist/matter/order-cancel/order-cancel.js.map +1 -0
- package/dist/matter/order-delivery-address/order-delivery-address.d.ts +73 -0
- package/dist/matter/order-delivery-address/order-delivery-address.js +172 -0
- package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -0
- package/dist/matter/order-delivery-group/order-delivery-group.d.ts +128 -0
- package/dist/matter/order-delivery-group/order-delivery-group.js +408 -0
- package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -0
- package/dist/matter/order-details-header/order-details-header.d.ts +104 -0
- package/dist/matter/order-details-header/order-details-header.js +190 -0
- package/dist/matter/order-details-header/order-details-header.js.map +1 -0
- package/dist/matter/order-list/customer-orders-filter.d.ts +12 -0
- package/dist/matter/order-list/customer-orders-filter.js +30 -0
- package/dist/matter/order-list/customer-orders-filter.js.map +1 -0
- package/dist/matter/order-list/order-list.d.ts +121 -0
- package/dist/matter/order-list/order-list.js +395 -0
- package/dist/matter/order-list/order-list.js.map +1 -0
- package/dist/matter/order-list-row/order-list-row.d.ts +44 -0
- package/dist/matter/order-list-row/order-list-row.js +127 -0
- package/dist/matter/order-list-row/order-list-row.js.map +1 -0
- package/dist/matter/order-list-search/order-list-search.d.ts +72 -0
- package/dist/matter/order-list-search/order-list-search.js +296 -0
- package/dist/matter/order-list-search/order-list-search.js.map +1 -0
- package/dist/matter/order-list-views/order-list-views.d.ts +65 -0
- package/dist/matter/order-list-views/order-list-views.js +154 -0
- package/dist/matter/order-list-views/order-list-views.js.map +1 -0
- package/dist/matter/order-payment/order-payment.d.ts +83 -0
- package/dist/matter/order-payment/order-payment.js +258 -0
- package/dist/matter/order-payment/order-payment.js.map +1 -0
- package/dist/matter/order-placed/order-placed-deliveries.d.ts +145 -0
- package/dist/matter/order-placed/order-placed-deliveries.js +380 -0
- package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -0
- package/dist/matter/order-placed/order-placed.d.ts +122 -0
- package/dist/matter/order-placed/order-placed.js +452 -0
- package/dist/matter/order-placed/order-placed.js.map +1 -0
- package/dist/matter/order-placed-date/order-placed-date.d.ts +45 -0
- package/dist/matter/order-placed-date/order-placed-date.js +92 -0
- package/dist/matter/order-placed-date/order-placed-date.js.map +1 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +5 -8
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +29 -81
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
- package/dist/matter/order-progress/order-progress.d.ts +85 -0
- package/dist/matter/order-progress/order-progress.js +203 -0
- package/dist/matter/order-progress/order-progress.js.map +1 -0
- package/dist/matter/order-summary/order-summary.d.ts +81 -0
- package/dist/matter/order-summary/order-summary.js +192 -0
- package/dist/matter/order-summary/order-summary.js.map +1 -0
- package/dist/matter/payment/cardholder-document-rule.d.ts +35 -0
- package/dist/matter/payment/cardholder-document-rule.js +35 -0
- package/dist/matter/payment/cardholder-document-rule.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.js +38 -23
- package/dist/matter/payment/payment-card-capture.js.map +1 -1
- package/dist/matter/payment/payment-controller.js +11 -0
- package/dist/matter/payment/payment-controller.js.map +1 -1
- package/dist/matter/payment/payment-method-badges.js +4 -2
- package/dist/matter/payment/payment-method-badges.js.map +1 -1
- package/dist/matter/payment/payment.js +11 -0
- package/dist/matter/payment/payment.js.map +1 -1
- package/dist/matter/payment/use-payment-method-selection.d.ts +39 -0
- package/dist/matter/payment/use-payment-method-selection.js +30 -2
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
- package/dist/matter/payment/use-payment-submit-gate.d.ts +16 -2
- package/dist/matter/payment/use-payment-submit-gate.js +42 -14
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
- package/dist/matter/place-order/place-order.d.ts +12 -7
- package/dist/matter/place-order/place-order.js +126 -103
- package/dist/matter/place-order/place-order.js.map +1 -1
- package/dist/matter/pricing/pricing.js +5 -5
- package/dist/matter/pricing/pricing.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +7 -0
- package/dist/matter/product-shelf/product-shelf.js +115 -1
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.js +1 -1
- package/dist/matter/saved-cards/saved-cards.js +26 -15
- package/dist/matter/saved-cards/saved-cards.js.map +1 -1
- package/dist/matter/session/session.js +2 -2
- package/dist/matter/session/session.js.map +1 -1
- package/dist/matter/shipping-address/country-descriptors.d.ts +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +23 -1
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.js +62 -14
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +2 -2
- package/dist/matter/shipping-simulator/shipping-simulator.js +6 -2
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/sign-in-redirect/sign-in-redirect.js +48 -10
- package/dist/matter/sign-in-redirect/sign-in-redirect.js.map +1 -1
- package/dist/matter/variant-selector/variant-selector.js +2 -2
- package/dist/matter/variant-selector/variant-selector.js.map +1 -1
- package/dist/particles/address-summary/address-summary.js +2 -2
- package/dist/particles/address-summary/address-summary.js.map +1 -1
- package/dist/particles/alert-dialog/alert-dialog.d.ts +5 -1
- package/dist/particles/alert-dialog/alert-dialog.js +5 -2
- package/dist/particles/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/particles/binding-switcher/binding-switcher.d.ts +38 -0
- package/dist/particles/binding-switcher/binding-switcher.js +183 -0
- package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
- package/dist/particles/card-summary/card-network.d.ts +17 -0
- package/dist/particles/card-summary/card-network.js +25 -0
- package/dist/particles/card-summary/card-network.js.map +1 -0
- package/dist/particles/card-summary/card-summary.d.ts +83 -0
- package/dist/particles/card-summary/card-summary.js +188 -0
- package/dist/particles/card-summary/card-summary.js.map +1 -0
- package/dist/particles/copy-text/copy-text.d.ts +28 -0
- package/dist/particles/copy-text/copy-text.js +140 -0
- package/dist/particles/copy-text/copy-text.js.map +1 -0
- package/dist/particles/document-field/document-field.d.ts +34 -5
- package/dist/particles/document-field/document-field.js +115 -19
- package/dist/particles/document-field/document-field.js.map +1 -1
- package/dist/particles/field/field.js +1 -1
- package/dist/particles/field/field.js.map +1 -1
- package/dist/particles/footer-link-group/footer-link-group.d.ts +6 -2
- package/dist/particles/footer-link-group/footer-link-group.js +18 -7
- package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
- package/dist/particles/footer-social/footer-social.d.ts +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/footer-social/footer-social.js.map +1 -1
- package/dist/particles/incentives/incentives.d.ts +7 -3
- package/dist/particles/incentives/incentives.js +8 -3
- package/dist/particles/incentives/incentives.js.map +1 -1
- package/dist/particles/logo/logo.d.ts +3 -2
- package/dist/particles/logo/logo.js +20 -8
- package/dist/particles/logo/logo.js.map +1 -1
- package/dist/particles/navigation-link/navigation-link.d.ts +2 -3
- package/dist/particles/navigation-link/navigation-link.js +4 -4
- package/dist/particles/navigation-link/navigation-link.js.map +1 -1
- package/dist/particles/navigation-link-list/navigation-link-list.d.ts +6 -2
- package/dist/particles/navigation-link-list/navigation-link-list.js +18 -7
- package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -1
- package/dist/particles/order-details-back/order-details-back.d.ts +28 -0
- package/dist/particles/order-details-back/order-details-back.js +52 -0
- package/dist/particles/order-details-back/order-details-back.js.map +1 -0
- package/dist/particles/order-status-badge/order-status-badge.d.ts +19 -0
- package/dist/particles/order-status-badge/order-status-badge.js +50 -0
- package/dist/particles/order-status-badge/order-status-badge.js.map +1 -0
- package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
- package/dist/particles/payment-methods/payment-methods.js +1 -1
- package/dist/particles/payment-methods/payment-methods.js.map +1 -1
- package/dist/particles/phone-field/phone-field.js +2 -2
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/select/select.js +6 -6
- package/dist/particles/select/select.js.map +1 -1
- package/dist/particles/toast/toast.d.ts +21 -7
- package/dist/particles/toast/toast.js +76 -8
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +1376 -126
- package/dist/sdk/actions/address-action-provider.d.ts +16 -0
- package/dist/sdk/actions/address-action-provider.js +20 -0
- package/dist/sdk/actions/address-action-provider.js.map +1 -0
- package/dist/sdk/actions/analytics-action-provider.js +1 -1
- package/dist/sdk/actions/index.d.ts +5 -1
- package/dist/sdk/actions/index.js +5 -1
- package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
- package/dist/sdk/actions/locale-action-provider.js +20 -0
- package/dist/sdk/actions/locale-action-provider.js.map +1 -0
- package/dist/sdk/actions/order-action-provider.d.ts +12 -0
- package/dist/sdk/actions/order-action-provider.js +16 -0
- package/dist/sdk/actions/order-action-provider.js.map +1 -0
- package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
- package/dist/sdk/actions/saved-card-action-provider.js +16 -0
- package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
- package/dist/sdk/actions/types.d.ts +10 -2
- package/dist/sdk/address/address-fields.js +38 -0
- package/dist/sdk/address/address-fields.js.map +1 -0
- package/dist/sdk/address/checkout-readiness.js +17 -0
- package/dist/sdk/address/checkout-readiness.js.map +1 -0
- package/dist/sdk/address/constants.js +60 -0
- package/dist/sdk/address/constants.js.map +1 -0
- package/dist/sdk/address/country-display.js +19 -0
- package/dist/sdk/address/country-display.js.map +1 -0
- package/dist/sdk/address/country-rules.js +30 -0
- package/dist/sdk/address/country-rules.js.map +1 -0
- package/dist/sdk/address/format-address.js +18 -0
- package/dist/sdk/address/format-address.js.map +1 -0
- package/dist/sdk/address/iso-countries.js +262 -0
- package/dist/sdk/address/iso-countries.js.map +1 -0
- package/dist/sdk/address/layouts.js +56 -0
- package/dist/sdk/address/layouts.js.map +1 -0
- package/dist/sdk/address/messages.js +97 -0
- package/dist/sdk/address/messages.js.map +1 -0
- package/dist/sdk/address/operations.d.ts +54 -0
- package/dist/sdk/address/operations.js +83 -0
- package/dist/sdk/address/operations.js.map +1 -0
- package/dist/sdk/address/postal-code-lookup-operations.js +23 -0
- package/dist/sdk/address/postal-code-lookup-operations.js.map +1 -0
- package/dist/sdk/address/postal-code.js +11 -0
- package/dist/sdk/address/postal-code.js.map +1 -0
- package/dist/sdk/address/schema.js +14 -0
- package/dist/sdk/address/schema.js.map +1 -0
- package/dist/sdk/address/server-fields.js +25 -0
- package/dist/sdk/address/server-fields.js.map +1 -0
- package/dist/sdk/address/switch-country.js +57 -0
- package/dist/sdk/address/switch-country.js.map +1 -0
- package/dist/sdk/address/types.d.ts +26 -0
- package/dist/sdk/address/use-address-actions.d.ts +29 -0
- package/dist/sdk/address/use-address-actions.js +247 -0
- package/dist/sdk/address/use-address-actions.js.map +1 -0
- package/dist/sdk/address/use-address-by-postal-code.js +57 -0
- package/dist/sdk/address/use-address-by-postal-code.js.map +1 -0
- package/dist/sdk/address/validate-address.js +62 -0
- package/dist/sdk/address/validate-address.js.map +1 -0
- package/dist/sdk/cache/storefront-cache.js +30 -4
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +2 -1
- package/dist/sdk/cart/operations.js +55 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.d.ts +30 -7
- package/dist/sdk/cart/optimistic.js +78 -41
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
- package/dist/sdk/cart/use-cart-actions.js +61 -15
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
- package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
- package/dist/sdk/client/fetch-page-data.d.ts +11 -0
- package/dist/sdk/client/fetch-page-data.js +12 -1
- package/dist/sdk/client/fetch-page-data.js.map +1 -1
- package/dist/sdk/content/create-content-runtime.js +1 -8
- package/dist/sdk/content/create-content-runtime.js.map +1 -1
- package/dist/sdk/data/failed-fields.js +23 -0
- package/dist/sdk/data/failed-fields.js.map +1 -0
- package/dist/sdk/data/index.js +2 -2
- package/dist/sdk/data/page-reactive-data-root.d.ts +45 -7
- package/dist/sdk/data/page-reactive-data-root.js +88 -12
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
- package/dist/sdk/generated/fragment-types.js +2 -0
- package/dist/sdk/generated/fragment-types.js.map +1 -1
- package/dist/sdk/generated/gql.js +17 -11
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +185 -46
- package/dist/sdk/generated/graphql.js +2587 -155
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/messages/en-US.js +157 -1
- package/dist/sdk/i18n/messages/en-US.json +157 -1
- package/dist/sdk/i18n/messages/en-US.json.d.ts +156 -0
- package/dist/sdk/i18n/messages/es-ES.js +157 -1
- package/dist/sdk/i18n/messages/es-ES.json +157 -1
- package/dist/sdk/i18n/messages/pt-BR.js +157 -1
- package/dist/sdk/i18n/messages/pt-BR.json +157 -1
- package/dist/sdk/i18n/provider.js +1 -1
- package/dist/sdk/i18n/provider.js.map +1 -1
- package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
- package/dist/sdk/locale/binding-switch-provider.js +20 -0
- package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
- package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
- package/dist/sdk/locale/use-locale-actions.js +70 -0
- package/dist/sdk/locale/use-locale-actions.js.map +1 -0
- package/dist/sdk/navigation/binding-switch.d.ts +39 -0
- package/dist/sdk/navigation/binding-switch.js +129 -0
- package/dist/sdk/navigation/binding-switch.js.map +1 -0
- package/dist/sdk/navigation/current-page.js +30 -0
- package/dist/sdk/navigation/current-page.js.map +1 -0
- package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
- package/dist/sdk/navigation/decode-route-params.js +32 -0
- package/dist/sdk/navigation/decode-route-params.js.map +1 -0
- package/dist/sdk/navigation/not-found-log.d.ts +28 -0
- package/dist/sdk/navigation/not-found-log.js +133 -0
- package/dist/sdk/navigation/not-found-log.js.map +1 -0
- package/dist/sdk/navigation/path.js +25 -0
- package/dist/sdk/navigation/path.js.map +1 -0
- package/dist/sdk/navigation/redirect.d.ts +11 -0
- package/dist/sdk/navigation/redirect.js +22 -0
- package/dist/sdk/navigation/redirect.js.map +1 -0
- package/dist/sdk/navigation/report.js +70 -0
- package/dist/sdk/navigation/report.js.map +1 -0
- package/dist/sdk/navigation/resolve-storefront-href.d.ts +12 -0
- package/dist/sdk/navigation/resolve-storefront-href.js +214 -0
- package/dist/sdk/navigation/resolve-storefront-href.js.map +1 -0
- package/dist/sdk/navigation/route-identity-provider.d.ts +11 -0
- package/dist/sdk/navigation/route-identity-provider.js +20 -0
- package/dist/sdk/navigation/route-identity-provider.js.map +1 -0
- package/dist/sdk/navigation/route-map-provider.d.ts +19 -0
- package/dist/sdk/navigation/route-map-provider.js +29 -0
- package/dist/sdk/navigation/route-map-provider.js.map +1 -0
- package/dist/sdk/navigation/storefront-link.d.ts +16 -0
- package/dist/sdk/navigation/storefront-link.js +66 -0
- package/dist/sdk/navigation/storefront-link.js.map +1 -0
- package/dist/sdk/navigation/types.d.ts +45 -0
- package/dist/sdk/navigation/use-storefront-navigation.d.ts +26 -0
- package/dist/sdk/navigation/use-storefront-navigation.js +73 -0
- package/dist/sdk/navigation/use-storefront-navigation.js.map +1 -0
- package/dist/sdk/navigation/use-storefront-route.d.ts +26 -0
- package/dist/sdk/navigation/use-storefront-route.js +87 -0
- package/dist/sdk/navigation/use-storefront-route.js.map +1 -0
- package/dist/sdk/navigation/use-storefront-search-params.d.ts +11 -0
- package/dist/sdk/navigation/use-storefront-search-params.js +16 -0
- package/dist/sdk/navigation/use-storefront-search-params.js.map +1 -0
- package/dist/sdk/orders/completion-badge.d.ts +8 -0
- package/dist/sdk/orders/completion-badge.js +47 -0
- package/dist/sdk/orders/completion-badge.js.map +1 -0
- package/dist/sdk/orders/order-operations.d.ts +19 -0
- package/dist/sdk/orders/order-operations.js +21 -0
- package/dist/sdk/orders/order-operations.js.map +1 -0
- package/dist/sdk/orders/use-order-actions.d.ts +23 -0
- package/dist/sdk/orders/use-order-actions.js +62 -0
- package/dist/sdk/orders/use-order-actions.js.map +1 -0
- package/dist/sdk/payment/gateway-origin.js +26 -13
- package/dist/sdk/payment/gateway-origin.js.map +1 -1
- package/dist/sdk/payment/gateway.d.ts +14 -2
- package/dist/sdk/payment/gateway.js +32 -14
- package/dist/sdk/payment/gateway.js.map +1 -1
- package/dist/sdk/payment/operations.js +11 -0
- package/dist/sdk/payment/operations.js.map +1 -1
- package/dist/sdk/payment/submission-registry.d.ts +2 -1
- package/dist/sdk/payment/submission-registry.js +12 -8
- package/dist/sdk/payment/submission-registry.js.map +1 -1
- package/dist/sdk/payment/use-payment-actions.d.ts +5 -3
- package/dist/sdk/payment/use-payment-actions.js +5 -2
- package/dist/sdk/payment/use-payment-actions.js.map +1 -1
- package/dist/sdk/payment/use-place-order.d.ts +6 -3
- package/dist/sdk/payment/use-place-order.js +333 -143
- package/dist/sdk/payment/use-place-order.js.map +1 -1
- package/dist/sdk/saved-cards/operations.d.ts +16 -0
- package/dist/sdk/saved-cards/operations.js +41 -0
- package/dist/sdk/saved-cards/operations.js.map +1 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
- package/dist/sdk/seo/page-alternates.d.ts +57 -0
- package/dist/sdk/seo/page-alternates.js +127 -0
- package/dist/sdk/seo/page-alternates.js.map +1 -0
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js +13 -0
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +9 -2
- package/dist/sdk/state/cart.js +9 -2
- package/dist/sdk/state/cart.js.map +1 -1
- package/dist/utils/own-value.js +19 -0
- package/dist/utils/own-value.js.map +1 -0
- package/dist/utils/safe-href.d.ts +4 -4
- package/dist/utils/safe-href.js +31 -22
- package/dist/utils/safe-href.js.map +1 -1
- package/package.json +5 -1
- package/skills/storefront-asset/SKILL.md +111 -0
- package/skills/storefront-asset/references/api-side.md +153 -0
- package/skills/storefront-asset/references/findings.md +40 -0
- package/skills/storefront-asset/references/ui-side.md +94 -0
- package/src/styles/tailwind.css +28 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../../particles/field/field.js";
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
//#region src/matter/shipping-address/country-descriptors.ts
|
|
2
|
+
/**
|
|
3
|
+
* Whether `value` satisfies the field's declared `rule.pattern`. A field with no pattern, or a blank
|
|
4
|
+
* value (empty or whitespace-only: blankness is the required rule's business, and a form that trims
|
|
5
|
+
* before judging, as `BillingAddress` does, reads such a value as required, never as a format failure),
|
|
6
|
+
* satisfies it. A non-blank value is tested raw, equivalent to the predicate react-hook-form applies
|
|
7
|
+
* (`value.match(regex) !== null`), so both forms agree on every non-blank value. Blank values are the
|
|
8
|
+
* one deliberate divergence: react-hook-form skips the pattern only for `''`, so for `' '` the
|
|
9
|
+
* delivery form runs the pattern and reports the format, while this helper reports it satisfied and
|
|
10
|
+
* leaves the verdict to the required rule. A caller that needs react-hook-form's exact verdict on a
|
|
11
|
+
* blank value must not rely on this helper alone. `search` ignores a global regex's `lastIndex`, so
|
|
12
|
+
* the descriptor's shared regex is never written to.
|
|
13
|
+
*/
|
|
14
|
+
function satisfiesFieldPattern(field, value) {
|
|
15
|
+
const pattern = field.rule?.pattern;
|
|
16
|
+
if (!pattern || value.trim() === "") return true;
|
|
17
|
+
return value.search(pattern.value) !== -1;
|
|
18
|
+
}
|
|
1
19
|
/**
|
|
2
20
|
* All available country descriptors, keyed by ISO alpha-3 code.
|
|
3
21
|
*
|
|
@@ -8,6 +26,8 @@ const countryDescriptors = {
|
|
|
8
26
|
BRA: {
|
|
9
27
|
iso: "BRA",
|
|
10
28
|
label: "Brasil",
|
|
29
|
+
countryLabel: "país",
|
|
30
|
+
requiredSuffix: "é obrigatório",
|
|
11
31
|
fields: [
|
|
12
32
|
{
|
|
13
33
|
name: "recipientName",
|
|
@@ -51,6 +71,8 @@ const countryDescriptors = {
|
|
|
51
71
|
USA: {
|
|
52
72
|
iso: "USA",
|
|
53
73
|
label: "United States",
|
|
74
|
+
countryLabel: "country",
|
|
75
|
+
requiredSuffix: "is required",
|
|
54
76
|
fields: [
|
|
55
77
|
{
|
|
56
78
|
name: "recipientName",
|
|
@@ -106,6 +128,6 @@ function getCountryDescriptor(iso) {
|
|
|
106
128
|
return countryDescriptors[iso];
|
|
107
129
|
}
|
|
108
130
|
//#endregion
|
|
109
|
-
export { countryDescriptors, getAvailableCountries, getCountryDescriptor };
|
|
131
|
+
export { countryDescriptors, getAvailableCountries, getCountryDescriptor, satisfiesFieldPattern };
|
|
110
132
|
|
|
111
133
|
//# sourceMappingURL=country-descriptors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"country-descriptors.js","names":[],"sources":["../../../src/matter/shipping-address/country-descriptors.ts"],"sourcesContent":["/**\n * Country-adaptive shipping address form descriptors.\n *\n * Each descriptor declares the form shape (field set, order, and labels) for a specific country.\n * Descriptors are primarily data — field set, order, and labels — but a `FieldDescriptor` may also\n * carry `required` and `rule`, the two validation facts a country varies. `ShippingAddressFieldset`\n * is the only reader of either (specs/shipping-address-fieldset.md, Decision 3): a field whose\n * descriptor entry is absent is never rendered, so it can carry no requiredness at all.\n * Country adaptation is data-driven; adding a country is a data-only change (a new descriptor entry).\n *\n * Canonical field names must be shared/consistent across descriptors for fields both countries have\n * (recipientName, postalCode, street, number, complement, city, state), so that switching countries\n * preserves shared field values in the batched draft state (Decision 1/Invariant).\n *\n * Per Decision 2, this narrows the RFC's descriptor scope to form shape plus two per-field validation\n * facts: the non-blank recipient name and, per country, the postal code's format. Both descriptors'\n * `postalCode` entry carries a `pattern` rule matching that country's CEP or ZIP shape; every other\n * field's `rule` stays undefined. There is no server-side postal-code validation to fall back on:\n * `shippingAddressUpdate` types `postalCode` as a plain `z.string()`, forwards it verbatim with\n * `clearAddressIfPostalCodeNotFound: false`, and has no try/catch around the upstream call, so a\n * malformed value still returns HTTP 200 with an empty `userErrors` array. This client-side rule is\n * the only postal-code guard in the system today; per-field blur validation and a future\n * @vtex/country-forms adoption remain deferred.\n */\n\nimport type { FieldRule } from '../../particles/field/field.js';\n\n/**\n * Describes a single form field within a country descriptor.\n *\n * @property name - Canonical field name (e.g., \"recipientName\", \"street\", \"neighborhood\").\n * Shared field names across descriptors enable draft state preservation on country switch.\n * @property label - Human-readable label for the field. Named `label` (not a key) to allow future\n * swapping with i18n keys once the codebase adopts an i18n layer.\n */\nexport type FieldDescriptor = Readonly<{\n name: string;\n label: string;\n /**\n * Whether the fieldset requires a non-blank value. Read only by ShippingAddressFieldset, which\n * turns it into the field contract's `rule`. A field whose descriptor entry is absent is not\n * rendered, so it can carry no requiredness at all — that is the point (Decision 3).\n */\n required?: boolean;\n /**\n * Extra react-hook-form rules for this field in this country: pattern, minLength, and so on.\n * Merged under the generated `required`. Only `postalCode` carries one today.\n */\n rule?: FieldRule;\n}>;\n\n/**\n * Describes the form shape for a single country.\n *\n * @property iso - ISO 3166-1 alpha-3 country code (e.g., \"BRA\", \"USA\"). Must be a valid 3-letter code\n * matching the Address.country field type (plain String!, ISO alpha-3 by convention).\n * @property label - Human-readable country name for the country selector (e.g., \"Brazil\", \"United States\").\n * Named `label` (not a key) to allow future swapping with i18n keys.\n * @property fields - Ordered field set for this country. Order defines the visual order in the form.\n * Only fields this country uses are listed; absent fields are not rendered.\n */\nexport type CountryDescriptor = Readonly<{\n iso: string;\n label: string;\n fields: readonly FieldDescriptor[];\n}>;\n\n/**\n * Brazil (BRA) address form descriptor.\n *\n * Field order:\n * 1. recipientName — recipient of the package\n * 2. street — street name\n * 3. number — street number\n * 4. complement — apartment, suite, etc. (optional per GraphQL but no form-level validation)\n * 5. neighborhood — bairro (BR-specific, not in US form)\n * 6. city — city name\n * 7. state — state/UF code (canonical name shared with US, though US calls it state abbreviation)\n * 8. postalCode — CEP format, client-validated via `rule` (8 digits, hyphen after the fifth optional)\n */\nconst brDescriptor: CountryDescriptor = {\n iso: 'BRA',\n label: 'Brasil',\n fields: [\n { name: 'recipientName', label: 'nome do destinatário', required: true },\n { name: 'street', label: 'rua' },\n { name: 'number', label: 'número' },\n { name: 'complement', label: 'complemento (opcional)' },\n { name: 'neighborhood', label: 'bairro' },\n { name: 'city', label: 'cidade' },\n { name: 'state', label: 'estado' },\n {\n name: 'postalCode',\n label: 'cep',\n rule: { pattern: { value: /^\\d{5}-?\\d{3}$/, message: 'cep inválido' } },\n },\n ],\n};\n\n/**\n * United States (USA) address form descriptor.\n *\n * Field order:\n * 1. recipientName — recipient of the package\n * 2. street — street name\n * 3. number — street number\n * 4. complement — apartment, suite, etc. (optional per GraphQL but no form-level validation)\n * 5. city — city name\n * 6. state — state abbreviation (canonical name shared with BR for draft preservation)\n * 7. postalCode — ZIP/ZIP+4 format, client-validated via `rule` (5 digits, optional 4-digit\n * extension, hyphen before it optional either way — accepts both `02101-1234` and `021011234`)\n *\n * Note: neighborhood is not included in the US v1 form. If the shopper switches from BR to US,\n * the neighborhood value is retained in the draft but hidden (descriptor controls visibility only);\n * switching back to BR resurfaces it.\n */\nconst usaDescriptor: CountryDescriptor = {\n iso: 'USA',\n label: 'United States',\n fields: [\n { name: 'recipientName', label: 'recipient name', required: true },\n { name: 'street', label: 'street' },\n { name: 'number', label: 'number' },\n { name: 'complement', label: 'apartment, suite, etc. (optional)' },\n { name: 'city', label: 'city' },\n { name: 'state', label: 'state' },\n {\n name: 'postalCode',\n label: 'zip code',\n rule: { pattern: { value: /^\\d{5}(-?\\d{4})?$/, message: 'invalid zip code' } },\n },\n ],\n};\n\n/**\n * All available country descriptors, keyed by ISO alpha-3 code.\n *\n * The country selector lists only countries with a descriptor; a descriptor-less country is unreachable.\n * Adding a country is a data-only change: add a new CountryDescriptor entry here.\n */\nexport const countryDescriptors: Readonly<Record<string, CountryDescriptor>> = {\n BRA: brDescriptor,\n USA: usaDescriptor,\n};\n\n/**\n * Returns an ordered list of available country ISO codes (those with a descriptor).\n *\n * @returns ISO alpha-3 codes of all implemented countries, in definition order.\n */\nexport function getAvailableCountries(): readonly string[] {\n return Object.keys(countryDescriptors);\n}\n\n/**\n * Retrieves the descriptor for a given country.\n *\n * @param iso - ISO 3166-1 alpha-3 country code (e.g., \"BRA\", \"USA\")\n * @returns The CountryDescriptor for the country, or undefined if not implemented.\n */\nexport function getCountryDescriptor(iso: string): CountryDescriptor | undefined {\n return countryDescriptors[iso];\n}\n"],"mappings":";;;;;;AA4IA,MAAa,qBAAkE;CAC7E,KAAK;EA5DL,KAAK;EACL,OAAO;EACP,QAAQ;GACN;IAAE,MAAM;IAAiB,OAAO;IAAwB,UAAU;GAAK;GACvE;IAAE,MAAM;IAAU,OAAO;GAAM;GAC/B;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAc,OAAO;GAAyB;GACtD;IAAE,MAAM;IAAgB,OAAO;GAAS;GACxC;IAAE,MAAM;IAAQ,OAAO;GAAS;GAChC;IAAE,MAAM;IAAS,OAAO;GAAS;GACjC;IACE,MAAM;IACN,OAAO;IACP,MAAM,EAAE,SAAS;KAAE,OAAO;KAAkB,SAAS;IAAe,EAAE;GACxE;EACF;CA6CK;CACL,KAAK;EAzBL,KAAK;EACL,OAAO;EACP,QAAQ;GACN;IAAE,MAAM;IAAiB,OAAO;IAAkB,UAAU;GAAK;GACjE;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAc,OAAO;GAAoC;GACjE;IAAE,MAAM;IAAQ,OAAO;GAAO;GAC9B;IAAE,MAAM;IAAS,OAAO;GAAQ;GAChC;IACE,MAAM;IACN,OAAO;IACP,MAAM,EAAE,SAAS;KAAE,OAAO;KAAqB,SAAS;IAAmB,EAAE;GAC/E;EACF;CAWK;AACP;;;;;;AAOA,SAAgB,wBAA2C;CACzD,OAAO,OAAO,KAAK,kBAAkB;AACvC;;;;;;;AAQA,SAAgB,qBAAqB,KAA4C;CAC/E,OAAO,mBAAmB;AAC5B"}
|
|
1
|
+
{"version":3,"file":"country-descriptors.js","names":[],"sources":["../../../src/matter/shipping-address/country-descriptors.ts"],"sourcesContent":["/**\n * Country-adaptive shipping address form descriptors.\n *\n * Each descriptor declares the form shape (field set, order, and labels) for a specific country.\n * Descriptors are primarily data — field set, order, and labels — but a `FieldDescriptor` may also\n * carry `required` and `rule`, the two validation facts a country varies. `ShippingAddressFieldset`\n * is the only reader of `required` (specs/shipping-address-fieldset.md, Decision 3): a field whose\n * descriptor entry is absent is never rendered, so it can carry no requiredness at all. `rule.pattern`\n * has two readers: the fieldset, through react-hook-form, and `satisfiesFieldPattern` below, which\n * `BillingAddress` applies to its own submit gate and field errors. A descriptor also carries the two\n * strings a country's form speaks for itself — the Country label and the required-message suffix — so\n * no copy of the delivery form is hardcoded in the fieldset.\n * Country adaptation is data-driven; adding a country is a data-only change (a new descriptor entry).\n *\n * Canonical field names must be shared/consistent across descriptors for fields both countries have\n * (recipientName, postalCode, street, number, complement, city, state), so that switching countries\n * preserves shared field values in the batched draft state (Decision 1/Invariant).\n *\n * Per Decision 2, this narrows the RFC's descriptor scope to form shape plus two per-field validation\n * facts: the non-blank recipient name and, per country, the postal code's format. Both descriptors'\n * `postalCode` entry carries a `pattern` rule matching that country's CEP or ZIP shape; every other\n * field's `rule` stays undefined. There is no server-side postal-code validation to fall back on:\n * `shippingAddressUpdate` types `postalCode` as a plain `z.string()`, forwards it verbatim with\n * `clearAddressIfPostalCodeNotFound: false`, and has no try/catch around the upstream call, so a\n * malformed value still returns HTTP 200 with an empty `userErrors` array. This client-side rule is\n * the only postal-code guard in the system today. The two forms apply it on different triggers: the\n * billing form judges a touched field on every render (through `getFieldIssue`, which reads\n * `satisfiesFieldPattern`), touching it on blur or when a refused submit focuses it, while the\n * delivery form's react-hook-form rule runs on submit and re-validates after it. A future\n * @vtex/country-forms adoption remains deferred.\n */\n\nimport type { FieldRule, FieldRuleConstraint } from '../../particles/field/field.js';\n\n/**\n * A descriptor's validation rule: a `FieldRule` whose `pattern` always carries the message a failing value\n * shows. A bare `RegExp` is not accepted, so both forms of a country's address read the one message for\n * one rule and no consumer needs a fallback string of its own.\n */\nexport type FieldDescriptorRule = Omit<FieldRule, 'pattern'> &\n Readonly<{\n pattern?: FieldRuleConstraint<RegExp>;\n }>;\n\n/**\n * Describes a single form field within a country descriptor.\n *\n * @property name - Canonical field name (e.g., \"recipientName\", \"street\", \"neighborhood\").\n * Shared field names across descriptors enable draft state preservation on country switch.\n * @property label - Human-readable label for the field. Named `label` (not a key) to allow future\n * swapping with i18n keys once the codebase adopts an i18n layer.\n */\nexport type FieldDescriptor = Readonly<{\n name: string;\n label: string;\n /**\n * Whether the fieldset requires a non-blank value. Read only by ShippingAddressFieldset, which\n * turns it into the field contract's `rule`. A field whose descriptor entry is absent is not\n * rendered, so it can carry no requiredness at all — that is the point (Decision 3).\n */\n required?: boolean;\n /**\n * Extra react-hook-form rules for this field in this country: pattern, minLength, and so on.\n * Merged under the generated `required`. Only `postalCode` carries one today. `pattern` is also read\n * by `satisfiesFieldPattern`, for forms that are not built on react-hook-form, and its `message` is the\n * copy every form shows for it.\n */\n rule?: FieldDescriptorRule;\n}>;\n\n/**\n * Describes the form shape for a single country.\n *\n * @property iso - ISO 3166-1 alpha-3 country code (e.g., \"BRA\", \"USA\"). Must be a valid 3-letter code\n * matching the Address.country field type (plain String!, ISO alpha-3 by convention).\n * @property label - Human-readable country name for the country selector (e.g., \"Brazil\", \"United States\").\n * Named `label` (not a key) to allow future swapping with i18n keys.\n * @property countryLabel - Default label of the country selector on this country's form, in the language of\n * the form's other copy. An authored `label` on the control wins.\n * @property requiredSuffix - Ends a required field's message (`${label} ${requiredSuffix}`), in the same\n * language as the field labels.\n * @property fields - Ordered field set for this country. Order defines the visual order in the form.\n * Only fields this country uses are listed; absent fields are not rendered.\n */\nexport type CountryDescriptor = Readonly<{\n iso: string;\n label: string;\n /** Default label of the country selector on this country's form; an authored `label` wins. */\n countryLabel: string;\n /** Closes a required field's message: `${label} ${requiredSuffix}`. */\n requiredSuffix: string;\n fields: readonly FieldDescriptor[];\n}>;\n\n/**\n * Whether `value` satisfies the field's declared `rule.pattern`. A field with no pattern, or a blank\n * value (empty or whitespace-only: blankness is the required rule's business, and a form that trims\n * before judging, as `BillingAddress` does, reads such a value as required, never as a format failure),\n * satisfies it. A non-blank value is tested raw, equivalent to the predicate react-hook-form applies\n * (`value.match(regex) !== null`), so both forms agree on every non-blank value. Blank values are the\n * one deliberate divergence: react-hook-form skips the pattern only for `''`, so for `' '` the\n * delivery form runs the pattern and reports the format, while this helper reports it satisfied and\n * leaves the verdict to the required rule. A caller that needs react-hook-form's exact verdict on a\n * blank value must not rely on this helper alone. `search` ignores a global regex's `lastIndex`, so\n * the descriptor's shared regex is never written to.\n */\nexport function satisfiesFieldPattern(field: FieldDescriptor, value: string): boolean {\n const pattern = field.rule?.pattern;\n if (!pattern || value.trim() === '') return true;\n return value.search(pattern.value) !== -1;\n}\n\n/**\n * Brazil (BRA) address form descriptor.\n *\n * Field order:\n * 1. recipientName — recipient of the package\n * 2. street — street name\n * 3. number — street number\n * 4. complement — apartment, suite, etc. (optional per GraphQL but no form-level validation)\n * 5. neighborhood — bairro (BR-specific, not in US form)\n * 6. city — city name\n * 7. state — state/UF code (canonical name shared with US, though US calls it state abbreviation)\n * 8. postalCode — CEP format, client-validated via `rule` (8 digits, hyphen after the fifth optional)\n */\nconst brDescriptor: CountryDescriptor = {\n iso: 'BRA',\n label: 'Brasil',\n countryLabel: 'país',\n requiredSuffix: 'é obrigatório',\n fields: [\n { name: 'recipientName', label: 'nome do destinatário', required: true },\n { name: 'street', label: 'rua' },\n { name: 'number', label: 'número' },\n { name: 'complement', label: 'complemento (opcional)' },\n { name: 'neighborhood', label: 'bairro' },\n { name: 'city', label: 'cidade' },\n { name: 'state', label: 'estado' },\n {\n name: 'postalCode',\n label: 'cep',\n rule: { pattern: { value: /^\\d{5}-?\\d{3}$/, message: 'cep inválido' } },\n },\n ],\n};\n\n/**\n * United States (USA) address form descriptor.\n *\n * Field order:\n * 1. recipientName — recipient of the package\n * 2. street — street name\n * 3. number — street number\n * 4. complement — apartment, suite, etc. (optional per GraphQL but no form-level validation)\n * 5. city — city name\n * 6. state — state abbreviation (canonical name shared with BR for draft preservation)\n * 7. postalCode — ZIP/ZIP+4 format, client-validated via `rule` (5 digits, optional 4-digit\n * extension, hyphen before it optional either way — accepts both `02101-1234` and `021011234`)\n *\n * Note: neighborhood is not included in the US v1 form. If the shopper switches from BR to US,\n * the neighborhood value is retained in the draft but hidden (descriptor controls visibility only);\n * switching back to BR resurfaces it.\n */\nconst usaDescriptor: CountryDescriptor = {\n iso: 'USA',\n label: 'United States',\n countryLabel: 'country',\n requiredSuffix: 'is required',\n fields: [\n { name: 'recipientName', label: 'recipient name', required: true },\n { name: 'street', label: 'street' },\n { name: 'number', label: 'number' },\n { name: 'complement', label: 'apartment, suite, etc. (optional)' },\n { name: 'city', label: 'city' },\n { name: 'state', label: 'state' },\n {\n name: 'postalCode',\n label: 'zip code',\n rule: { pattern: { value: /^\\d{5}(-?\\d{4})?$/, message: 'invalid zip code' } },\n },\n ],\n};\n\n/**\n * All available country descriptors, keyed by ISO alpha-3 code.\n *\n * The country selector lists only countries with a descriptor; a descriptor-less country is unreachable.\n * Adding a country is a data-only change: add a new CountryDescriptor entry here.\n */\nexport const countryDescriptors: Readonly<Record<string, CountryDescriptor>> = {\n BRA: brDescriptor,\n USA: usaDescriptor,\n};\n\n/**\n * Returns an ordered list of available country ISO codes (those with a descriptor).\n *\n * @returns ISO alpha-3 codes of all implemented countries, in definition order.\n */\nexport function getAvailableCountries(): readonly string[] {\n return Object.keys(countryDescriptors);\n}\n\n/**\n * Retrieves the descriptor for a given country.\n *\n * @param iso - ISO 3166-1 alpha-3 country code (e.g., \"BRA\", \"USA\")\n * @returns The CountryDescriptor for the country, or undefined if not implemented.\n */\nexport function getCountryDescriptor(iso: string): CountryDescriptor | undefined {\n return countryDescriptors[iso];\n}\n"],"mappings":";;;;;;;;;;;;;AA0GA,SAAgB,sBAAsB,OAAwB,OAAwB;CACpF,MAAM,UAAU,MAAM,MAAM;CAC5B,IAAI,CAAC,WAAW,MAAM,KAAK,MAAM,IAAI,OAAO;CAC5C,OAAO,MAAM,OAAO,QAAQ,KAAK,MAAM;AACzC;;;;;;;AA+EA,MAAa,qBAAkE;CAC7E,KAAK;EAhEL,KAAK;EACL,OAAO;EACP,cAAc;EACd,gBAAgB;EAChB,QAAQ;GACN;IAAE,MAAM;IAAiB,OAAO;IAAwB,UAAU;GAAK;GACvE;IAAE,MAAM;IAAU,OAAO;GAAM;GAC/B;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAc,OAAO;GAAyB;GACtD;IAAE,MAAM;IAAgB,OAAO;GAAS;GACxC;IAAE,MAAM;IAAQ,OAAO;GAAS;GAChC;IAAE,MAAM;IAAS,OAAO;GAAS;GACjC;IACE,MAAM;IACN,OAAO;IACP,MAAM,EAAE,SAAS;KAAE,OAAO;KAAkB,SAAS;IAAe,EAAE;GACxE;EACF;CA+CK;CACL,KAAK;EA3BL,KAAK;EACL,OAAO;EACP,cAAc;EACd,gBAAgB;EAChB,QAAQ;GACN;IAAE,MAAM;IAAiB,OAAO;IAAkB,UAAU;GAAK;GACjE;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAU,OAAO;GAAS;GAClC;IAAE,MAAM;IAAc,OAAO;GAAoC;GACjE;IAAE,MAAM;IAAQ,OAAO;GAAO;GAC9B;IAAE,MAAM;IAAS,OAAO;GAAQ;GAChC;IACE,MAAM;IACN,OAAO;IACP,MAAM,EAAE,SAAS;KAAE,OAAO;KAAqB,SAAS;IAAmB,EAAE;GAC/E;EACF;CAWK;AACP;;;;;;AAOA,SAAgB,wBAA2C;CACzD,OAAO,OAAO,KAAK,kBAAkB;AACvC;;;;;;;AAQA,SAAgB,qBAAqB,KAA4C;CAC/E,OAAO,mBAAmB;AAC5B"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { defineComponent } from "../../core/dist/define-component.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
-
import { Field, FieldBinding, FieldsetFieldContext, useFieldsetField, useFieldsetFieldNames, useNoAncestorFieldset } from "../../particles/field/field.js";
|
|
4
|
+
import { Field, FieldBinding, FieldsetFieldContext, readBaseline, useFieldsetField, useFieldsetFieldNames, useNoAncestorFieldset } from "../../particles/field/field.js";
|
|
5
5
|
import { useActionsOverride } from "../../sdk/actions/actions-override-context.js";
|
|
6
6
|
import { useDataOverride } from "../../sdk/data/data-override-context.js";
|
|
7
|
+
import { resolveAuthoredCopy } from "../../utils/resolve-authored-copy.js";
|
|
8
|
+
import { useFormRegistry } from "../../particles/form/form.js";
|
|
7
9
|
import { useEntityDataResolved } from "../../sdk/data/entity-resolution-context.js";
|
|
8
10
|
import { useReactiveDataSettled } from "../../sdk/data/use-reactive-data-settled.js";
|
|
9
11
|
import { Fieldset } from "../../particles/fieldset/fieldset.js";
|
|
10
12
|
import { getAvailableCountries, getCountryDescriptor } from "./country-descriptors.js";
|
|
11
|
-
import { useFormRegistry } from "../../particles/form/form.js";
|
|
12
13
|
import { FieldSelect } from "../../particles/select/field-select.js";
|
|
13
14
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
14
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
-
import { useWatch } from "react-hook-form";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
import { useFormContext, useWatch } from "react-hook-form";
|
|
16
17
|
//#region src/matter/shipping-address/shipping-address.tsx
|
|
17
18
|
/**
|
|
18
19
|
* Shipping address step (T2 — Enter and save the delivery address).
|
|
@@ -97,11 +98,11 @@ const FIELD_AUTOCOMPLETE = {
|
|
|
97
98
|
* declaration of the baseline. The blank check it used to hand-write alongside lives in
|
|
98
99
|
* `resolveRequiredness` now, installed for every bound control rather than only for this one.
|
|
99
100
|
*/
|
|
100
|
-
function buildRule(field, label) {
|
|
101
|
+
function buildRule(field, label, requiredSuffix) {
|
|
101
102
|
if (!field.required) return field.rule;
|
|
102
103
|
return {
|
|
103
104
|
...field.rule,
|
|
104
|
-
required: `${label}
|
|
105
|
+
required: `${label} ${requiredSuffix}`
|
|
105
106
|
};
|
|
106
107
|
}
|
|
107
108
|
/** Keeps only the AddressDraft keys `values` actually defines — a field no control composed is absent, not `undefined`. */
|
|
@@ -349,6 +350,49 @@ const ShippingAddressCountryControlDefinition = defineComponent({
|
|
|
349
350
|
} },
|
|
350
351
|
guideline: "Country selector; lists only countries with an implemented descriptor. Must be a descendant of ShippingAddressFieldset, which provides the shipping-address context this control requires. Recomposable: compose Field.Label, FieldSelect.Root and Field.Error as children, in any order; a childless composition keeps the default label-select-error order."
|
|
351
352
|
});
|
|
353
|
+
/** The message a constrained rule member carries; a bare value (or a bare `RegExp`) carries none. */
|
|
354
|
+
function messageOf(constraint) {
|
|
355
|
+
return typeof constraint === "object" && !(constraint instanceof RegExp) ? constraint.message : "";
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Every static message a rule carries, in a fixed order: the `required` copy in any of its three shapes,
|
|
359
|
+
* then the message of each constrained member. A `validate` record has no static copy, so it adds none.
|
|
360
|
+
*/
|
|
361
|
+
function messagesOf(rule) {
|
|
362
|
+
return [
|
|
363
|
+
readBaseline(rule).message ?? "",
|
|
364
|
+
messageOf(rule?.pattern),
|
|
365
|
+
messageOf(rule?.min),
|
|
366
|
+
messageOf(rule?.max),
|
|
367
|
+
messageOf(rule?.minLength),
|
|
368
|
+
messageOf(rule?.maxLength)
|
|
369
|
+
];
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* An error already on screen keeps the message of the rule that raised it, so a country switch would
|
|
373
|
+
* leave "é obrigatório" under a USA form until the shopper edits or submits again. A bound control
|
|
374
|
+
* therefore revalidates itself when the copy of its own rule changes while it carries an error: that
|
|
375
|
+
* re-words it from the new rule without newly flagging a field the shopper has not reached.
|
|
376
|
+
*
|
|
377
|
+
* It runs inside the control, as an effect of the component that renders the field's own subtree, so it
|
|
378
|
+
* always fires after that field's registration — `useController` re-registers `rules` during render, and
|
|
379
|
+
* descendants' effects precede their parent's — and never validates against the previous rule, whichever
|
|
380
|
+
* of the two the registration becomes. The first run counts as a change too: a field that remounts after
|
|
381
|
+
* a country without it keeps its error across the unmount (`shouldUnregister` being false) and comes
|
|
382
|
+
* back carrying the old wording.
|
|
383
|
+
*/
|
|
384
|
+
function useRewordErroredField(name, rule) {
|
|
385
|
+
const { getFieldState, trigger } = useFormContext();
|
|
386
|
+
const copy = messagesOf(rule).join("\n");
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
if (getFieldState(name).error) trigger(name);
|
|
389
|
+
}, [
|
|
390
|
+
copy,
|
|
391
|
+
name,
|
|
392
|
+
getFieldState,
|
|
393
|
+
trigger
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
352
396
|
/**
|
|
353
397
|
* ShippingAddressFieldset — this entity's root: same data, same action as a page-level submit
|
|
354
398
|
* would use, dispatched at form-submit time instead of through a button of its own. Registers one
|
|
@@ -408,12 +452,13 @@ function ShippingAddressFieldset({ defaultCountry = "BRA", skeletonCount = SHIPP
|
|
|
408
452
|
});
|
|
409
453
|
const activeCountry = typeof watchedCountry === "string" && watchedCountry || seed.country;
|
|
410
454
|
const descriptor = getCountryDescriptor(activeCountry);
|
|
455
|
+
const requiredSuffix = descriptor?.requiredSuffix ?? "";
|
|
411
456
|
const fieldFor = useCallback((key) => descriptor?.fields.find((f) => f.name === key), [descriptor]);
|
|
412
457
|
const seedFor = useCallback((key) => seed[key], [seed]);
|
|
413
458
|
const ruleFor = useCallback((key, label) => {
|
|
414
459
|
const field = fieldFor(key);
|
|
415
|
-
return field ? buildRule(field, label
|
|
416
|
-
}, [fieldFor]);
|
|
460
|
+
return field ? buildRule(field, label, requiredSuffix) : void 0;
|
|
461
|
+
}, [fieldFor, requiredSuffix]);
|
|
417
462
|
const countryOptions = useMemo(() => getAvailableCountries().map((iso) => ({
|
|
418
463
|
value: iso,
|
|
419
464
|
label: getCountryDescriptor(iso)?.label ?? iso
|
|
@@ -510,18 +555,20 @@ function ShippingAddressFieldsetSkeleton({ count = SHIPPING_ADDRESS_SKELETON_ROW
|
|
|
510
555
|
ShippingAddressFieldset.Skeleton = ShippingAddressFieldsetSkeleton;
|
|
511
556
|
function BoundAddressTextField({ fieldKey, slug, className, label, placeholder, children, fieldsetCtx, fieldDescriptor }) {
|
|
512
557
|
const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, fieldKey);
|
|
513
|
-
const resolvedLabel = label
|
|
558
|
+
const resolvedLabel = resolveAuthoredCopy(label, fieldDescriptor.label);
|
|
559
|
+
const rule = fieldsetCtx.ruleFor(fieldKey, resolvedLabel);
|
|
560
|
+
useRewordErroredField(name, rule);
|
|
514
561
|
return /* @__PURE__ */ jsx(FieldBinding, {
|
|
515
562
|
name,
|
|
516
563
|
label: resolvedLabel,
|
|
517
564
|
placeholder,
|
|
518
565
|
defaultValue: fieldsetCtx.seedFor(fieldKey),
|
|
519
|
-
rule
|
|
566
|
+
rule,
|
|
520
567
|
autoComplete: FIELD_AUTOCOMPLETE[fieldKey],
|
|
521
568
|
children: /* @__PURE__ */ jsx(Field.Root, {
|
|
522
569
|
className,
|
|
523
570
|
"data-fs-shipping-address-field": slug,
|
|
524
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
571
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
525
572
|
/* @__PURE__ */ jsx(Field.Label, {}),
|
|
526
573
|
/* @__PURE__ */ jsx(Field.Control, {}),
|
|
527
574
|
/* @__PURE__ */ jsx(Field.Error, {})
|
|
@@ -673,16 +720,17 @@ function ShippingAddressCountryControl({ className, label, placeholder, children
|
|
|
673
720
|
return /* @__PURE__ */ jsx(BoundShippingAddressCountryControl, {
|
|
674
721
|
className,
|
|
675
722
|
label,
|
|
723
|
+
defaultLabel: fieldsetCtx.descriptor.countryLabel,
|
|
676
724
|
placeholder,
|
|
677
725
|
fieldsetCtx,
|
|
678
726
|
children
|
|
679
727
|
});
|
|
680
728
|
}
|
|
681
|
-
function BoundShippingAddressCountryControl({ className, label, placeholder, children, fieldsetCtx }) {
|
|
729
|
+
function BoundShippingAddressCountryControl({ className, label, defaultLabel, placeholder, children, fieldsetCtx }) {
|
|
682
730
|
const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, "country");
|
|
683
731
|
return /* @__PURE__ */ jsx(FieldBinding, {
|
|
684
732
|
name,
|
|
685
|
-
label: label
|
|
733
|
+
label: resolveAuthoredCopy(label, defaultLabel),
|
|
686
734
|
placeholder: placeholder ?? fieldsetCtx.descriptor?.label,
|
|
687
735
|
defaultValue: fieldsetCtx.seedFor("country"),
|
|
688
736
|
options: fieldsetCtx.countryOptions,
|
|
@@ -690,7 +738,7 @@ function BoundShippingAddressCountryControl({ className, label, placeholder, chi
|
|
|
690
738
|
children: /* @__PURE__ */ jsx(Field.Root, {
|
|
691
739
|
className,
|
|
692
740
|
"data-fs-shipping-address-field": "country",
|
|
693
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
741
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
694
742
|
/* @__PURE__ */ jsx(Field.Label, {}),
|
|
695
743
|
/* @__PURE__ */ jsx(FieldSelect.Root, {}),
|
|
696
744
|
/* @__PURE__ */ jsx(Field.Error, {})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shipping-address.js","names":[],"sources":["../../../src/matter/shipping-address/shipping-address.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 useState,\n} from 'react';\nimport { useWatch } from 'react-hook-form';\nimport {\n Field,\n FieldBinding,\n type FieldOption,\n type FieldRule,\n FieldsetFieldContext,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { type FieldsetRegistration, type FormUserError, useFormRegistry } from '../../particles/form/form.js';\nimport { FieldSelect } from '../../particles/select/field-select.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 { ShippingAddressInput } from '../../sdk/shipping/shipping-operations.js';\nimport type { CountryDescriptor, FieldDescriptor } from './country-descriptors.js';\nimport { getAvailableCountries, getCountryDescriptor } from './country-descriptors.js';\n\n/**\n * Shipping address step (T2 — Enter and save the delivery address).\n * Single-file matter per ADR-0001; batches form state and writes once via shipping.setAddress.\n * Controls are thin context-bound components that read/write draft state (docs/storefront-core/reference-cart.md § Delivery).\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\n/**\n * The fieldset's own fragment. Drops `savedAddresses` — the fieldset has no saved-address UI of\n * its own (Decision 1 of specs/shipping-address-fieldset.md).\n *\n * `clientProfile` selects `id` even though nothing renders it. The reactive runtime resolves each\n * root field to a cache reference through `cache.identify`, which needs `__typename` and `id`; with\n * no `id` in the composed page query the profile never normalises, `useReactiveEntity` keeps\n * returning the server's `fallbackData`, and a page composing this fieldset without\n * `ClientProfileFieldset` would show a logged-in shopper a blank recipient name instead of the one\n * US-4 fills in from their profile.\n */\nconst fieldsetFragment = /* GraphQL */ `\n fragment ShippingAddressFieldsetData on Query {\n shipping {\n __typename\n id\n address {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n }\n clientProfile {\n __typename\n id\n firstName\n lastName\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * The `$data` slice forwarded to `ShippingAddressFieldset` by the reactive runtime. Selects two\n * root fields (`shipping`, `clientProfile`), so the compiler composes them via\n * `MultipleReactiveDataProvider`, which keys each entity's resolved slice by its own root field —\n * `$data` is `{ shipping: {...}, clientProfile: {...} }`, not a flat/unwrapped shape (that unwrapped\n * shape only applies to single-root-field fragments, e.g. CartTotalizerRoot's `$data.totalizers`).\n * Carries no `savedAddresses` — the fieldset has no saved-address UI of its own (Decision 1).\n */\nexport type ShippingAddressFieldsetData = {\n shipping?: {\n address?: {\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country?: string | null;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n } | null;\n } | null;\n clientProfile?: {\n firstName?: string | null;\n lastName?: string | null;\n } | null;\n} | null;\n\n/** The batched draft state, keyed by canonical field name (Decision 1). */\ntype AddressDraft = {\n recipientName: string;\n postalCode: string;\n country: string;\n street: string;\n number: string;\n complement: string;\n neighborhood: string;\n city: string;\n state: string;\n};\n\n// ---------------------------------------------------------------------------\n// Fieldset context\n// ---------------------------------------------------------------------------\n\n/** The react-hook-form namespace every field of this entity registers under. */\nconst SHIPPING_ADDRESS_NAMESPACE = 'shippingAddress';\n\n/** Canonical field keys, matching AddressDraft's keys and the descriptors' `name` values. */\nexport type ShippingAddressFieldKey = keyof AddressDraft;\n\n/** What a bound Control needs from its fieldset. Carries no live value. */\ntype ShippingAddressFieldsetContextValue = Readonly<{\n namespace: string;\n /** The active country's descriptor, or undefined when the country has none. */\n descriptor: CountryDescriptor | undefined;\n /** The descriptor entry for a key, or undefined when this country does not have the field. */\n fieldFor: (key: ShippingAddressFieldKey) => FieldDescriptor | undefined;\n /** The value this field registers with as react-hook-form's field-level defaultValue. */\n seedFor: (key: ShippingAddressFieldKey) => string;\n /**\n * The rule for a rendered field. `label`, when given, overrides the descriptor's own label in\n * the generated required-message copy — an authored `label` renames the field in its own error\n * message, not just on screen. Never called for a field with no descriptor entry.\n */\n ruleFor: (key: ShippingAddressFieldKey, label?: string) => FieldRule | undefined;\n /** Only for `country`: the platform's option list, contract-shaped. */\n countryOptions: readonly FieldOption[];\n}>;\n\nconst ShippingAddressFieldsetContext = createContext<ShippingAddressFieldsetContextValue | null>(null);\n\n/**\n * Read before any field hook (Decision 4): a control calls this before looking up its own\n * descriptor entry, so a field the active descriptor does not declare never calls\n * `useFieldsetField`/`useController` and so never registers with react-hook-form at all. Throws\n * when rendered with no `ShippingAddressFieldset` above it (Decision 2), naming the required\n * composition.\n */\nfunction useShippingAddressFieldsetContext(): ShippingAddressFieldsetContextValue {\n const ctx = useContext(ShippingAddressFieldsetContext);\n if (!ctx) {\n throw new Error('ShippingAddress*Control components must be used inside ShippingAddressFieldset.');\n }\n return ctx;\n}\n\n/**\n * Rows `ShippingAddressFieldsetSkeleton` draws when nobody says otherwise: one per Control in the\n * full anatomy, the nine of them. It is a default and not a derivation — the skeleton renders before\n * any address has resolved, so it cannot read the live descriptor, and the composed Controls are\n * opaque children. A page that composes fewer than nine sets `skeletonCount` to what it composed,\n * or the form jumps by the difference when the Controls take the skeleton's place.\n */\nconst SHIPPING_ADDRESS_SKELETON_ROWS = 9;\n\n/** `autoComplete` tokens per field (US-3, WCAG 2.1 SC 1.3.5). `number` has no standard token. */\nconst FIELD_AUTOCOMPLETE: Readonly<Record<ShippingAddressFieldKey, string | undefined>> = {\n recipientName: 'name',\n postalCode: 'postal-code',\n country: 'country',\n street: 'address-line1',\n number: undefined,\n complement: 'address-line2',\n neighborhood: 'address-level3',\n city: 'address-level2',\n state: 'address-level1',\n};\n\n/**\n * Merges the descriptor's own `rule` under a generated `required`, which is this fieldset's whole\n * declaration of the baseline. The blank check it used to hand-write alongside lives in\n * `resolveRequiredness` now, installed for every bound control rather than only for this one.\n */\nfunction buildRule(field: FieldDescriptor, label: string): FieldRule | undefined {\n if (!field.required) return field.rule;\n return { ...field.rule, required: `${label} é obrigatório` };\n}\n\n/** Keeps only the AddressDraft keys `values` actually defines — a field no control composed is absent, not `undefined`. */\nfunction pickDefinedAddressFields(values: Record<string, unknown>): Partial<AddressDraft> {\n const result: Partial<AddressDraft> = {};\n for (const key of Object.keys(values) as ShippingAddressFieldKey[]) {\n const value = values[key];\n if (value !== undefined) result[key] = value as string;\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Props Types\n// ---------------------------------------------------------------------------\n\nexport type ShippingAddressFieldsetProps = {\n /** Country used when the stored address has none. */\n defaultCountry?: string;\n /** Placeholder rows the loading skeleton draws. Set it to the number of Controls composed here. */\n skeletonCount?: number;\n /** Announced politely while the address resolves. 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 /** `ShippingAddressFieldsetData` forwarded by the reactive runtime. */\n $data?: ShippingAddressFieldsetData;\n /** Compiler-injected action surface; carries `shipping.setAddress`. */\n $actions?: ComponentActions;\n};\n\nexport type ShippingAddressStreetControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressNumberControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressCityControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressStateControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressPostalCodeControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressComplementControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressNeighborhoodControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressCountryControlProps = {\n className?: string;\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, FieldSelect.Root, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressRecipientNameControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\n// ---------------------------------------------------------------------------\n// Root Definition\n// ---------------------------------------------------------------------------\n\nexport const ShippingAddressFieldsetDefinition = defineComponent<ShippingAddressFieldsetProps>({\n name: 'ShippingAddressFieldset',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressFieldset,\n fragment: fieldsetFragment,\n fetchStrategy: 'reactive',\n skeleton: ShippingAddressFieldsetSkeleton,\n actions: { shipping: ['setAddress'] },\n requiresContext: 'form',\n providesContext: 'shipping-address',\n editor: { label: 'Shipping Address Fieldset', category: 'commerce' },\n schema: {\n defaultCountry: { type: 'string', default: 'BRA', label: 'Default country (ISO-3)' },\n skeletonCount: { type: 'number', default: 9, label: 'Skeleton rows' },\n loadingLabel: { type: 'string', default: 'Loading your delivery address', label: 'Loading announcement' },\n loadedLabel: { type: 'string', default: 'Your delivery address is ready', label: 'Loaded announcement' },\n groupLabel: { type: 'string', default: 'Your delivery address', label: 'Accessible group name' },\n },\n guideline:\n 'Composable delivery-address entity: registers under \"shippingAddress\" with the enclosing FormRoot and dispatches shipping.setAddress only when the shopper changed something. Compose the nine ShippingAddress*Control parts inside it; place FormSubmit/FormEnterSubmit/FormError as siblings of the fieldset, not inside it — this fieldset renders no submit or error part of its own. The Controls mount only once the address has 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. groupLabel names the group as its accessible name; blank emits no aria-label, and a composed FieldsetLegend wins over it. See shipping-address.md.',\n});\n\n// Control Definitions\n// Shared by all eight text Controls below (RFC:503): states the requiresContext and the\n// recomposable anatomy every one of them shares.\nconst ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX =\n 'Must be a descendant of ShippingAddressFieldset, which provides the shipping-address context this control requires. Recomposable: compose Field.Label, Field.Control and Field.Error as children, in any order, to reorder or extend the anatomy; a childless composition keeps the default label-control-error order.';\n\nexport const ShippingAddressRecipientNameControlDefinition = defineComponent<ShippingAddressRecipientNameControlProps>({\n name: 'ShippingAddressRecipientNameControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressRecipientNameControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Recipient Name Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Recipient-name input field; required for submit. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressStreetControlDefinition = defineComponent<ShippingAddressStreetControlProps>({\n name: 'ShippingAddressStreetControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressStreetControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Street Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Street name input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressNumberControlDefinition = defineComponent<ShippingAddressNumberControlProps>({\n name: 'ShippingAddressNumberControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressNumberControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Number Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Street number input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressCityControlDefinition = defineComponent<ShippingAddressCityControlProps>({\n name: 'ShippingAddressCityControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressCityControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'City Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `City name input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressStateControlDefinition = defineComponent<ShippingAddressStateControlProps>({\n name: 'ShippingAddressStateControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressStateControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'State Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `State/province input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressPostalCodeControlDefinition = defineComponent<ShippingAddressPostalCodeControlProps>({\n name: 'ShippingAddressPostalCodeControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressPostalCodeControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Postal Code Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Postal code input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressComplementControlDefinition = defineComponent<ShippingAddressComplementControlProps>({\n name: 'ShippingAddressComplementControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressComplementControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Complement Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Complement (apartment, suite, etc.) input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressNeighborhoodControlDefinition = defineComponent<ShippingAddressNeighborhoodControlProps>({\n name: 'ShippingAddressNeighborhoodControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressNeighborhoodControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Neighborhood Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Neighborhood (bairro) input field; shown only for countries that have this field (BR in v1). ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressCountryControlDefinition = defineComponent<ShippingAddressCountryControlProps>({\n name: 'ShippingAddressCountryControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressCountryControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Country Control', category: 'action' },\n schema: {\n // No default (Decision 11): absence means the platform's value ('país'), applied at render time\n // by the control itself, not baked into the schema.\n label: { type: 'string', label: 'Field label' },\n },\n guideline:\n 'Country selector; lists only countries with an implemented descriptor. Must be a descendant of ShippingAddressFieldset, which provides the shipping-address context this control requires. Recomposable: compose Field.Label, FieldSelect.Root and Field.Error as children, in any order; a childless composition keeps the default label-select-error order.',\n});\n\n// ---------------------------------------------------------------------------\n// Fieldset Component\n// ---------------------------------------------------------------------------\n\n/**\n * ShippingAddressFieldset — this entity's root: same data, same action as a page-level submit\n * would use, dispatched at form-submit time instead of through a button of its own. Registers one\n * `FieldsetRegistration` with the enclosing `FormRoot` under the `shippingAddress` namespace,\n * derives the active country descriptor from react-hook-form (Decision 2), and publishes each\n * field's seed/rule/label through its own context so a bound Control never writes a validation\n * expression. Renders no button and holds no draft of its own.\n *\n * Its controls mount only once the entity has resolved; until then the `Fieldset.Root` carries\n * `-pending` and renders `ShippingAddressFieldsetSkeleton`. \"Resolved\" is two conditions, because\n * `$data` alone cannot answer it: under the reactive runtime the slice is defined from the first\n * render — `useReactiveEntity` hands down `fallbackData` while the cache read is incomplete — so an\n * empty server answer looks exactly like a resolved one, and every control would mount seeded `''`\n * before the shopper's stored address arrives. Each seed reaches react-hook-form as a field-level\n * `defaultValue`; `useSeedAdoption` re-seeds a clean field with it on every render, but once the\n * field turns dirty no later seed ever reaches it again (Decision 12). Mounting before the answer\n * arrives would seed `''`: a shopper who starts typing before the real value lands makes the field\n * dirty on that empty seed, permanently locking their saved address out of it, and even a shopper who\n * does not type sees the field flash from `''` to the real data. `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\n * trees with no reactive root above them, where 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\n * polite live region that announces `loadingLabel` and then `loadedLabel`. Style the region\n * `sr-only` — it is text meant for a screen reader, not for the page.\n */\nexport function ShippingAddressFieldset({\n defaultCountry = 'BRA',\n skeletonCount = SHIPPING_ADDRESS_SKELETON_ROWS,\n loadingLabel = 'Loading your delivery address',\n loadedLabel = 'Your delivery address is ready',\n groupLabel = 'Your delivery address',\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ShippingAddressFieldsetProps): ReactNode {\n // First hook called: throws the named registry error when no FormRoot is above (US-1, 5th\n // criterion), before any react-hook-form hook below has a chance to run against a missing context.\n const { registerFieldset } = useFormRegistry();\n\n // Guards runtime registry integrity the same way FormRoot's namespace-collision throw does:\n // useFieldsetField resolves the *nearest* FieldsetFieldContext, not the fieldset that owns a\n // given namespace, so a fieldset nested inside another one would register its controls' names\n // into the ancestor's name set instead of its own — FormClear, FormReset and post-dispatch\n // reconciliation would then act on the wrong fields. Nesting fieldsets has no legitimate use,\n // so this throws at mount rather than silently misrouting names.\n useNoAncestorFieldset('ShippingAddressFieldset');\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 const currentAddress = $data?.shipping?.address;\n const clientProfile = $data?.clientProfile;\n const joinedProfileName = [clientProfile?.firstName, clientProfile?.lastName].filter(Boolean).join(' ');\n\n // The one seed record every field registers with as react-hook-form's own defaultValue (Decision\n // 12) — resolved fresh from $data on every render and re-applied to every already-mounted field\n // that is still clean; a field the shopper has started editing turns dirty and locks this out.\n const seed = useMemo<AddressDraft>(\n () => ({\n recipientName: currentAddress?.recipientName ?? joinedProfileName,\n postalCode: currentAddress?.postalCode ?? '',\n country: currentAddress?.country ?? defaultCountry,\n street: currentAddress?.street ?? '',\n number: currentAddress?.number ?? '',\n complement: currentAddress?.complement ?? '',\n neighborhood: currentAddress?.neighborhood ?? '',\n city: currentAddress?.city ?? '',\n state: currentAddress?.state ?? '',\n }),\n [currentAddress, joinedProfileName, defaultCountry],\n );\n\n // Decision 2: the descriptor is derived from react-hook-form, not from a draft of our own, so a\n // country change reshapes the form with one subscription and no re-seeding effect. `FormClear`\n // can drive the live value to '' (the select itself never offers an empty option); falling back\n // to the seeded country there keeps every field — including the required recipient name — mounted\n // and focusable instead of vanishing the moment the form is cleared.\n const watchedCountry = useWatch({ name: `${SHIPPING_ADDRESS_NAMESPACE}.country`, defaultValue: seed.country });\n const activeCountry = (typeof watchedCountry === 'string' && watchedCountry) || seed.country;\n const descriptor = getCountryDescriptor(activeCountry);\n\n const fieldFor = useCallback(\n (key: ShippingAddressFieldKey) => descriptor?.fields.find((f) => f.name === key),\n [descriptor],\n );\n const seedFor = useCallback((key: ShippingAddressFieldKey) => seed[key], [seed]);\n const ruleFor = useCallback(\n (key: ShippingAddressFieldKey, label?: string) => {\n const field = fieldFor(key);\n return field ? buildRule(field, label ?? field.label) : undefined;\n },\n [fieldFor],\n );\n const countryOptions = useMemo<readonly FieldOption[]>(\n () => getAvailableCountries().map((iso) => ({ value: iso, label: getCountryDescriptor(iso)?.label ?? iso })),\n [],\n );\n\n const fieldsetContextValue = useMemo<ShippingAddressFieldsetContextValue>(\n () => ({ namespace: SHIPPING_ADDRESS_NAMESPACE, descriptor, fieldFor, seedFor, ruleFor, countryOptions }),\n [descriptor, fieldFor, seedFor, ruleFor, countryOptions],\n );\n\n // Collects the field names this fieldset's own controls currently have mounted (FR 3), over the\n // seam `particles/field/field.tsx` exports for exactly this purpose.\n const { registry: fieldRegistryValue, getFieldNames } = useFieldsetFieldNames(SHIPPING_ADDRESS_NAMESPACE);\n\n // Deliberately NOT dirty-only (T21 Decision 4), unlike ClientProfileFieldset/ClientPreferencesFieldset:\n // `ShippingAddressUpdateInput` declares `recipientName`, `postalCode` and `country` non-null\n // (core.graphql:2446-2450), so a payload carrying only the changed keys is invalid by construction.\n // Sending the whole active-country address, seed-merged with the live values, is the correct shape\n // for this mutation's contract — not an oversight to \"fix\" into dirty-only.\n const toPayload = useCallback(\n (values: Record<string, unknown>): Record<string, unknown> => {\n const merged = { ...seed, ...pickDefinedAddressFields(values) } as AddressDraft;\n const country = String(merged.country || seed.country);\n const active = getCountryDescriptor(country);\n const isActive = (key: ShippingAddressFieldKey) => active?.fields.some((f) => f.name === key) ?? false;\n\n return {\n country,\n ...(isActive('recipientName') ? { recipientName: String(merged.recipientName ?? '').trim() } : {}),\n ...(isActive('postalCode') ? { postalCode: merged.postalCode } : {}),\n ...(isActive('street') ? { street: merged.street } : {}),\n ...(isActive('number') ? { number: merged.number } : {}),\n ...(isActive('complement') ? { complement: merged.complement } : {}),\n ...(isActive('neighborhood') ? { neighborhood: merged.neighborhood } : {}),\n ...(isActive('city') ? { city: merged.city } : {}),\n ...(isActive('state') ? { state: merged.state } : {}),\n };\n },\n [seed],\n );\n\n const dispatch = useCallback(\n async (payload: Record<string, unknown>): Promise<readonly FormUserError[]> => {\n if (!$actions?.shipping?.setAddress) {\n // The form reports a failure rather than silently succeeding (FR 13).\n throw new Error('ShippingAddressFieldset requires $actions.shipping.setAddress.');\n }\n return $actions.shipping.setAddress(payload as ShippingAddressInput);\n },\n [$actions],\n );\n\n const registration = useMemo<FieldsetRegistration>(\n () => ({\n namespace: SHIPPING_ADDRESS_NAMESPACE,\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` (`shippingAddress` → `shipping-address`) — not authored per\n // page (Decision 2).\n label: 'shipping-address',\n }),\n [getFieldNames, dispatch, toPayload],\n );\n\n // Registered from the mount commit, like the other two fieldsets, because `FormRoot` takes a\n // fieldset's dispatch slot from its first registration: deferring it until the entity resolves\n // would put this fieldset after every sibling that registered at mount, whatever their order in\n // the document.\n //\n // Registering early cannot send an unresolved seed. `toPayload` is whole-entity here\n // (`ShippingAddressUpdateInput` declares three fields non-null, so the payload is\n // `{ ...seed, ...liveValues }`), which makes a placeholder seed sendable, but the Controls mount only\n // once the entity has resolved. Until then `getFieldNames()` is empty and `FormRoot` finds nothing of\n // this fieldset that could be dirty — including a field the shopper edited before the slice regressed.\n useEffect(() => registerFieldset(registration), [registerFieldset, registration]);\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 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-shipping-address-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-shipping-address-fieldset-pending': '' })}\n >\n <ShippingAddressFieldsetContext.Provider value={fieldsetContextValue}>\n <FieldsetFieldContext.Provider value={fieldRegistryValue}>\n {resolved ? children : <ShippingAddressFieldsetSkeleton count={skeletonCount} />}\n </FieldsetFieldContext.Provider>\n </ShippingAddressFieldsetContext.Provider>\n <output aria-live=\"polite\" data-fs-shipping-address-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\n * live region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ShippingAddressFieldsetSkeleton({\n count = SHIPPING_ADDRESS_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-shipping-address-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-shipping-address-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nShippingAddressFieldset.Skeleton = ShippingAddressFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Control Components (thin, context-bound, reuse particles)\n//\n// Each control reads the fieldset context and finds its descriptor entry *before* calling any\n// field hook, so a field the active descriptor does not declare never calls\n// `useFieldsetField`/`useController` and so never registers with react-hook-form at all\n// (Decision 4).\n// ---------------------------------------------------------------------------\n\n/** The eight text fields' shared anatomy (Decision 6): `FieldBinding > Field.Root > (Field.Label, Field.Control, Field.Error)`. */\ntype BoundAddressTextFieldProps = {\n fieldKey: Exclude<ShippingAddressFieldKey, 'country'>;\n slug: string;\n className?: string;\n label?: string;\n placeholder?: string;\n children?: ReactNode;\n fieldsetCtx: ShippingAddressFieldsetContextValue;\n fieldDescriptor: FieldDescriptor;\n};\n\nfunction BoundAddressTextField({\n fieldKey,\n slug,\n className,\n label,\n placeholder,\n children,\n fieldsetCtx,\n fieldDescriptor,\n}: BoundAddressTextFieldProps) {\n const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, fieldKey);\n // Resolved once and threaded into both the visible label and the rule, so an authored `label`\n // renames the field in its own required-message copy too (spec 806-809), not just on screen.\n const resolvedLabel = label ?? fieldDescriptor.label;\n\n return (\n <FieldBinding\n name={name}\n label={resolvedLabel}\n placeholder={placeholder}\n defaultValue={fieldsetCtx.seedFor(fieldKey)}\n rule={fieldsetCtx.ruleFor(fieldKey, resolvedLabel)}\n autoComplete={FIELD_AUTOCOMPLETE[fieldKey]}\n >\n <Field.Root className={className} data-fs-shipping-address-field={slug}>\n {children ?? (\n <>\n <Field.Label />\n <Field.Control />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\n/**\n * RecipientNameControl — the only required field (US-4, US-6); the postal code is client-validated\n * too, against the active country's format.\n * Pre-filled from clientProfile, editable, required.\n */\nexport function ShippingAddressRecipientNameControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressRecipientNameControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('recipientName');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"recipientName\"\n slug=\"recipient-name\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** StreetControl */\nexport function ShippingAddressStreetControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressStreetControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('street');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"street\"\n slug=\"street\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** NumberControl */\nexport function ShippingAddressNumberControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressNumberControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('number');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"number\"\n slug=\"number\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** CityControl */\nexport function ShippingAddressCityControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressCityControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('city');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"city\"\n slug=\"city\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** StateControl */\nexport function ShippingAddressStateControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressStateControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('state');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"state\"\n slug=\"state\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** PostalCodeControl */\nexport function ShippingAddressPostalCodeControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressPostalCodeControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('postalCode');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"postalCode\"\n slug=\"postal-code\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** ComplementControl */\nexport function ShippingAddressComplementControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressComplementControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('complement');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"complement\"\n slug=\"complement\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** NeighborhoodControl (BR-specific in v1) */\nexport function ShippingAddressNeighborhoodControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressNeighborhoodControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('neighborhood');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"neighborhood\"\n slug=\"neighborhood\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/**\n * CountryControl — moves onto `FieldSelect` (Decision 8): the trigger resolves a country name from\n * the field contract's `options`. Gated on `descriptor`, not on a per-field entry (country has\n * none): a country with no descriptor renders no controls at all (Decision 3/4's \"no entry, no\n * control\" applied to the field that selects the entry itself).\n */\nexport function ShippingAddressCountryControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressCountryControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n if (!fieldsetCtx.descriptor) return null;\n return (\n <BoundShippingAddressCountryControl\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n >\n {children}\n </BoundShippingAddressCountryControl>\n );\n}\n\ntype BoundShippingAddressCountryControlProps = {\n className?: string;\n label?: string;\n placeholder?: string;\n children?: ReactNode;\n fieldsetCtx: ShippingAddressFieldsetContextValue;\n};\n\nfunction BoundShippingAddressCountryControl({\n className,\n label,\n placeholder,\n children,\n fieldsetCtx,\n}: BoundShippingAddressCountryControlProps) {\n const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, 'country');\n\n return (\n <FieldBinding\n name={name}\n label={label ?? 'país'}\n // Falls back to the active descriptor's label (already the FormClear-safe activeCountry,\n // not the raw watched value — Decision 2) so the trigger shows the country that will\n // actually be sent even when react-hook-form's own value is '' (e.g. right after\n // FormClear), instead of resolveOptionLabel('') rendering nothing at all.\n placeholder={placeholder ?? fieldsetCtx.descriptor?.label}\n defaultValue={fieldsetCtx.seedFor('country')}\n options={fieldsetCtx.countryOptions}\n autoComplete={FIELD_AUTOCOMPLETE.country}\n >\n <Field.Root className={className} data-fs-shipping-address-field=\"country\">\n {children ?? (\n <>\n <Field.Label />\n <FieldSelect.Root />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace Export\n// ---------------------------------------------------------------------------\n\nexport const ShippingAddress = {\n Fieldset: ShippingAddressFieldset,\n FieldsetDefinition: ShippingAddressFieldsetDefinition,\n FieldsetSkeleton: ShippingAddressFieldsetSkeleton,\n RecipientNameControl: ShippingAddressRecipientNameControl,\n RecipientNameControlDefinition: ShippingAddressRecipientNameControlDefinition,\n StreetControl: ShippingAddressStreetControl,\n StreetControlDefinition: ShippingAddressStreetControlDefinition,\n NumberControl: ShippingAddressNumberControl,\n NumberControlDefinition: ShippingAddressNumberControlDefinition,\n CityControl: ShippingAddressCityControl,\n CityControlDefinition: ShippingAddressCityControlDefinition,\n StateControl: ShippingAddressStateControl,\n StateControlDefinition: ShippingAddressStateControlDefinition,\n PostalCodeControl: ShippingAddressPostalCodeControl,\n PostalCodeControlDefinition: ShippingAddressPostalCodeControlDefinition,\n ComplementControl: ShippingAddressComplementControl,\n ComplementControlDefinition: ShippingAddressComplementControlDefinition,\n NeighborhoodControl: ShippingAddressNeighborhoodControl,\n NeighborhoodControlDefinition: ShippingAddressNeighborhoodControlDefinition,\n CountryControl: ShippingAddressCountryControl,\n CountryControlDefinition: ShippingAddressCountryControlDefinition,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shipping-address.js","names":[],"sources":["../../../src/matter/shipping-address/shipping-address.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 useState,\n} from 'react';\nimport { useFormContext, useWatch } from 'react-hook-form';\nimport {\n Field,\n FieldBinding,\n type FieldOption,\n type FieldRule,\n type FieldRuleConstraint,\n FieldsetFieldContext,\n readBaseline,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { type FieldsetRegistration, type FormUserError, useFormRegistry } from '../../particles/form/form.js';\nimport { FieldSelect } from '../../particles/select/field-select.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 { ShippingAddressInput } from '../../sdk/shipping/shipping-operations.js';\nimport { resolveAuthoredCopy } from '../../utils/resolve-authored-copy.js';\nimport type { CountryDescriptor, FieldDescriptor } from './country-descriptors.js';\nimport { getAvailableCountries, getCountryDescriptor } from './country-descriptors.js';\n\n/**\n * Shipping address step (T2 — Enter and save the delivery address).\n * Single-file matter per ADR-0001; batches form state and writes once via shipping.setAddress.\n * Controls are thin context-bound components that read/write draft state (docs/storefront-core/reference-cart.md § Delivery).\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment\n// ---------------------------------------------------------------------------\n\n/**\n * The fieldset's own fragment. Drops `savedAddresses` — the fieldset has no saved-address UI of\n * its own (Decision 1 of specs/shipping-address-fieldset.md).\n *\n * `clientProfile` selects `id` even though nothing renders it. The reactive runtime resolves each\n * root field to a cache reference through `cache.identify`, which needs `__typename` and `id`; with\n * no `id` in the composed page query the profile never normalises, `useReactiveEntity` keeps\n * returning the server's `fallbackData`, and a page composing this fieldset without\n * `ClientProfileFieldset` would show a logged-in shopper a blank recipient name instead of the one\n * US-4 fills in from their profile.\n */\nconst fieldsetFragment = /* GraphQL */ `\n fragment ShippingAddressFieldsetData on Query {\n shipping {\n __typename\n id\n address {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n }\n clientProfile {\n __typename\n id\n firstName\n lastName\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * The `$data` slice forwarded to `ShippingAddressFieldset` by the reactive runtime. Selects two\n * root fields (`shipping`, `clientProfile`), so the compiler composes them via\n * `MultipleReactiveDataProvider`, which keys each entity's resolved slice by its own root field —\n * `$data` is `{ shipping: {...}, clientProfile: {...} }`, not a flat/unwrapped shape (that unwrapped\n * shape only applies to single-root-field fragments, e.g. CartTotalizerRoot's `$data.totalizers`).\n * Carries no `savedAddresses` — the fieldset has no saved-address UI of its own (Decision 1).\n */\nexport type ShippingAddressFieldsetData = {\n shipping?: {\n address?: {\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country?: string | null;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n } | null;\n } | null;\n clientProfile?: {\n firstName?: string | null;\n lastName?: string | null;\n } | null;\n} | null;\n\n/** The batched draft state, keyed by canonical field name (Decision 1). */\ntype AddressDraft = {\n recipientName: string;\n postalCode: string;\n country: string;\n street: string;\n number: string;\n complement: string;\n neighborhood: string;\n city: string;\n state: string;\n};\n\n// ---------------------------------------------------------------------------\n// Fieldset context\n// ---------------------------------------------------------------------------\n\n/** The react-hook-form namespace every field of this entity registers under. */\nconst SHIPPING_ADDRESS_NAMESPACE = 'shippingAddress';\n\n/** Canonical field keys, matching AddressDraft's keys and the descriptors' `name` values. */\nexport type ShippingAddressFieldKey = keyof AddressDraft;\n\n/** What a bound Control needs from its fieldset. Carries no live value. */\ntype ShippingAddressFieldsetContextValue = Readonly<{\n namespace: string;\n /** The active country's descriptor, or undefined when the country has none. */\n descriptor: CountryDescriptor | undefined;\n /** The descriptor entry for a key, or undefined when this country does not have the field. */\n fieldFor: (key: ShippingAddressFieldKey) => FieldDescriptor | undefined;\n /** The value this field registers with as react-hook-form's field-level defaultValue. */\n seedFor: (key: ShippingAddressFieldKey) => string;\n /**\n * The rule for a rendered field. `label` is the already-resolved label (authored, or the descriptor's\n * own when the authored one is blank): the same string the field shows on screen, so the generated\n * required-message copy renames the field exactly as the screen does. The caller resolves it once.\n * Never called for a field with no descriptor entry.\n */\n ruleFor: (key: ShippingAddressFieldKey, label: string) => FieldRule | undefined;\n /** Only for `country`: the platform's option list, contract-shaped. */\n countryOptions: readonly FieldOption[];\n}>;\n\nconst ShippingAddressFieldsetContext = createContext<ShippingAddressFieldsetContextValue | null>(null);\n\n/**\n * Read before any field hook (Decision 4): a control calls this before looking up its own\n * descriptor entry, so a field the active descriptor does not declare never calls\n * `useFieldsetField`/`useController` and so never registers with react-hook-form at all. Throws\n * when rendered with no `ShippingAddressFieldset` above it (Decision 2), naming the required\n * composition.\n */\nfunction useShippingAddressFieldsetContext(): ShippingAddressFieldsetContextValue {\n const ctx = useContext(ShippingAddressFieldsetContext);\n if (!ctx) {\n throw new Error('ShippingAddress*Control components must be used inside ShippingAddressFieldset.');\n }\n return ctx;\n}\n\n/**\n * Rows `ShippingAddressFieldsetSkeleton` draws when nobody says otherwise: one per Control in the\n * full anatomy, the nine of them. It is a default and not a derivation — the skeleton renders before\n * any address has resolved, so it cannot read the live descriptor, and the composed Controls are\n * opaque children. A page that composes fewer than nine sets `skeletonCount` to what it composed,\n * or the form jumps by the difference when the Controls take the skeleton's place.\n */\nconst SHIPPING_ADDRESS_SKELETON_ROWS = 9;\n\n/** `autoComplete` tokens per field (US-3, WCAG 2.1 SC 1.3.5). `number` has no standard token. */\nconst FIELD_AUTOCOMPLETE: Readonly<Record<ShippingAddressFieldKey, string | undefined>> = {\n recipientName: 'name',\n postalCode: 'postal-code',\n country: 'country',\n street: 'address-line1',\n number: undefined,\n complement: 'address-line2',\n neighborhood: 'address-level3',\n city: 'address-level2',\n state: 'address-level1',\n};\n\n/**\n * Merges the descriptor's own `rule` under a generated `required`, which is this fieldset's whole\n * declaration of the baseline. The blank check it used to hand-write alongside lives in\n * `resolveRequiredness` now, installed for every bound control rather than only for this one.\n */\nfunction buildRule(field: FieldDescriptor, label: string, requiredSuffix: string): FieldRule | undefined {\n if (!field.required) return field.rule;\n return { ...field.rule, required: `${label} ${requiredSuffix}` };\n}\n\n/** Keeps only the AddressDraft keys `values` actually defines — a field no control composed is absent, not `undefined`. */\nfunction pickDefinedAddressFields(values: Record<string, unknown>): Partial<AddressDraft> {\n const result: Partial<AddressDraft> = {};\n for (const key of Object.keys(values) as ShippingAddressFieldKey[]) {\n const value = values[key];\n if (value !== undefined) result[key] = value as string;\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Props Types\n// ---------------------------------------------------------------------------\n\nexport type ShippingAddressFieldsetProps = {\n /** Country used when the stored address has none. */\n defaultCountry?: string;\n /** Placeholder rows the loading skeleton draws. Set it to the number of Controls composed here. */\n skeletonCount?: number;\n /** Announced politely while the address resolves. 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 /** `ShippingAddressFieldsetData` forwarded by the reactive runtime. */\n $data?: ShippingAddressFieldsetData;\n /** Compiler-injected action surface; carries `shipping.setAddress`. */\n $actions?: ComponentActions;\n};\n\nexport type ShippingAddressStreetControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressNumberControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressCityControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressStateControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressPostalCodeControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressComplementControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressNeighborhoodControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressCountryControlProps = {\n className?: string;\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, FieldSelect.Root, Field.Error. */\n children?: ReactNode;\n};\n\nexport type ShippingAddressRecipientNameControlProps = {\n className?: string;\n /** Overrides the descriptor's label. Absence means the platform's value. */\n label?: string;\n placeholder?: string;\n /** Recomposes the anatomy. Absence renders Field.Label, Field.Control, Field.Error. */\n children?: ReactNode;\n};\n\n// ---------------------------------------------------------------------------\n// Root Definition\n// ---------------------------------------------------------------------------\n\nexport const ShippingAddressFieldsetDefinition = defineComponent<ShippingAddressFieldsetProps>({\n name: 'ShippingAddressFieldset',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressFieldset,\n fragment: fieldsetFragment,\n fetchStrategy: 'reactive',\n skeleton: ShippingAddressFieldsetSkeleton,\n actions: { shipping: ['setAddress'] },\n requiresContext: 'form',\n providesContext: 'shipping-address',\n editor: { label: 'Shipping Address Fieldset', category: 'commerce' },\n schema: {\n defaultCountry: { type: 'string', default: 'BRA', label: 'Default country (ISO-3)' },\n skeletonCount: { type: 'number', default: 9, label: 'Skeleton rows' },\n loadingLabel: { type: 'string', default: 'Loading your delivery address', label: 'Loading announcement' },\n loadedLabel: { type: 'string', default: 'Your delivery address is ready', label: 'Loaded announcement' },\n groupLabel: { type: 'string', default: 'Your delivery address', label: 'Accessible group name' },\n },\n guideline:\n 'Composable delivery-address entity: registers under \"shippingAddress\" with the enclosing FormRoot and dispatches shipping.setAddress only when the shopper changed something. Compose the nine ShippingAddress*Control parts inside it; place FormSubmit/FormEnterSubmit/FormError as siblings of the fieldset, not inside it — this fieldset renders no submit or error part of its own. The Controls mount only once the address has 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. groupLabel names the group as its accessible name; blank emits no aria-label, and a composed FieldsetLegend wins over it. See shipping-address.md.',\n});\n\n// Control Definitions\n// Shared by all eight text Controls below (RFC:503): states the requiresContext and the\n// recomposable anatomy every one of them shares.\nconst ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX =\n 'Must be a descendant of ShippingAddressFieldset, which provides the shipping-address context this control requires. Recomposable: compose Field.Label, Field.Control and Field.Error as children, in any order, to reorder or extend the anatomy; a childless composition keeps the default label-control-error order.';\n\nexport const ShippingAddressRecipientNameControlDefinition = defineComponent<ShippingAddressRecipientNameControlProps>({\n name: 'ShippingAddressRecipientNameControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressRecipientNameControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Recipient Name Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Recipient-name input field; required for submit. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressStreetControlDefinition = defineComponent<ShippingAddressStreetControlProps>({\n name: 'ShippingAddressStreetControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressStreetControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Street Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Street name input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressNumberControlDefinition = defineComponent<ShippingAddressNumberControlProps>({\n name: 'ShippingAddressNumberControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressNumberControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Number Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Street number input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressCityControlDefinition = defineComponent<ShippingAddressCityControlProps>({\n name: 'ShippingAddressCityControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressCityControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'City Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `City name input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressStateControlDefinition = defineComponent<ShippingAddressStateControlProps>({\n name: 'ShippingAddressStateControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressStateControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'State Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `State/province input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressPostalCodeControlDefinition = defineComponent<ShippingAddressPostalCodeControlProps>({\n name: 'ShippingAddressPostalCodeControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressPostalCodeControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Postal Code Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Postal code input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressComplementControlDefinition = defineComponent<ShippingAddressComplementControlProps>({\n name: 'ShippingAddressComplementControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressComplementControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Complement Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Complement (apartment, suite, etc.) input field. ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressNeighborhoodControlDefinition = defineComponent<ShippingAddressNeighborhoodControlProps>({\n name: 'ShippingAddressNeighborhoodControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressNeighborhoodControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Neighborhood Control', category: 'action' },\n schema: {\n // No default (Decision 11): 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: 'Field label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline: `Neighborhood (bairro) input field; shown only for countries that have this field (BR in v1). ${ADDRESS_TEXT_CONTROL_GUIDELINE_SUFFIX}`,\n});\n\nexport const ShippingAddressCountryControlDefinition = defineComponent<ShippingAddressCountryControlProps>({\n name: 'ShippingAddressCountryControl',\n importPath: '@vtex/faststore/components',\n component: ShippingAddressCountryControl,\n requiresContext: 'shipping-address',\n providesContext: 'field',\n editor: { label: 'Country Control', category: 'action' },\n schema: {\n // No default (Decision 11): absence means the platform's value (the active country descriptor's\n // `countryLabel`), applied at render time by the control itself, not baked into the schema.\n label: { type: 'string', label: 'Field label' },\n },\n guideline:\n 'Country selector; lists only countries with an implemented descriptor. Must be a descendant of ShippingAddressFieldset, which provides the shipping-address context this control requires. Recomposable: compose Field.Label, FieldSelect.Root and Field.Error as children, in any order; a childless composition keeps the default label-select-error order.',\n});\n\n// ---------------------------------------------------------------------------\n// Fieldset Component\n// ---------------------------------------------------------------------------\n\n/** The message a constrained rule member carries; a bare value (or a bare `RegExp`) carries none. */\nfunction messageOf(constraint: number | string | RegExp | FieldRuleConstraint<unknown> | undefined): string {\n return typeof constraint === 'object' && !(constraint instanceof RegExp) ? constraint.message : '';\n}\n\n/**\n * Every static message a rule carries, in a fixed order: the `required` copy in any of its three shapes,\n * then the message of each constrained member. A `validate` record has no static copy, so it adds none.\n */\nfunction messagesOf(rule: FieldRule | undefined): string[] {\n return [\n readBaseline(rule).message ?? '',\n messageOf(rule?.pattern),\n messageOf(rule?.min),\n messageOf(rule?.max),\n messageOf(rule?.minLength),\n messageOf(rule?.maxLength),\n ];\n}\n\n/**\n * An error already on screen keeps the message of the rule that raised it, so a country switch would\n * leave \"é obrigatório\" under a USA form until the shopper edits or submits again. A bound control\n * therefore revalidates itself when the copy of its own rule changes while it carries an error: that\n * re-words it from the new rule without newly flagging a field the shopper has not reached.\n *\n * It runs inside the control, as an effect of the component that renders the field's own subtree, so it\n * always fires after that field's registration — `useController` re-registers `rules` during render, and\n * descendants' effects precede their parent's — and never validates against the previous rule, whichever\n * of the two the registration becomes. The first run counts as a change too: a field that remounts after\n * a country without it keeps its error across the unmount (`shouldUnregister` being false) and comes\n * back carrying the old wording.\n */\nfunction useRewordErroredField(name: string, rule: FieldRule | undefined) {\n const { getFieldState, trigger } = useFormContext();\n const copy = messagesOf(rule).join('\\n');\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `copy` is the trigger, not an input — the effect revalidates when the rule's wording changes.\n useEffect(() => {\n if (getFieldState(name).error) void trigger(name);\n }, [copy, name, getFieldState, trigger]);\n}\n\n/**\n * ShippingAddressFieldset — this entity's root: same data, same action as a page-level submit\n * would use, dispatched at form-submit time instead of through a button of its own. Registers one\n * `FieldsetRegistration` with the enclosing `FormRoot` under the `shippingAddress` namespace,\n * derives the active country descriptor from react-hook-form (Decision 2), and publishes each\n * field's seed/rule/label through its own context so a bound Control never writes a validation\n * expression. Renders no button and holds no draft of its own.\n *\n * Its controls mount only once the entity has resolved; until then the `Fieldset.Root` carries\n * `-pending` and renders `ShippingAddressFieldsetSkeleton`. \"Resolved\" is two conditions, because\n * `$data` alone cannot answer it: under the reactive runtime the slice is defined from the first\n * render — `useReactiveEntity` hands down `fallbackData` while the cache read is incomplete — so an\n * empty server answer looks exactly like a resolved one, and every control would mount seeded `''`\n * before the shopper's stored address arrives. Each seed reaches react-hook-form as a field-level\n * `defaultValue`; `useSeedAdoption` re-seeds a clean field with it on every render, but once the\n * field turns dirty no later seed ever reaches it again (Decision 12). Mounting before the answer\n * arrives would seed `''`: a shopper who starts typing before the real value lands makes the field\n * dirty on that empty seed, permanently locking their saved address out of it, and even a shopper who\n * does not type sees the field flash from `''` to the real data. `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\n * trees with no reactive root above them, where 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\n * polite live region that announces `loadingLabel` and then `loadedLabel`. Style the region\n * `sr-only` — it is text meant for a screen reader, not for the page.\n */\nexport function ShippingAddressFieldset({\n defaultCountry = 'BRA',\n skeletonCount = SHIPPING_ADDRESS_SKELETON_ROWS,\n loadingLabel = 'Loading your delivery address',\n loadedLabel = 'Your delivery address is ready',\n groupLabel = 'Your delivery address',\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ShippingAddressFieldsetProps): ReactNode {\n // First hook called: throws the named registry error when no FormRoot is above (US-1, 5th\n // criterion), before any react-hook-form hook below has a chance to run against a missing context.\n const { registerFieldset } = useFormRegistry();\n\n // Guards runtime registry integrity the same way FormRoot's namespace-collision throw does:\n // useFieldsetField resolves the *nearest* FieldsetFieldContext, not the fieldset that owns a\n // given namespace, so a fieldset nested inside another one would register its controls' names\n // into the ancestor's name set instead of its own — FormClear, FormReset and post-dispatch\n // reconciliation would then act on the wrong fields. Nesting fieldsets has no legitimate use,\n // so this throws at mount rather than silently misrouting names.\n useNoAncestorFieldset('ShippingAddressFieldset');\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 const currentAddress = $data?.shipping?.address;\n const clientProfile = $data?.clientProfile;\n const joinedProfileName = [clientProfile?.firstName, clientProfile?.lastName].filter(Boolean).join(' ');\n\n // The one seed record every field registers with as react-hook-form's own defaultValue (Decision\n // 12) — resolved fresh from $data on every render and re-applied to every already-mounted field\n // that is still clean; a field the shopper has started editing turns dirty and locks this out.\n const seed = useMemo<AddressDraft>(\n () => ({\n recipientName: currentAddress?.recipientName ?? joinedProfileName,\n postalCode: currentAddress?.postalCode ?? '',\n country: currentAddress?.country ?? defaultCountry,\n street: currentAddress?.street ?? '',\n number: currentAddress?.number ?? '',\n complement: currentAddress?.complement ?? '',\n neighborhood: currentAddress?.neighborhood ?? '',\n city: currentAddress?.city ?? '',\n state: currentAddress?.state ?? '',\n }),\n [currentAddress, joinedProfileName, defaultCountry],\n );\n\n // Decision 2: the descriptor is derived from react-hook-form, not from a draft of our own, so a\n // country change reshapes the form with one subscription and no re-seeding effect. `FormClear`\n // can drive the live value to '' (the select itself never offers an empty option); falling back\n // to the seeded country there keeps every field — including the required recipient name — mounted\n // and focusable instead of vanishing the moment the form is cleared.\n const watchedCountry = useWatch({ name: `${SHIPPING_ADDRESS_NAMESPACE}.country`, defaultValue: seed.country });\n const activeCountry = (typeof watchedCountry === 'string' && watchedCountry) || seed.country;\n const descriptor = getCountryDescriptor(activeCountry);\n\n // The suffix of the descriptor every field below came from; unused when there is no descriptor, since\n // then no field is found and `ruleFor` is never called.\n const requiredSuffix = descriptor?.requiredSuffix ?? '';\n\n const fieldFor = useCallback(\n (key: ShippingAddressFieldKey) => descriptor?.fields.find((f) => f.name === key),\n [descriptor],\n );\n const seedFor = useCallback((key: ShippingAddressFieldKey) => seed[key], [seed]);\n const ruleFor = useCallback(\n (key: ShippingAddressFieldKey, label: string) => {\n const field = fieldFor(key);\n return field ? buildRule(field, label, requiredSuffix) : undefined;\n },\n [fieldFor, requiredSuffix],\n );\n const countryOptions = useMemo<readonly FieldOption[]>(\n () => getAvailableCountries().map((iso) => ({ value: iso, label: getCountryDescriptor(iso)?.label ?? iso })),\n [],\n );\n\n const fieldsetContextValue = useMemo<ShippingAddressFieldsetContextValue>(\n () => ({ namespace: SHIPPING_ADDRESS_NAMESPACE, descriptor, fieldFor, seedFor, ruleFor, countryOptions }),\n [descriptor, fieldFor, seedFor, ruleFor, countryOptions],\n );\n\n // Collects the field names this fieldset's own controls currently have mounted (FR 3), over the\n // seam `particles/field/field.tsx` exports for exactly this purpose.\n const { registry: fieldRegistryValue, getFieldNames } = useFieldsetFieldNames(SHIPPING_ADDRESS_NAMESPACE);\n\n // Deliberately NOT dirty-only (T21 Decision 4), unlike ClientProfileFieldset/ClientPreferencesFieldset:\n // `ShippingAddressUpdateInput` declares `postalCode` and `country` non-null (`recipientName` is optional;\n // core.graphql:2795-2807), so a payload carrying only the changed keys can omit the non-null fields.\n // Sending the whole active-country address, seed-merged with the live values, is the correct shape\n // for this mutation's contract — not an oversight to \"fix\" into dirty-only.\n const toPayload = useCallback(\n (values: Record<string, unknown>): Record<string, unknown> => {\n const merged = { ...seed, ...pickDefinedAddressFields(values) } as AddressDraft;\n const country = String(merged.country || seed.country);\n const active = getCountryDescriptor(country);\n const isActive = (key: ShippingAddressFieldKey) => active?.fields.some((f) => f.name === key) ?? false;\n\n return {\n country,\n ...(isActive('recipientName') ? { recipientName: String(merged.recipientName ?? '').trim() } : {}),\n ...(isActive('postalCode') ? { postalCode: merged.postalCode } : {}),\n ...(isActive('street') ? { street: merged.street } : {}),\n ...(isActive('number') ? { number: merged.number } : {}),\n ...(isActive('complement') ? { complement: merged.complement } : {}),\n ...(isActive('neighborhood') ? { neighborhood: merged.neighborhood } : {}),\n ...(isActive('city') ? { city: merged.city } : {}),\n ...(isActive('state') ? { state: merged.state } : {}),\n };\n },\n [seed],\n );\n\n const dispatch = useCallback(\n async (payload: Record<string, unknown>): Promise<readonly FormUserError[]> => {\n if (!$actions?.shipping?.setAddress) {\n // The form reports a failure rather than silently succeeding (FR 13).\n throw new Error('ShippingAddressFieldset requires $actions.shipping.setAddress.');\n }\n return $actions.shipping.setAddress(payload as ShippingAddressInput);\n },\n [$actions],\n );\n\n const registration = useMemo<FieldsetRegistration>(\n () => ({\n namespace: SHIPPING_ADDRESS_NAMESPACE,\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` (`shippingAddress` → `shipping-address`) — not authored per\n // page (Decision 2).\n label: 'shipping-address',\n }),\n [getFieldNames, dispatch, toPayload],\n );\n\n // Registered from the mount commit, like the other two fieldsets, because `FormRoot` takes a\n // fieldset's dispatch slot from its first registration: deferring it until the entity resolves\n // would put this fieldset after every sibling that registered at mount, whatever their order in\n // the document.\n //\n // Registering early cannot send an unresolved seed. `toPayload` is whole-entity here\n // (`ShippingAddressUpdateInput` declares three fields non-null, so the payload is\n // `{ ...seed, ...liveValues }`), which makes a placeholder seed sendable, but the Controls mount only\n // once the entity has resolved. Until then `getFieldNames()` is empty and `FormRoot` finds nothing of\n // this fieldset that could be dirty — including a field the shopper edited before the slice regressed.\n useEffect(() => registerFieldset(registration), [registerFieldset, registration]);\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 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-shipping-address-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-shipping-address-fieldset-pending': '' })}\n >\n <ShippingAddressFieldsetContext.Provider value={fieldsetContextValue}>\n <FieldsetFieldContext.Provider value={fieldRegistryValue}>\n {resolved ? children : <ShippingAddressFieldsetSkeleton count={skeletonCount} />}\n </FieldsetFieldContext.Provider>\n </ShippingAddressFieldsetContext.Provider>\n <output aria-live=\"polite\" data-fs-shipping-address-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\n * live region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ShippingAddressFieldsetSkeleton({\n count = SHIPPING_ADDRESS_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-shipping-address-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-shipping-address-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nShippingAddressFieldset.Skeleton = ShippingAddressFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Control Components (thin, context-bound, reuse particles)\n//\n// Each control reads the fieldset context and finds its descriptor entry *before* calling any\n// field hook, so a field the active descriptor does not declare never calls\n// `useFieldsetField`/`useController` and so never registers with react-hook-form at all\n// (Decision 4).\n// ---------------------------------------------------------------------------\n\n/** The eight text fields' shared anatomy (Decision 6): `FieldBinding > Field.Root > (Field.Label, Field.Control, Field.Error)`. */\ntype BoundAddressTextFieldProps = {\n fieldKey: Exclude<ShippingAddressFieldKey, 'country'>;\n slug: string;\n className?: string;\n label?: string;\n placeholder?: string;\n children?: ReactNode;\n fieldsetCtx: ShippingAddressFieldsetContextValue;\n fieldDescriptor: FieldDescriptor;\n};\n\nfunction BoundAddressTextField({\n fieldKey,\n slug,\n className,\n label,\n placeholder,\n children,\n fieldsetCtx,\n fieldDescriptor,\n}: BoundAddressTextFieldProps) {\n const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, fieldKey);\n // The rule gets the same resolved label the field shows, so it renames the field in its own\n // required-message copy too (spec 806-809), not just on screen.\n const resolvedLabel = resolveAuthoredCopy(label, fieldDescriptor.label);\n const rule = fieldsetCtx.ruleFor(fieldKey, resolvedLabel);\n useRewordErroredField(name, rule);\n\n return (\n <FieldBinding\n name={name}\n label={resolvedLabel}\n placeholder={placeholder}\n defaultValue={fieldsetCtx.seedFor(fieldKey)}\n rule={rule}\n autoComplete={FIELD_AUTOCOMPLETE[fieldKey]}\n >\n <Field.Root className={className} data-fs-shipping-address-field={slug}>\n {children ?? (\n <>\n <Field.Label />\n <Field.Control />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\n/**\n * RecipientNameControl — the only required field (US-4, US-6); the postal code is client-validated\n * too, against the active country's format.\n * Pre-filled from clientProfile, editable, required.\n */\nexport function ShippingAddressRecipientNameControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressRecipientNameControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('recipientName');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"recipientName\"\n slug=\"recipient-name\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** StreetControl */\nexport function ShippingAddressStreetControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressStreetControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('street');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"street\"\n slug=\"street\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** NumberControl */\nexport function ShippingAddressNumberControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressNumberControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('number');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"number\"\n slug=\"number\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** CityControl */\nexport function ShippingAddressCityControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressCityControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('city');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"city\"\n slug=\"city\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** StateControl */\nexport function ShippingAddressStateControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressStateControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('state');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"state\"\n slug=\"state\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** PostalCodeControl */\nexport function ShippingAddressPostalCodeControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressPostalCodeControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('postalCode');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"postalCode\"\n slug=\"postal-code\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** ComplementControl */\nexport function ShippingAddressComplementControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressComplementControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('complement');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"complement\"\n slug=\"complement\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/** NeighborhoodControl (BR-specific in v1) */\nexport function ShippingAddressNeighborhoodControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressNeighborhoodControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n const fieldDescriptor = fieldsetCtx.fieldFor('neighborhood');\n if (!fieldDescriptor) return null;\n return (\n <BoundAddressTextField\n fieldKey=\"neighborhood\"\n slug=\"neighborhood\"\n className={className}\n label={label}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n fieldDescriptor={fieldDescriptor}\n >\n {children}\n </BoundAddressTextField>\n );\n}\n\n/**\n * CountryControl — moves onto `FieldSelect` (Decision 8): the trigger resolves a country name from\n * the field contract's `options`. Gated on `descriptor`, not on a per-field entry (country has\n * none): a country with no descriptor renders no controls at all (Decision 3/4's \"no entry, no\n * control\" applied to the field that selects the entry itself).\n */\nexport function ShippingAddressCountryControl({\n className,\n label,\n placeholder,\n children,\n}: ShippingAddressCountryControlProps): ReactNode {\n const fieldsetCtx = useShippingAddressFieldsetContext();\n if (!fieldsetCtx.descriptor) return null;\n return (\n <BoundShippingAddressCountryControl\n className={className}\n label={label}\n defaultLabel={fieldsetCtx.descriptor.countryLabel}\n placeholder={placeholder}\n fieldsetCtx={fieldsetCtx}\n >\n {children}\n </BoundShippingAddressCountryControl>\n );\n}\n\ntype BoundShippingAddressCountryControlProps = {\n className?: string;\n label?: string;\n /** The active descriptor's `countryLabel`, used when no `label` is authored. */\n defaultLabel: string;\n placeholder?: string;\n children?: ReactNode;\n fieldsetCtx: ShippingAddressFieldsetContextValue;\n};\n\nfunction BoundShippingAddressCountryControl({\n className,\n label,\n defaultLabel,\n placeholder,\n children,\n fieldsetCtx,\n}: Readonly<BoundShippingAddressCountryControlProps>) {\n const name = useFieldsetField(SHIPPING_ADDRESS_NAMESPACE, 'country');\n\n return (\n <FieldBinding\n name={name}\n label={resolveAuthoredCopy(label, defaultLabel)}\n // Falls back to the active descriptor's label (already the FormClear-safe activeCountry,\n // not the raw watched value — Decision 2) so the trigger shows the country that will\n // actually be sent even when react-hook-form's own value is '' (e.g. right after\n // FormClear), instead of resolveOptionLabel('') rendering nothing at all.\n placeholder={placeholder ?? fieldsetCtx.descriptor?.label}\n defaultValue={fieldsetCtx.seedFor('country')}\n options={fieldsetCtx.countryOptions}\n autoComplete={FIELD_AUTOCOMPLETE.country}\n >\n <Field.Root className={className} data-fs-shipping-address-field=\"country\">\n {children ?? (\n <>\n <Field.Label />\n <FieldSelect.Root />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Namespace Export\n// ---------------------------------------------------------------------------\n\nexport const ShippingAddress = {\n Fieldset: ShippingAddressFieldset,\n FieldsetDefinition: ShippingAddressFieldsetDefinition,\n FieldsetSkeleton: ShippingAddressFieldsetSkeleton,\n RecipientNameControl: ShippingAddressRecipientNameControl,\n RecipientNameControlDefinition: ShippingAddressRecipientNameControlDefinition,\n StreetControl: ShippingAddressStreetControl,\n StreetControlDefinition: ShippingAddressStreetControlDefinition,\n NumberControl: ShippingAddressNumberControl,\n NumberControlDefinition: ShippingAddressNumberControlDefinition,\n CityControl: ShippingAddressCityControl,\n CityControlDefinition: ShippingAddressCityControlDefinition,\n StateControl: ShippingAddressStateControl,\n StateControlDefinition: ShippingAddressStateControlDefinition,\n PostalCodeControl: ShippingAddressPostalCodeControl,\n PostalCodeControlDefinition: ShippingAddressPostalCodeControlDefinition,\n ComplementControl: ShippingAddressComplementControl,\n ComplementControlDefinition: ShippingAddressComplementControlDefinition,\n NeighborhoodControl: ShippingAddressNeighborhoodControl,\n NeighborhoodControlDefinition: ShippingAddressNeighborhoodControlDefinition,\n CountryControl: ShippingAddressCountryControl,\n CountryControlDefinition: ShippingAddressCountryControlDefinition,\n};\n"],"mappings":"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"}
|
|
@@ -20,11 +20,11 @@ type RawShippingSimulatorData = {
|
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
type MoneyValue = {
|
|
23
|
-
amount:
|
|
23
|
+
amount: string;
|
|
24
24
|
currencyCode: string;
|
|
25
25
|
};
|
|
26
26
|
type DeliveryChannel = 'DELIVERY' | 'PICKUP' | 'UNKNOWN';
|
|
27
|
-
type ShippingEstimateUnit = 'BUSINESS_DAYS' | 'DAYS' | 'HOURS' | 'MINUTES';
|
|
27
|
+
export type ShippingEstimateUnit = 'BUSINESS_DAYS' | 'DAYS' | 'HOURS' | 'MINUTES';
|
|
28
28
|
type ShippingEstimate = {
|
|
29
29
|
value: number;
|
|
30
30
|
unit: ShippingEstimateUnit;
|
|
@@ -6,6 +6,7 @@ import { FormattedMessage, useIntl } from "../../sdk/i18n/client.js";
|
|
|
6
6
|
import { useCartShippingSimulation } from "../../sdk/shipping/use-cart-shipping-simulation.js";
|
|
7
7
|
import { useShippingSimulation } from "../../sdk/shipping/use-shipping-simulation.js";
|
|
8
8
|
import { useDataOverride } from "../../sdk/data/data-override-context.js";
|
|
9
|
+
import { isFiniteAmount } from "../cart/cart.js";
|
|
9
10
|
import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react";
|
|
10
11
|
import { jsx } from "react/jsx-runtime";
|
|
11
12
|
//#region src/matter/shipping-simulator/shipping-simulator.tsx
|
|
@@ -576,11 +577,14 @@ function ShippingSimulatorOptionEstimate({ className, children, ...props }) {
|
|
|
576
577
|
children: children ?? text
|
|
577
578
|
});
|
|
578
579
|
}
|
|
580
|
+
function isFreeAmount(amount) {
|
|
581
|
+
return isFiniteAmount(amount) && Number(amount) === 0;
|
|
582
|
+
}
|
|
579
583
|
function ShippingSimulatorOptionPrice({ className, children, ...props }) {
|
|
580
584
|
const option = useOptionItem();
|
|
581
585
|
const intl = useIntl();
|
|
582
586
|
const { locale, currency } = useStorefrontContext();
|
|
583
|
-
const text = option.price.amount
|
|
587
|
+
const text = isFreeAmount(option.price.amount) ? intl.formatMessage({ id: "fs/shipping.free-price" }) : formatPrice(Number(option.price.amount), locale, currency);
|
|
584
588
|
return /* @__PURE__ */ jsx("span", {
|
|
585
589
|
...props,
|
|
586
590
|
className,
|
|
@@ -589,7 +593,7 @@ function ShippingSimulatorOptionPrice({ className, children, ...props }) {
|
|
|
589
593
|
});
|
|
590
594
|
}
|
|
591
595
|
function ShippingSimulatorOptionFreeBadge({ className, children, ...props }) {
|
|
592
|
-
if (useOptionItem().price.amount
|
|
596
|
+
if (!isFreeAmount(useOptionItem().price.amount)) return null;
|
|
593
597
|
return /* @__PURE__ */ jsx("span", {
|
|
594
598
|
...props,
|
|
595
599
|
className,
|