@vtex/faststore 0.0.10 → 0.0.12
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 +55 -0
- package/README.md +0 -1
- package/dist/_virtual/_rolldown/runtime.js +4 -0
- package/dist/actions.json +6 -1
- package/dist/catalog.json +789 -1701
- package/dist/cli/index.d.ts +66 -28
- package/dist/cli/index.js +7371 -512
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/server-runtime.js +41 -60
- package/dist/cli/server-runtime.js.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +2 -2
- package/dist/components.d.ts +63 -57
- package/dist/components.js +60 -54
- package/dist/content-types.json +5785 -754
- package/dist/core/dist/define-component.d.ts +1 -1
- package/dist/core/dist/define-content-type.d.ts +50 -2
- package/dist/core/dist/define-content-type.js +107 -3
- package/dist/core/dist/define-content-type.js.map +1 -1
- package/dist/core/dist/index.d.ts +2 -2
- package/dist/docs/access-code-field.md +1 -1
- package/dist/docs/access-code-sign-in.md +126 -77
- package/dist/docs/account-address-book.md +210 -95
- package/dist/docs/account-menu.md +14 -15
- package/dist/docs/account-saved-cards.md +44 -39
- package/dist/docs/alert-dialog.md +3 -1
- package/dist/docs/avatar.md +4 -2
- package/dist/docs/billing-address.md +99 -30
- package/dist/docs/binding-switcher.md +5 -2
- package/dist/docs/buy-button.md +7 -8
- package/dist/docs/card-entry.md +39 -26
- package/dist/docs/card-summary.md +18 -8
- package/dist/docs/cardholder-document.md +5 -3
- package/dist/docs/carousel.md +5 -4
- package/dist/docs/cart-destination.md +39 -26
- package/dist/docs/cart-item.md +29 -14
- package/dist/docs/cart-totalizer.md +7 -5
- package/dist/docs/cart.md +135 -41
- package/dist/docs/challenge-return.md +135 -0
- package/dist/docs/client-preferences-fieldset.md +10 -5
- package/dist/docs/client-preferences.md +31 -8
- package/dist/docs/client-profile-fieldset.md +20 -6
- package/dist/docs/client-profile.md +12 -3
- package/dist/docs/copy-text.md +9 -7
- package/dist/docs/document-field.md +1 -1
- package/dist/docs/email-field.md +2 -1
- package/dist/docs/email-identification.md +12 -2
- package/dist/docs/footer-copyright.md +4 -2
- package/dist/docs/form.md +54 -18
- package/dist/docs/free-shipping-progress.md +6 -5
- package/dist/docs/identity-edit.md +8 -2
- package/dist/docs/identity-summary.md +18 -5
- package/dist/docs/installments.md +46 -32
- package/dist/docs/my-account-profile.md +16 -11
- package/dist/docs/navigation-link.md +5 -3
- package/dist/docs/order-cancel.md +3 -1
- package/dist/docs/order-delivery-address.md +7 -5
- package/dist/docs/order-delivery-group.md +1 -3
- package/dist/docs/order-details-back.md +1 -1
- package/dist/docs/order-details-header.md +1 -4
- package/dist/docs/order-invoice-download.md +60 -0
- package/dist/docs/order-list-row.md +1 -1
- package/dist/docs/order-list-search.md +13 -20
- package/dist/docs/order-list-views.md +11 -17
- package/dist/docs/order-list.md +12 -5
- package/dist/docs/order-payment.md +9 -7
- package/dist/docs/order-placed-date.md +1 -1
- package/dist/docs/order-placed-payment-summary.md +28 -15
- package/dist/docs/order-placed.md +49 -14
- package/dist/docs/order-progress.md +1 -1
- package/dist/docs/order-status-badge.md +20 -9
- package/dist/docs/order-summary.md +2 -2
- package/dist/docs/order-tracking-link.md +58 -0
- package/dist/docs/payment-method-badges.md +30 -4
- package/dist/docs/payment-methods.md +1 -1
- package/dist/docs/payment.md +36 -17
- package/dist/docs/phone-field.md +4 -4
- package/dist/docs/place-order.md +84 -36
- package/dist/docs/postal-code-field.md +3 -1
- package/dist/docs/pricing.md +21 -23
- package/dist/docs/product-gallery.md +19 -20
- package/dist/docs/product-information.md +13 -9
- package/dist/docs/product-list.md +7 -6
- package/dist/docs/product-shelf.md +0 -1
- package/dist/docs/promotion.md +4 -2
- package/dist/docs/region.md +23 -15
- package/dist/docs/save-card.md +7 -6
- package/dist/docs/saved-cards.md +65 -36
- package/dist/docs/shipping-address.md +57 -21
- package/dist/docs/shipping-simulator.md +53 -15
- package/dist/docs/sign-in-disclosure.md +176 -0
- package/dist/docs/sign-in-form.md +78 -47
- package/dist/docs/sign-in-redirect.md +4 -2
- package/dist/docs/sign-in.md +173 -0
- package/dist/docs/toast.md +15 -4
- package/dist/docs/variant-selector.md +15 -11
- package/dist/domain-logic/dist/checkout/rules.js +33 -0
- package/dist/domain-logic/dist/checkout/rules.js.map +1 -0
- package/dist/graphql/types.d.ts +4 -14
- package/dist/index.d.ts +2 -2
- package/dist/internal/client.d.ts +1 -3
- package/dist/internal/client.js +1 -1
- package/dist/internal/server.d.ts +7 -4
- package/dist/internal/server.js +7 -4
- package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +250 -66
- package/dist/matter/access-code-sign-in/access-code-sign-in.js +459 -188
- package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-delete.d.ts +78 -40
- package/dist/matter/account-address-book/account-address-book-delete.js +86 -50
- package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +21 -4
- package/dist/matter/account-address-book/account-address-book-deliverability.js +45 -17
- package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +74 -19
- package/dist/matter/account-address-book/account-address-book-form-parts.js +77 -26
- package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +27 -6
- package/dist/matter/account-address-book/account-address-book-profile-notice.js +55 -28
- package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book.d.ts +67 -14
- package/dist/matter/account-address-book/account-address-book.js +74 -33
- package/dist/matter/account-address-book/account-address-book.js.map +1 -1
- package/dist/matter/account-address-book/account-address-country-switch.js +3 -3
- package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -1
- package/dist/matter/account-address-book/account-address-country.d.ts +66 -20
- package/dist/matter/account-address-book/account-address-country.js +83 -49
- package/dist/matter/account-address-book/account-address-country.js.map +1 -1
- package/dist/matter/account-address-book/account-address-form-context.d.ts +8 -4
- package/dist/matter/account-address-book/account-address-form-context.js.map +1 -1
- package/dist/matter/account-address-book/account-address-form.d.ts +468 -45
- package/dist/matter/account-address-book/account-address-form.js +518 -155
- package/dist/matter/account-address-book/account-address-form.js.map +1 -1
- package/dist/matter/account-address-book/account-address-record.d.ts +27 -6
- package/dist/matter/account-address-book/account-address-record.js +32 -17
- package/dist/matter/account-address-book/account-address-record.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +34 -17
- package/dist/matter/account-menu/account-menu.js +46 -54
- package/dist/matter/account-menu/account-menu.js.map +1 -1
- package/dist/matter/account-menu-identity/account-menu-identity.js +1 -1
- package/dist/matter/account-saved-cards/account-saved-cards.d.ts +108 -28
- package/dist/matter/account-saved-cards/account-saved-cards.js +177 -122
- package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -1
- package/dist/matter/billing-address/billing-address.d.ts +156 -74
- package/dist/matter/billing-address/billing-address.js +227 -156
- package/dist/matter/billing-address/billing-address.js.map +1 -1
- package/dist/matter/breadcrumb/breadcrumb.d.ts +21 -3
- package/dist/matter/breadcrumb/breadcrumb.js +24 -9
- package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/matter/buy-button/buy-button.d.ts +8 -11
- package/dist/matter/buy-button/buy-button.js +10 -19
- package/dist/matter/buy-button/buy-button.js.map +1 -1
- package/dist/matter/card-entry/card-capture.js +12 -4
- package/dist/matter/card-entry/card-capture.js.map +1 -1
- package/dist/matter/card-entry/card-entry.d.ts +123 -32
- package/dist/matter/card-entry/card-entry.js +348 -221
- package/dist/matter/card-entry/card-entry.js.map +1 -1
- package/dist/matter/cart/cart-namespace.d.ts +7 -1
- package/dist/matter/cart/cart-namespace.js +7 -1
- package/dist/matter/cart/cart-namespace.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +402 -61
- package/dist/matter/cart/cart.js +624 -153
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-destination/cart-destination.d.ts +30 -19
- package/dist/matter/cart-destination/cart-destination.js +160 -70
- package/dist/matter/cart-destination/cart-destination.js.map +1 -1
- package/dist/matter/cart-item/cart-item.d.ts +144 -17
- package/dist/matter/cart-item/cart-item.js +166 -49
- package/dist/matter/cart-item/cart-item.js.map +1 -1
- package/dist/matter/cart-item-compositions/cart-item-compositions.js +1 -1
- package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -1
- package/dist/matter/cart-item-customizations/cart-item-customizations.js +1 -1
- package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -1
- package/dist/matter/cart-item-discounts/cart-item-discounts.js +1 -1
- package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -1
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +1 -1
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -1
- package/dist/matter/cart-item-variations/cart-item-variations.js +1 -1
- package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -1
- package/dist/matter/cart-totalizer/cart-totalizer.d.ts +43 -9
- package/dist/matter/cart-totalizer/cart-totalizer.js +46 -17
- package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
- package/dist/matter/challenge-return/challenge-return.d.ts +62 -0
- package/dist/matter/challenge-return/challenge-return.js +241 -0
- package/dist/matter/challenge-return/challenge-return.js.map +1 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +86 -17
- package/dist/matter/client-preferences/client-preferences-fieldset.js +126 -54
- package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences.d.ts +50 -7
- package/dist/matter/client-preferences/client-preferences.js +84 -15
- package/dist/matter/client-preferences/client-preferences.js.map +1 -1
- package/dist/matter/client-profile/client-profile.d.ts +44 -9
- package/dist/matter/client-profile/client-profile.js +64 -24
- package/dist/matter/client-profile/client-profile.js.map +1 -1
- package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -22
- package/dist/matter/client-profile-form/client-profile-fieldset.js +161 -73
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options-accordion.d.ts +49 -4
- package/dist/matter/delivery-options/delivery-options-accordion.js +67 -14
- package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options-controller.d.ts +69 -9
- package/dist/matter/delivery-options/delivery-options-controller.js +80 -14
- package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options.d.ts +37 -2
- package/dist/matter/delivery-options/delivery-options.js +75 -12
- package/dist/matter/delivery-options/delivery-options.js.map +1 -1
- package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +1 -0
- package/dist/matter/delivery-options/use-delivery-option-selection.js +1 -1
- package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -1
- package/dist/matter/email-identification/email-identification.d.ts +25 -3
- package/dist/matter/email-identification/email-identification.js +49 -12
- package/dist/matter/email-identification/email-identification.js.map +1 -1
- package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +79 -7
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +77 -20
- package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.d.ts +52 -10
- package/dist/matter/identity-edit/identity-edit.js +47 -19
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.d.ts +76 -22
- package/dist/matter/identity-summary/identity-summary.js +95 -45
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/installments/installments-select.d.ts +98 -16
- package/dist/matter/installments/installments-select.js +156 -48
- package/dist/matter/installments/installments-select.js.map +1 -1
- package/dist/matter/installments/installments.d.ts +96 -16
- package/dist/matter/installments/installments.js +115 -40
- package/dist/matter/installments/installments.js.map +1 -1
- package/dist/matter/installments/use-installments-selection.d.ts +1 -0
- package/dist/matter/installments/use-installments-selection.js +8 -3
- package/dist/matter/installments/use-installments-selection.js.map +1 -1
- package/dist/matter/my-account-profile/my-account-profile.d.ts +358 -103
- package/dist/matter/my-account-profile/my-account-profile.js +370 -174
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-cancel/order-cancel.d.ts +65 -19
- package/dist/matter/order-cancel/order-cancel.js +118 -51
- package/dist/matter/order-cancel/order-cancel.js.map +1 -1
- package/dist/matter/order-delivery-address/order-delivery-address.d.ts +8 -18
- package/dist/matter/order-delivery-address/order-delivery-address.js +14 -23
- package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -1
- package/dist/matter/order-delivery-group/order-delivery-group.d.ts +40 -24
- package/dist/matter/order-delivery-group/order-delivery-group.js +64 -74
- package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -1
- package/dist/matter/order-details-header/order-details-header.d.ts +32 -15
- package/dist/matter/order-details-header/order-details-header.js +66 -58
- package/dist/matter/order-details-header/order-details-header.js.map +1 -1
- package/dist/matter/order-invoice-download/order-invoice-download.d.ts +78 -0
- package/dist/matter/order-invoice-download/order-invoice-download.js +173 -0
- package/dist/matter/order-invoice-download/order-invoice-download.js.map +1 -0
- package/dist/matter/order-list/order-list.d.ts +164 -19
- package/dist/matter/order-list/order-list.js +229 -87
- package/dist/matter/order-list/order-list.js.map +1 -1
- package/dist/matter/order-list-row/order-list-row.d.ts +6 -1
- package/dist/matter/order-list-row/order-list-row.js +3 -2
- package/dist/matter/order-list-row/order-list-row.js.map +1 -1
- package/dist/matter/order-list-search/order-list-search.d.ts +18 -26
- package/dist/matter/order-list-search/order-list-search.js +30 -69
- package/dist/matter/order-list-search/order-list-search.js.map +1 -1
- package/dist/matter/order-list-views/order-list-views.d.ts +15 -22
- package/dist/matter/order-list-views/order-list-views.js +22 -68
- package/dist/matter/order-list-views/order-list-views.js.map +1 -1
- package/dist/matter/order-payment/order-payment.d.ts +33 -10
- package/dist/matter/order-payment/order-payment.js +44 -39
- package/dist/matter/order-payment/order-payment.js.map +1 -1
- package/dist/matter/order-placed/order-placed-deliveries.d.ts +144 -12
- package/dist/matter/order-placed/order-placed-deliveries.js +115 -40
- package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -1
- package/dist/matter/order-placed/order-placed.d.ts +198 -31
- package/dist/matter/order-placed/order-placed.js +230 -139
- package/dist/matter/order-placed/order-placed.js.map +1 -1
- package/dist/matter/order-placed-date/order-placed-date.d.ts +5 -8
- package/dist/matter/order-placed-date/order-placed-date.js +7 -8
- package/dist/matter/order-placed-date/order-placed-date.js.map +1 -1
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +90 -17
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +93 -117
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
- package/dist/matter/order-progress/order-progress.d.ts +19 -8
- package/dist/matter/order-progress/order-progress.js +37 -45
- package/dist/matter/order-progress/order-progress.js.map +1 -1
- package/dist/matter/order-summary/order-summary.d.ts +19 -9
- package/dist/matter/order-summary/order-summary.js +38 -44
- package/dist/matter/order-summary/order-summary.js.map +1 -1
- package/dist/matter/order-tracking-link/order-tracking-link.d.ts +43 -0
- package/dist/matter/order-tracking-link/order-tracking-link.js +107 -0
- package/dist/matter/order-tracking-link/order-tracking-link.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.js +17 -10
- package/dist/matter/payment/payment-card-capture.js.map +1 -1
- package/dist/matter/payment/payment-controller.d.ts +4 -2
- package/dist/matter/payment/payment-controller.js +30 -9
- package/dist/matter/payment/payment-controller.js.map +1 -1
- package/dist/matter/payment/payment-method-badges.js +1 -1
- package/dist/matter/payment/payment.d.ts +69 -19
- package/dist/matter/payment/payment.js +101 -35
- package/dist/matter/payment/payment.js.map +1 -1
- package/dist/matter/payment/use-payment-method-selection.d.ts +25 -4
- package/dist/matter/payment/use-payment-method-selection.js +94 -32
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
- package/dist/matter/payment/use-payment-submit-gate.d.ts +14 -3
- package/dist/matter/payment/use-payment-submit-gate.js +47 -8
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
- package/dist/matter/place-order/place-order.d.ts +171 -57
- package/dist/matter/place-order/place-order.js +376 -185
- package/dist/matter/place-order/place-order.js.map +1 -1
- package/dist/matter/pricing/pricing.d.ts +152 -13
- package/dist/matter/pricing/pricing.js +153 -52
- package/dist/matter/pricing/pricing.js.map +1 -1
- package/dist/matter/product-information/product-information.d.ts +27 -4
- package/dist/matter/product-information/product-information.js +32 -15
- package/dist/matter/product-information/product-information.js.map +1 -1
- package/dist/matter/product-list/product-list.d.ts +24 -6
- package/dist/matter/product-list/product-list.js +32 -26
- package/dist/matter/product-list/product-list.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +1 -3
- package/dist/matter/product-shelf/product-shelf.js +2 -15
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.d.ts +33 -16
- package/dist/matter/region/region.js +59 -52
- package/dist/matter/region/region.js.map +1 -1
- package/dist/matter/save-card/save-card.d.ts +43 -8
- package/dist/matter/save-card/save-card.js +61 -23
- package/dist/matter/save-card/save-card.js.map +1 -1
- package/dist/matter/saved-cards/saved-cards.d.ts +113 -21
- package/dist/matter/saved-cards/saved-cards.js +349 -77
- package/dist/matter/saved-cards/saved-cards.js.map +1 -1
- package/dist/matter/shipping-address/address-payload.js +25 -0
- package/dist/matter/shipping-address/address-payload.js.map +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +71 -71
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/library-country-descriptors.js +136 -0
- package/dist/matter/shipping-address/library-country-descriptors.js.map +1 -0
- package/dist/matter/shipping-address/shipping-address.d.ts +312 -45
- package/dist/matter/shipping-address/shipping-address.js +443 -188
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +250 -24
- package/dist/matter/shipping-simulator/shipping-simulator.js +257 -51
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/sign-in/sign-in.d.ts +108 -0
- package/dist/matter/sign-in/sign-in.js +285 -0
- package/dist/matter/sign-in/sign-in.js.map +1 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.d.ts +81 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.js +232 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.js.map +1 -0
- package/dist/matter/sign-in-form/sign-in-form.d.ts +93 -62
- package/dist/matter/sign-in-form/sign-in-form.js +134 -144
- package/dist/matter/sign-in-form/sign-in-form.js.map +1 -1
- package/dist/particles/binding-switcher/binding-switcher.d.ts +29 -8
- package/dist/particles/binding-switcher/binding-switcher.js +37 -26
- package/dist/particles/binding-switcher/binding-switcher.js.map +1 -1
- package/dist/particles/card-summary/card-summary.d.ts +38 -8
- package/dist/particles/card-summary/card-summary.js +55 -22
- package/dist/particles/card-summary/card-summary.js.map +1 -1
- package/dist/particles/carousel/carousel.d.ts +99 -11
- package/dist/particles/carousel/carousel.js +103 -35
- package/dist/particles/carousel/carousel.js.map +1 -1
- package/dist/particles/copy-text/copy-text.js +5 -15
- package/dist/particles/copy-text/copy-text.js.map +1 -1
- package/dist/particles/dialog/dialog.d.ts +14 -6
- package/dist/particles/dialog/dialog.js +6 -3
- package/dist/particles/dialog/dialog.js.map +1 -1
- package/dist/particles/drawer/drawer.js +1 -1
- package/dist/particles/drawer/drawer.js.map +1 -1
- package/dist/particles/email-field/email-field.d.ts +2 -1
- package/dist/particles/email-field/email-field.js +2 -1
- package/dist/particles/email-field/email-field.js.map +1 -1
- package/dist/particles/footer-link-group/footer-link-group.js +1 -0
- package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
- package/dist/particles/form/form.d.ts +85 -13
- package/dist/particles/form/form.js +91 -42
- package/dist/particles/form/form.js.map +1 -1
- package/dist/particles/gallery/gallery.d.ts +129 -12
- package/dist/particles/gallery/gallery.js +121 -34
- package/dist/particles/gallery/gallery.js.map +1 -1
- package/dist/particles/order-details-back/order-details-back.d.ts +5 -3
- package/dist/particles/order-details-back/order-details-back.js +8 -10
- package/dist/particles/order-details-back/order-details-back.js.map +1 -1
- package/dist/particles/order-status-badge/order-status-badge.d.ts +3 -3
- package/dist/particles/order-status-badge/order-status-badge.js +4 -20
- package/dist/particles/order-status-badge/order-status-badge.js.map +1 -1
- package/dist/particles/password-field/password-field.d.ts +1 -1
- package/dist/particles/password-field/password-field.js +2 -4
- package/dist/particles/password-field/password-field.js.map +1 -1
- package/dist/particles/phone-field/phone-field.d.ts +4 -4
- package/dist/particles/phone-field/phone-field.js +8 -11
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/spinner/spinner.d.ts +24 -4
- package/dist/particles/spinner/spinner.js +25 -9
- package/dist/particles/spinner/spinner.js.map +1 -1
- package/dist/particles/switch/switch.d.ts +4 -1
- package/dist/particles/switch/switch.js +3 -1
- package/dist/particles/switch/switch.js.map +1 -1
- package/dist/particles/toast/toast.d.ts +29 -3
- package/dist/particles/toast/toast.js +34 -10
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +164 -56
- package/dist/sdk/address/address-fields.js +4 -4
- package/dist/sdk/address/address-fields.js.map +1 -1
- package/dist/sdk/address/constants.js +1 -6
- package/dist/sdk/address/constants.js.map +1 -1
- package/dist/sdk/address/messages.js +44 -44
- package/dist/sdk/address/messages.js.map +1 -1
- package/dist/sdk/address/postal-code.js +15 -2
- package/dist/sdk/address/postal-code.js.map +1 -1
- package/dist/sdk/address/types.d.ts +5 -3
- package/dist/sdk/address/validate-address.js +3 -3
- package/dist/sdk/address/validate-address.js.map +1 -1
- package/dist/sdk/analytics/use-analytics-actions.d.ts +1 -1
- package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/data/index.js +2 -2
- package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
- package/dist/sdk/generated/gql.js +1 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +20 -5
- package/dist/sdk/generated/graphql.js +6 -0
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/format-error-code.js +23 -0
- package/dist/sdk/i18n/format-error-code.js.map +1 -0
- package/dist/sdk/i18n/message-formatter.d.ts +22 -0
- package/dist/sdk/i18n/message-formatter.js +140 -0
- package/dist/sdk/i18n/message-formatter.js.map +1 -0
- package/dist/sdk/i18n/use-message-formatter.d.ts +8 -0
- package/dist/sdk/i18n/use-message-formatter.js +18 -0
- package/dist/sdk/i18n/use-message-formatter.js.map +1 -0
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/navigation/redirect.d.ts +2 -0
- package/dist/sdk/navigation/redirect.js +19 -1
- package/dist/sdk/navigation/redirect.js.map +1 -1
- package/dist/sdk/navigation/types.d.ts +13 -0
- package/dist/sdk/payment/bin-format.js +21 -0
- package/dist/sdk/payment/bin-format.js.map +1 -0
- package/dist/sdk/payment/challenge-return.js +37 -0
- package/dist/sdk/payment/challenge-return.js.map +1 -0
- package/dist/sdk/payment/confirmation-last-four.js +39 -0
- package/dist/sdk/payment/confirmation-last-four.js.map +1 -0
- package/dist/sdk/payment/gateway.d.ts +1 -1
- package/dist/sdk/payment/gateway.js +8 -2
- package/dist/sdk/payment/gateway.js.map +1 -1
- package/dist/sdk/payment/operations.d.ts +1 -0
- package/dist/sdk/payment/operations.js +28 -6
- package/dist/sdk/payment/operations.js.map +1 -1
- package/dist/sdk/payment/resumed-purchase.d.ts +1 -0
- package/dist/sdk/payment/resumed-purchase.js +119 -0
- package/dist/sdk/payment/resumed-purchase.js.map +1 -0
- package/dist/sdk/payment/security-code-mask.js +16 -23
- package/dist/sdk/payment/security-code-mask.js.map +1 -1
- package/dist/sdk/payment/submission-registry.js +6 -2
- package/dist/sdk/payment/submission-registry.js.map +1 -1
- package/dist/sdk/payment/use-payment-actions.d.ts +18 -3
- package/dist/sdk/payment/use-payment-actions.js +23 -4
- package/dist/sdk/payment/use-payment-actions.js.map +1 -1
- package/dist/sdk/payment/use-place-order.d.ts +10 -2
- package/dist/sdk/payment/use-place-order.js +138 -76
- package/dist/sdk/payment/use-place-order.js.map +1 -1
- package/dist/sdk/provider/storefront-provider.d.ts +1 -7
- package/dist/sdk/provider/storefront-provider.js +4 -11
- package/dist/sdk/provider/storefront-provider.js.map +1 -1
- package/dist/sdk/seo/entity-landing.d.ts +24 -0
- package/dist/sdk/seo/entity-landing.js +30 -0
- package/dist/sdk/seo/entity-landing.js.map +1 -0
- package/dist/sdk/seo/page-alternates.d.ts +3 -2
- package/dist/sdk/seo/page-alternates.js +4 -2
- package/dist/sdk/seo/page-alternates.js.map +1 -1
- package/dist/sdk/seo/search-landing.d.ts +42 -0
- package/dist/sdk/seo/search-landing.js +85 -0
- package/dist/sdk/seo/search-landing.js.map +1 -0
- package/dist/sdk/session/mock-session.d.ts +9 -0
- package/dist/sdk/session/mock-session.js +31 -0
- package/dist/sdk/session/mock-session.js.map +1 -0
- package/dist/sdk/session/read-server-session.d.ts +3 -0
- package/dist/sdk/session/read-server-session.js +5 -0
- package/dist/sdk/session/read-server-session.js.map +1 -1
- package/dist/sdk/session/return-path-segment.d.ts +10 -0
- package/dist/sdk/session/return-path-segment.js +15 -0
- package/dist/sdk/session/return-path-segment.js.map +1 -0
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -1
- package/dist/utils/safe-href.d.ts +2 -0
- package/package.json +4 -3
- package/skills/storefront-asset/SKILL.md +2 -2
- package/skills/storefront-asset/references/api-side.md +27 -14
- package/skills/storefront-asset/references/findings.md +5 -2
- package/src/styles/tailwind.css +8 -0
- package/dist/matter/shipping-address/country-descriptors.d.ts +0 -1
- package/dist/message-locales.json +0 -7
- package/dist/sdk/i18n/client.d.ts +0 -4
- package/dist/sdk/i18n/client.js +0 -4
- package/dist/sdk/i18n/locales.d.ts +0 -8
- package/dist/sdk/i18n/locales.js +0 -57
- package/dist/sdk/i18n/locales.js.map +0 -1
- package/dist/sdk/i18n/messages/en-US.js +0 -183
- package/dist/sdk/i18n/messages/en-US.js.map +0 -1
- package/dist/sdk/i18n/messages/en-US.json +0 -178
- package/dist/sdk/i18n/messages/en-US.json.d.ts +0 -182
- package/dist/sdk/i18n/messages/es-ES.js +0 -183
- package/dist/sdk/i18n/messages/es-ES.js.map +0 -1
- package/dist/sdk/i18n/messages/es-ES.json +0 -178
- package/dist/sdk/i18n/messages/pt-BR.js +0 -183
- package/dist/sdk/i18n/messages/pt-BR.js.map +0 -1
- package/dist/sdk/i18n/messages/pt-BR.json +0 -178
- package/dist/sdk/i18n/provider.d.ts +0 -1
- package/dist/sdk/i18n/provider.js +0 -30
- package/dist/sdk/i18n/provider.js.map +0 -1
- package/dist/sdk/i18n/server.d.ts +0 -28
- package/dist/sdk/i18n/server.js +0 -59
- package/dist/sdk/i18n/server.js.map +0 -1
- package/dist/utils/resolve-authored-copy.js +0 -18
- package/dist/utils/resolve-authored-copy.js.map +0 -1
- package/dist/utils/substitute-template.js +0 -33
- package/dist/utils/substitute-template.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-profile-fieldset.js","names":[],"sources":["../../../src/matter/client-profile-form/client-profile-fieldset.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport type { DocumentType } from '../../particles/document-field/document-field.js';\nimport { DOCUMENTS, DocumentField, isSupportedDocumentType } from '../../particles/document-field/document-field.js';\nimport type { FieldRule } from '../../particles/field/field.js';\nimport {\n Field,\n FieldBinding,\n FieldsetFieldContext,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { useFormRegistry } from '../../particles/form/form.js';\nimport type { PhoneCountry } from '../../particles/phone-field/phone-field.js';\nimport { PhoneField, toE164 } from '../../particles/phone-field/phone-field.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 { ClientProfileUpdateInput } from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * `ClientProfileFieldset` — the composable, one-Save write of the `ClientProfile` sibling entity\n * (RFC: Composable Entity Forms, `Proposal > Design > The fieldset`). It registers itself with the\n * enclosing `FormRoot` under the `clientProfile` namespace and dispatches\n * `$actions.identity.clientProfileUpdate` for its own submit slot; it renders no `<form>` of its own.\n *\n * The four controls below are the smallest placeable unit: each calls `useFieldsetField` for its full\n * field name, renders a `FieldBinding` carrying the field's static facts, and — inside it — either the\n * default anatomy or the author's own children. No control's field contract carries a blocking\n * `RegisterOptions` key (no `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`); requiredness\n * on the phone control rides on its own `requirement` prop instead, which only ever gates required\n * validation — a field the store does not want is omitted from the page, not switched off by a prop.\n *\n * The fieldset's context name is `client-profile-fieldset`, not `client-profile`: the shipped\n * `ClientProfilePhoneControl` (`matter/client-profile/client-profile.tsx`) already requires\n * `client-profile` and writes on blur, so reusing that name here would let an on-blur control compile\n * inside this batched fieldset and write immediately. `ClientProfileFieldsetPhoneControl` carries the\n * same container prefix as the context it requires, naming the collision rather than hiding it.\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated on the fieldset, its own data root\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientProfileFieldsetData on Query {\n clientProfile {\n __typename\n id\n firstName\n lastName\n phone\n document\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the ClientProfile sibling entity, unwrapped. */\nexport type ClientProfileFieldsetData = {\n firstName?: string | null;\n lastName?: string | null;\n phone?: string | null;\n document?: string | null;\n} | null;\n\n/** The four keys this fieldset registers under its namespace. */\ntype ProfileFieldKey = 'firstName' | 'lastName' | 'phone' | 'document';\n\n/** What the fieldset publishes to its controls. Carries no live value — react-hook-form owns those. */\ntype ClientProfileFieldsetContextValue = Readonly<{\n namespace: 'clientProfile';\n /** Seeds, resolved from `$data`. Empty string, never null, so a control never seeds `undefined`. */\n saved: Readonly<Record<ProfileFieldKey, string>>;\n /** True when the session reports `canEditData: false`. */\n readOnly: boolean;\n /** Phone mask/validation country, from the fieldset's own prop. */\n country: PhoneCountry;\n /** Locale document type; the document control renders only when supported. */\n documentType: string | undefined;\n /** The fieldset's own validation rules, per key. Present and empty today (Decision 6). */\n rules: Readonly<Partial<Record<ProfileFieldKey, FieldRule>>>;\n}>;\n\n/** No control publishes a rule today — a blocking `RegisterOptions` key would reopen the same submit\n * block for a read-only session (Decision 6): `readOnly` disables a control's rendered `<input>` via a\n * plain HTML attribute, never react-hook-form's own `disabled` registration option (`field.tsx`'s\n * `useController` call takes no `disabled`), so a required field would stay fully registered and\n * validated while the shopper has no way to focus or edit it. Kept as a stable empty object so the\n * context value's identity does not churn on every render. */\nconst NO_RULES: Readonly<Partial<Record<ProfileFieldKey, FieldRule>>> = {};\n\n/**\n * Rows `ClientProfileFieldsetSkeleton` draws when nobody says otherwise: one per control in the full\n * anatomy — first name, last name, phone, document. It is a default and not a derivation, because\n * the composed children are opaque here. A page that composes fewer sets `skeletonCount` to what it\n * composed, or the form jumps by the difference when the controls take the skeleton's place.\n */\nconst CLIENT_PROFILE_SKELETON_ROWS = 4;\n\nconst CLIENT_PROFILE_FIELDSET_UNSET = Symbol('ClientProfileFieldsetContextUnset');\n\nconst ClientProfileFieldsetContext = createContext<\n ClientProfileFieldsetContextValue | typeof CLIENT_PROFILE_FIELDSET_UNSET\n>(CLIENT_PROFILE_FIELDSET_UNSET);\n\nfunction useClientProfileFieldsetContext(): ClientProfileFieldsetContextValue {\n const ctx = useContext(ClientProfileFieldsetContext);\n if (ctx === CLIENT_PROFILE_FIELDSET_UNSET) {\n throw new Error('ClientProfileFieldset controls must be used inside ClientProfileFieldset.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport type ClientProfileFieldsetProps = {\n /** Phone mask/validation country, provided to the phone control via context. */\n country?: PhoneCountry;\n /** Locale document type; the document control renders only when supported. */\n documentType?: 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 profile 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 /** `ClientProfileFieldsetData` slice forwarded by the reactive runtime. */\n $data?: ClientProfileFieldsetData;\n /** Compiler-injected; carries `identity.clientProfileUpdate`. */\n $actions?: ComponentActions;\n};\n\ntype ProfileTextControlProps = { label?: string; placeholder?: string; className?: string; children?: ReactNode };\n\nexport type ClientProfileFirstNameControlProps = ProfileTextControlProps;\nexport type ClientProfileLastNameControlProps = ProfileTextControlProps;\n\nexport type ClientProfileFieldsetPhoneControlProps = {\n label?: string;\n placeholder?: string;\n /**\n * Raises the field to required. The composite owns it; the contract carries no rule (Decision 6),\n * so here the raise is the whole of the resolution. Unset is no opinion, which leaves the phone\n * optional.\n */\n requirement?: 'mandatory' | 'optional';\n errorInvalid?: string;\n errorRequired?: string;\n className?: string;\n /** Given, replaces PhoneField's default Field.Label + PhoneFieldInput + Field.Error anatomy. */\n children?: ReactNode;\n};\n\nexport type ClientProfileDocumentControlProps = {\n label?: string;\n placeholder?: string;\n errorMessage?: string;\n className?: string;\n /** Given, replaces DocumentField's default Field.Label + DocumentFieldInput + Field.Error anatomy. */\n children?: ReactNode;\n};\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientProfileFieldsetDefinition = defineComponent<ClientProfileFieldsetProps>({\n name: 'ClientProfileFieldset',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFieldset,\n fragment,\n fetchStrategy: 'reactive',\n skeleton: ClientProfileFieldsetSkeleton,\n requiresContext: ['form', 'session'],\n providesContext: 'client-profile-fieldset',\n actions: { identity: ['clientProfileUpdate'] },\n editor: { label: 'Client Profile Fieldset', category: 'identity' },\n schema: {\n country: { type: 'string', default: 'US', label: 'Phone country (US or BR)' },\n documentType: { type: 'string', label: 'Document type (e.g. CPF)' },\n skeletonCount: { type: 'number', default: 4, label: 'Skeleton rows' },\n loadingLabel: { type: 'string', default: 'Loading your details', label: 'Loading announcement' },\n loadedLabel: { type: 'string', default: 'Your details are ready', label: 'Loaded announcement' },\n groupLabel: { type: 'string', default: 'Your details', label: 'Accessible group name' },\n },\n guideline:\n 'Registers a batched write of the ClientProfile entity with the enclosing FormRoot; renders one Fieldset.Root and no <form>. Must be inside a FormRoot with a SessionRoot ancestor. Compose ClientProfileFirstNameControl / ClientProfileLastNameControl / ClientProfileFieldsetPhoneControl / ClientProfileDocumentControl as children, in any order. The controls mount only once the profile 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. Dispatches only the fields the shopper changed. groupLabel names the group as its accessible name; blank emits no aria-label, and a composed FieldsetLegend wins over it.',\n});\n\nexport const ClientProfileFirstNameControlDefinition = defineComponent<ClientProfileFirstNameControlProps>({\n name: 'ClientProfileFirstNameControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFirstNameControl,\n requiresContext: 'client-profile-fieldset',\n providesContext: 'field',\n editor: { label: 'Client Profile First Name Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline:\n \"The bound first-name control; must be a descendant of ClientProfileFieldset. Renders Field.Root > Field.Label + Field.Control + Field.Error by default, or the composed children in the author's own order.\",\n});\n\nexport const ClientProfileLastNameControlDefinition = defineComponent<ClientProfileLastNameControlProps>({\n name: 'ClientProfileLastNameControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileLastNameControl,\n requiresContext: 'client-profile-fieldset',\n providesContext: 'field',\n editor: { label: 'Client Profile Last Name Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline:\n \"The bound last-name control; must be a descendant of ClientProfileFieldset. Renders Field.Root > Field.Label + Field.Control + Field.Error by default, or the composed children in the author's own order.\",\n});\n\nexport const ClientProfileFieldsetPhoneControlDefinition = defineComponent<ClientProfileFieldsetPhoneControlProps>({\n name: 'ClientProfileFieldsetPhoneControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFieldsetPhoneControl,\n requiresContext: 'client-profile-fieldset',\n // Provides both names (mirrors shipping-address.tsx:595's Decision 7): 'field' is what every\n // fieldset Control declares (RFC:503), but this control also composes PhoneField, whose\n // PhoneFieldInput part requires 'phone-field' — a page composing\n // ClientProfileFieldsetPhoneControl > PhoneFieldInput would otherwise fail the build with a\n // context-constraint violation, since PhoneField itself (the only 'phone-field' provider) never\n // appears in the page schema (finding F1).\n providesContext: ['field', 'phone-field'],\n editor: { label: 'Client Profile Fieldset Phone Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n // No default: an unset requirement is no opinion, not a raise to mandatory.\n requirement: { type: ['mandatory', 'optional'] as const, label: 'Requirement' },\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n errorInvalid: { type: 'string', label: 'Invalid error message' },\n errorRequired: { type: 'string', label: 'Required error message' },\n },\n guideline:\n \"The bound phone control; must be a descendant of ClientProfileFieldset. Distinct from ClientProfilePhoneControl (matter/client-profile), which writes on blur and requires the client-profile context — the two cannot compile into each other's container. Composes the PhoneField particle: recomposable (RFC:503) — given children, they replace PhoneField's default Field.Label + PhoneFieldInput + Field.Error anatomy, in any order; childless keeps today's order. Its className styles PhoneField's own root, the node that lays out label, input and error — not the wrapper, which carries only the data-fs-client-profile-fieldset-field=\\\"phone\\\" styling hook. A store that does not want a phone field omits this element from the page: requirement only governs required validation, never visibility.\",\n});\n\nexport const ClientProfileDocumentControlDefinition = defineComponent<ClientProfileDocumentControlProps>({\n name: 'ClientProfileDocumentControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileDocumentControl,\n requiresContext: 'client-profile-fieldset',\n // Provides both names, same reasoning as ClientProfileFieldsetPhoneControlDefinition above: this\n // control composes DocumentField, whose DocumentFieldInput part requires 'document-field' — a page\n // composing ClientProfileDocumentControl > DocumentFieldInput would otherwise fail the build\n // (finding F1).\n providesContext: ['field', 'document-field'],\n editor: { label: 'Client Profile Document Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n errorMessage: { type: 'string', label: 'Error message' },\n },\n guideline:\n \"The bound tax-document control; must be a descendant of ClientProfileFieldset. Renders nothing, and registers no field name, when the fieldset's documentType is unsupported. Composes the DocumentField particle: recomposable (RFC:503) — given children, they replace DocumentField's default Field.Label + DocumentFieldInput + Field.Error anatomy, in any order; childless keeps today's order.\",\n});\n\n// ---------------------------------------------------------------------------\n// Fieldset root\n// ---------------------------------------------------------------------------\n\n/**\n * Registers a batched write of the `ClientProfile` entity with the enclosing `FormRoot`\n * (`registerFieldset`, namespace `clientProfile`) on mount, unconditionally — so this fieldset keeps its\n * original dispatch slot even while its own query is still resolving. Its children — the seed values and\n * the field-name registry its controls need — render only once the entity has resolved; until then the\n * `Fieldset.Root` carries `-pending` and renders `ClientProfileFieldsetSkeleton` (Decision 5).\n * `dispatch` and `toPayload` are `useCallback([])`-stable and read `$actions`/`country`/`documentType`\n * through a ref, so the registration effect runs exactly once per mount regardless of how often the\n * parent re-renders.\n *\n * \"Resolved\" is two conditions, because `$data` alone cannot answer it. Under the reactive runtime the\n * slice is defined from the first render — `useReactiveEntity` hands down `fallbackData` while the cache\n * read is incomplete — so an empty server answer looks exactly like a resolved one, and the controls\n * would mount and seed `''` before the shopper's real profile arrives. `useSeedAdoption` re-seeds a\n * clean field with `defaultValue` on every render, but once the field turns dirty no later seed\n * ever reaches it again: a shopper who starts typing before the real profile arrives locks that\n * empty seed in for good, and even a shopper who does not type sees the field flash from `''` to\n * the real data. `useReactiveDataSettled` supplies the missing half: the page query's own\n * in-flight state, latched so it only ever goes pending → settled. The `$data === undefined` half still\n * carries 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 polite\n * live region that announces `loadingLabel` and then `loadedLabel`. Style the region `sr-only` — it is\n * text meant for a screen reader, not for the page.\n */\nexport function ClientProfileFieldset({\n country = 'US',\n documentType,\n skeletonCount = CLIENT_PROFILE_SKELETON_ROWS,\n loadingLabel = 'Loading your details',\n loadedLabel = 'Your details are ready',\n groupLabel = 'Your details',\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ClientProfileFieldsetProps) {\n // Nesting fieldsets has no legitimate use: useFieldsetField resolves the *nearest*\n // FieldsetFieldContext, not the one owning a control's actual namespace, so a control nested two\n // fieldsets deep would silently register under the wrong one and its write would be discarded on\n // submit. Runtime registry integrity, mirroring the namespace-collision throw FormRoot already ships\n // (form.tsx:280-288).\n useNoAncestorFieldset('ClientProfileFieldset');\n\n const $data = useDataOverride($dataProp);\n\n const $actions = useActionsOverride($actionsProp);\n // Three conditions, not two. `useReactiveDataSettled` latches one way and never re-arms, so on its\n // own it answers \"has this page ever resolved\", not \"is what I am holding right now the server's\n // answer\" — after the page query's entity ref moves to one this cache never stored, or its root is\n // skipped for want of a variable, the slice silently regresses to `fallbackData` while the latch\n // still reads settled. `useEntityDataResolved` is the per-entity half: unlatched, so it follows the\n // slice back down and returns this fieldset to its skeleton instead of leaving live controls seeded\n // from a placeholder.\n const settled = useReactiveDataSettled();\n const sliceResolved = useEntityDataResolved();\n const resolved = settled && sliceResolved && $data !== undefined;\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n // Runs before useFormContext() below: useFormRegistry() throws the friendly \"Form parts must be used\n // inside FormRoot.\" error when no FormRoot is above, so a FormRoot-less render fails there rather than\n // reaching the getFieldState destructure, which throws an unhelpful TypeError instead (useFormContext()\n // resolves to null outside a FormRoot, and destructuring null throws).\n const { registerFieldset } = useFormRegistry();\n\n // Decision 3, as later narrowed: this fieldset still reads dirtiness imperatively, but the rule is no\n // longer the form's. `FormRoot` subscribes `dirtyFields` in render and decides which fieldsets to\n // dispatch from it, by the fields each one has mounted, on react-hook-form's documented contract.\n //\n // The imperative read survives here because it asks a different question in a different place: which\n // of *this* fieldset's own fields changed, resolved inside `toPayload` at submit time, by full\n // registered field name — the shape `getFieldState` documents. `useFormContext()` adds no\n // `formState` subscription of its own; one is created only when a caller reads a formState key off\n // the `useForm`/`useFormState` proxy (or hands that already-subscribed object to `getFieldState`'s\n // second argument). Calling `getFieldState(name)` with no second argument reads the current internal\n // state directly, so this fieldset root still does not re-render on a keystroke.\n const { getFieldState } = useFormContext();\n\n const latest = useRef({ $actions, country, documentType, readOnly, getFieldState });\n useEffect(() => {\n latest.current = { $actions, country, documentType, readOnly, getFieldState };\n }, [$actions, country, documentType, readOnly, getFieldState]);\n\n const { registry: fieldsetRegistry, getFieldNames } = useFieldsetFieldNames('clientProfile');\n\n const dispatch = useCallback(async (payload: Record<string, unknown>) => {\n // Defence-in-depth: the UI disables every input while read-only, but `FormClear` sets values (and\n // marks them dirty) on every registered field regardless of that disabled attribute — react-hook-\n // form's own `useController` calls never receive a `disabled` registration option, so it has no\n // notion of \"disabled\" of its own. Guarding here keeps the write from reaching the network even if\n // some other composition dirties this fieldset while canEditData is false (the server also refuses,\n // but a client-side guard should not depend on that).\n if (latest.current.readOnly) {\n throw new Error('ClientProfileFieldset cannot dispatch while the session is read-only.');\n }\n const update = latest.current.$actions?.identity?.clientProfileUpdate;\n // Throwing is the contract's failure path: FormRoot catches it and records this fieldset's failure\n // (form.tsx:264-266). Returning [] would report an unqualified success for a write that never\n // happened.\n if (!update) throw new Error('ClientProfileFieldset requires $actions.identity.clientProfileUpdate.');\n return update(payload as ClientProfileUpdateInput);\n }, []);\n\n const toPayload = useCallback((values: Record<string, unknown>): Record<string, unknown> => {\n const { country: activeCountry, documentType: activeDocumentType, getFieldState } = latest.current;\n // FR-5: a key is emitted only when the shopper actually changed it — presence in `values` alone\n // (every registered field is always present) is not enough. `dirtyFields` is not read directly;\n // `getFieldState` is called with no second argument, which reads react-hook-form's current\n // internal state without subscribing to it (Decision 3).\n const isDirty = (key: ProfileFieldKey) => getFieldState(`clientProfile.${key}`).isDirty;\n const payload: Record<string, string> = {};\n if ('firstName' in values && isDirty('firstName')) payload.firstName = String(values.firstName ?? '').trim();\n if ('lastName' in values && isDirty('lastName')) payload.lastName = String(values.lastName ?? '').trim();\n if ('phone' in values && isDirty('phone')) {\n const raw = String(values.phone ?? '').trim();\n // toE164 on a blank value returns the bare country code, which would write \"+55\" over the\n // shopper's number and fail every later save.\n payload.phone = raw ? toE164(raw, activeCountry) : '';\n }\n // The type's own sanitiser (digits for CPF, SSN and SIN, letters kept for RFC). Omitted when the type is\n // not supported: a value for a control that is no longer shown is never sent.\n if ('document' in values && isDirty('document') && isSupportedDocumentType(activeDocumentType)) {\n // The control only ever writes a string (the masked input's own value); `values` is typed `unknown`\n // because the fieldset contract carries every field's value, so it is narrowed here, not stringified.\n const rawDocument = typeof values.document === 'string' ? values.document : '';\n payload.document = DOCUMENTS[activeDocumentType].sanitize(rawDocument);\n }\n return payload;\n }, []);\n\n useEffect(\n () =>\n registerFieldset({\n namespace: 'clientProfile',\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` (`clientProfile` → `client-profile`) — not authored per\n // page (Decision 2).\n label: 'client-profile',\n }),\n [registerFieldset, getFieldNames, dispatch, toPayload],\n );\n\n const saved = useMemo<Readonly<Record<ProfileFieldKey, string>>>(\n () => ({\n firstName: $data?.firstName ?? '',\n lastName: $data?.lastName ?? '',\n phone: $data?.phone ?? '',\n document: $data?.document ?? '',\n }),\n [$data],\n );\n\n const contextValue = useMemo<ClientProfileFieldsetContextValue>(\n () => ({ namespace: 'clientProfile', saved, readOnly, country, documentType, rules: NO_RULES }),\n [saved, readOnly, country, documentType],\n );\n\n // Assistive technology only reports a change inside a region that was already in the tree, so a\n // region mounted together with its text announces nothing. The region therefore sits in both\n // branches and starts empty, with the wait written on the pass after mount and replaced — not\n // cleared — once the controls are up: the skeleton is `aria-hidden`, so without this second\n // message the form would materialise in silence (WCAG 2.1 SC 4.1.3).\n const [announcement, setAnnouncement] = useState('');\n const announced = resolved ? loadedLabel : loadingLabel;\n useEffect(() => {\n setAnnouncement(announced);\n }, [announced]);\n\n return (\n <Fieldset.Root\n className={className}\n disabled={readOnly}\n aria-busy={resolved ? undefined : true}\n // FR-12: blank (or whitespace-only) means no name is exposed, mirroring the loadingLabel/\n // loadedLabel convention. On the root itself (FR-13), so it is identical whether the fieldset\n // is pending or resolved; a page-composed FieldsetLegend still wins via aria-labelledby.\n {...(groupLabel?.trim() ? { 'aria-label': groupLabel } : {})}\n data-fs-client-profile-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-client-profile-fieldset-pending': '' })}\n {...(readOnly ? { 'data-fs-client-profile-fieldset-readonly': '' } : {})}\n >\n {resolved ? (\n <FieldsetFieldContext.Provider value={fieldsetRegistry}>\n <ClientProfileFieldsetContext.Provider value={contextValue}>{children}</ClientProfileFieldsetContext.Provider>\n </FieldsetFieldContext.Provider>\n ) : (\n <ClientProfileFieldsetSkeleton count={skeletonCount} />\n )}\n <output aria-live=\"polite\" data-fs-client-profile-fieldset-announcement=\"\">\n {announcement}\n </output>\n </Fieldset.Root>\n );\n}\n\n/**\n * The loading state of the fieldset, rendered in place of the controls until the entity resolves and\n * declared as the definition's `skeleton`. Purely visual: the wait is spoken by the fieldset's own live\n * region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ClientProfileFieldsetSkeleton({\n count = CLIENT_PROFILE_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-client-profile-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-client-profile-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nClientProfileFieldset.Skeleton = ClientProfileFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Text controls — first name, last name\n// ---------------------------------------------------------------------------\n\nfunction ProfileTextControl({\n fieldKey,\n attr,\n autoComplete,\n defaultLabel,\n label,\n placeholder,\n className,\n children,\n}: {\n fieldKey: 'firstName' | 'lastName';\n attr: string;\n autoComplete: string;\n defaultLabel: string;\n label?: string;\n placeholder?: string;\n className?: string;\n children?: ReactNode;\n}) {\n const { namespace, saved, readOnly, rules } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, fieldKey);\n\n return (\n <FieldBinding\n name={name}\n label={label ?? defaultLabel}\n placeholder={placeholder}\n defaultValue={saved[fieldKey]}\n rule={rules[fieldKey]}\n disabled={readOnly}\n autoComplete={autoComplete}\n >\n <Field.Root className={className} data-fs-client-profile-fieldset-field={attr}>\n {children ?? (\n <>\n <Field.Label />\n <Field.Control />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\nexport function ClientProfileFirstNameControl({\n label,\n placeholder,\n className,\n children,\n}: ClientProfileFirstNameControlProps) {\n return (\n <ProfileTextControl\n fieldKey=\"firstName\"\n attr=\"first-name\"\n autoComplete=\"given-name\"\n defaultLabel=\"First name\"\n label={label}\n placeholder={placeholder}\n className={className}\n >\n {children}\n </ProfileTextControl>\n );\n}\n\nexport function ClientProfileLastNameControl({\n label,\n placeholder,\n className,\n children,\n}: ClientProfileLastNameControlProps) {\n return (\n <ProfileTextControl\n fieldKey=\"lastName\"\n attr=\"last-name\"\n autoComplete=\"family-name\"\n defaultLabel=\"Last name\"\n label={label}\n placeholder={placeholder}\n className={className}\n >\n {children}\n </ProfileTextControl>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Phone control — the fieldset-bound counterpart of ClientProfilePhoneControl\n// ---------------------------------------------------------------------------\n\n/**\n * Composes `PhoneField` inside a `FieldBinding`, wrapped in a `data-fs-client-profile-fieldset-field=\"phone\"`\n * node — the same styling hook attribute the text controls carry on their own `Field.Root`.\n * `useFieldsetField` runs unconditionally, before `requirement` is even read — there is no suppressed\n * state for this control to second-guess; `requirement` only ever raises the field to required,\n * and left unset it raises nothing.\n */\nexport function ClientProfileFieldsetPhoneControl({\n label,\n placeholder,\n requirement,\n errorInvalid,\n errorRequired,\n className,\n children,\n}: ClientProfileFieldsetPhoneControlProps) {\n const { namespace, saved, readOnly, rules, country } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, 'phone');\n\n const binding = (\n <FieldBinding\n name={name}\n label={label}\n placeholder={placeholder}\n defaultValue={saved.phone}\n rule={rules.phone}\n disabled={readOnly}\n >\n <PhoneField\n country={country}\n requirement={requirement}\n errorInvalid={errorInvalid}\n errorRequired={errorRequired}\n className={className}\n >\n {children}\n </PhoneField>\n </FieldBinding>\n );\n\n // The wrapper carries no className of its own (Decision 1): className lands on PhoneField's own\n // Field.Root, the node that actually stacks label, input and error, so it needs no flex slot here.\n return <div data-fs-client-profile-fieldset-field=\"phone\">{binding}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Document control — self-gates on documentType, through an inner component\n// ---------------------------------------------------------------------------\n\ntype ClientProfileDocumentControlInnerProps = ClientProfileDocumentControlProps & { documentType: DocumentType };\n\n/**\n * `useFieldsetField` (through `useClientProfileFieldsetContext`'s namespace) lives only in this inner\n * component, mounted only once `ClientProfileDocumentControl` has already decided the document type is\n * supported. Splitting the decision from the registration this way (Decision 8) keeps a control that\n * renders nothing from registering a field name `FormClear` would otherwise dirty and dispatch.\n */\nfunction ClientProfileDocumentControlInner({\n documentType,\n label,\n placeholder,\n errorMessage,\n className,\n children,\n}: ClientProfileDocumentControlInnerProps) {\n const { namespace, saved, readOnly, rules } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, 'document');\n\n return (\n <FieldBinding\n name={name}\n label={label ?? DOCUMENTS[documentType].name}\n placeholder={placeholder}\n defaultValue={saved.document}\n rule={rules.document}\n disabled={readOnly}\n >\n <DocumentField\n documentType={documentType}\n errorMessage={errorMessage}\n className={className}\n data-fs-client-profile-fieldset-field=\"document\"\n >\n {children}\n </DocumentField>\n </FieldBinding>\n );\n}\n\nexport function ClientProfileDocumentControl({\n label,\n placeholder,\n errorMessage,\n className,\n children,\n}: ClientProfileDocumentControlProps) {\n const { documentType } = useClientProfileFieldsetContext();\n if (!isSupportedDocumentType(documentType)) return null;\n\n return (\n <ClientProfileDocumentControlInner\n documentType={documentType}\n label={label}\n placeholder={placeholder}\n errorMessage={errorMessage}\n className={className}\n >\n {children}\n </ClientProfileDocumentControlInner>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-profile-fieldset.js","names":[],"sources":["../../../src/matter/client-profile-form/client-profile-fieldset.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ContentTypeDefinition,\n type ContentValue,\n defineComponent,\n defineContentType,\n type MessageFieldName,\n type MessageLocaleProp,\n} from '@vtex/fs-core';\nimport {\n type ComponentPropsWithRef,\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useFormContext } from 'react-hook-form';\nimport type { DocumentType } from '../../particles/document-field/document-field.js';\nimport { DOCUMENTS, DocumentField, isSupportedDocumentType } from '../../particles/document-field/document-field.js';\nimport type { FieldRule } from '../../particles/field/field.js';\nimport {\n Field,\n FieldBinding,\n FieldsetFieldContext,\n useFieldsetField,\n useFieldsetFieldNames,\n useNoAncestorFieldset,\n} from '../../particles/field/field.js';\nimport { Fieldset } from '../../particles/fieldset/fieldset.js';\nimport { type FormUserError, useFormRegistry } from '../../particles/form/form.js';\nimport type { PhoneCountry } from '../../particles/phone-field/phone-field.js';\nimport { PhoneField, toE164 } from '../../particles/phone-field/phone-field.js';\nimport { useActionsOverride } from '../../sdk/actions/actions-override-context.js';\nimport type { ComponentActions } from '../../sdk/actions/types.js';\nimport { useDataOverride } from '../../sdk/data/data-override-context.js';\nimport { useEntityDataResolved } from '../../sdk/data/entity-resolution-context.js';\nimport { useReactiveDataSettled } from '../../sdk/data/use-reactive-data-settled.js';\nimport { formatErrorCode } from '../../sdk/i18n/format-error-code.js';\nimport type { MessageFormatter } from '../../sdk/i18n/message-formatter.js';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\nimport type { ClientProfileUpdateInput, ClientProfileUserError } from '../../sdk/identity/operations.js';\nimport { useSession } from '../session/session.js';\n\n/**\n * `ClientProfileFieldset` — the composable, one-Save write of the `ClientProfile` sibling entity\n * (RFC: Composable Entity Forms, `Proposal > Design > The fieldset`). It registers itself with the\n * enclosing `FormRoot` under the `clientProfile` namespace and dispatches\n * `$actions.identity.clientProfileUpdate` for its own submit slot; it renders no `<form>` of its own.\n *\n * The four controls below are the smallest placeable unit: each calls `useFieldsetField` for its full\n * field name, renders a `FieldBinding` carrying the field's static facts, and — inside it — either the\n * default anatomy or the author's own children. No control's field contract carries a blocking\n * `RegisterOptions` key (no `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`); requiredness\n * on the phone control rides on its own `requirement` prop instead, which only ever gates required\n * validation — a field the store does not want is omitted from the page, not switched off by a prop.\n *\n * The fieldset's context name is `client-profile-fieldset`, not `client-profile`: the shipped\n * `ClientProfilePhoneControl` (`matter/client-profile/client-profile.tsx`) already requires\n * `client-profile` and writes on blur, so reusing that name here would let an on-blur control compile\n * inside this batched fieldset and write immediately. `ClientProfileFieldsetPhoneControl` carries the\n * same container prefix as the context it requires, naming the collision rather than hiding it.\n */\n\n// ---------------------------------------------------------------------------\n// GraphQL Fragment — colocated on the fieldset, its own data root\n// ---------------------------------------------------------------------------\n\nconst fragment = /* GraphQL */ `\n fragment ClientProfileFieldsetData on Query {\n clientProfile {\n __typename\n id\n firstName\n lastName\n phone\n document\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Content model\n// ---------------------------------------------------------------------------\n\nexport const ClientProfileFieldsetContent = defineContentType({\n id: 'client-profile-fieldset',\n title: 'Client Profile Fieldset',\n description: \"The profile fieldset's loading and loaded announcements and its accessible group name.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n loadingLabel: {\n type: 'string',\n title: 'Loading announcement',\n format: 'icu-message',\n messageSource: 'Loading your details',\n },\n loadedLabel: {\n type: 'string',\n title: 'Loaded announcement',\n format: 'icu-message',\n messageSource: 'Your details are ready',\n },\n groupLabel: {\n type: 'string',\n title: 'Accessible group name',\n format: 'icu-message',\n messageSource: 'Your details',\n messageOptional: true,\n },\n genericErrorMessage: {\n type: 'string',\n title: 'Generic error message',\n description: 'Shown by FormError when the details could not be saved.',\n format: 'icu-message',\n messageSource: 'Unable to save your details. Please try again.',\n },\n },\n },\n});\n\ntype ClientProfileUpdateErrorCode = 'MISSING_CART_CONTEXT' | 'CART_NOT_FOUND' | 'NO_PROFILE_FIELD_PROVIDED';\n\n/**\n * The message for each refusal of the profile write: every `ClientProfileUpdateErrorCode` plus the\n * client-minted transport failure. None is a fault the shopper can fix, so all share one message.\n * `dispatch` hands `FormError` this copy, and genericErrorMessage for an unknown code.\n */\nexport const CLIENT_PROFILE_FIELDSET_ERROR_FIELDS = {\n MISSING_CART_CONTEXT: 'genericErrorMessage',\n CART_NOT_FOUND: 'genericErrorMessage',\n NO_PROFILE_FIELD_PROVIDED: 'genericErrorMessage',\n NETWORK_ERROR: 'genericErrorMessage',\n} as const satisfies Record<\n ClientProfileUpdateErrorCode | 'NETWORK_ERROR',\n MessageFieldName<typeof ClientProfileFieldsetContent>\n>;\n\nfunction wordClientProfileError(\n error: ClientProfileUserError,\n { format }: MessageFormatter<typeof ClientProfileFieldsetContent>,\n): FormUserError {\n return {\n code: error.code,\n message: formatErrorCode(\n ClientProfileFieldsetContent,\n CLIENT_PROFILE_FIELDSET_ERROR_FIELDS,\n error,\n format,\n 'genericErrorMessage',\n ),\n };\n}\n\nexport const ClientProfileFieldsetPhoneControlContent = defineContentType({\n id: 'client-profile-fieldset-phone',\n title: 'Client Profile Fieldset Phone Control',\n description: \"The phone control's label and its validation messages.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label', format: 'icu-message', messageSource: 'Phone' },\n errorInvalid: {\n type: 'string',\n title: 'Invalid error message',\n format: 'icu-message',\n messageSource: 'Invalid phone number',\n },\n errorRequired: {\n type: 'string',\n title: 'Required error message',\n format: 'icu-message',\n messageSource: 'Phone number is required',\n },\n },\n },\n});\n\nexport const ClientProfileFirstNameControlContent = defineContentType({\n id: 'client-profile-first-name',\n title: 'Client Profile First Name Control',\n description: \"The first-name control's label.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label', format: 'icu-message', messageSource: 'First name' },\n },\n },\n});\n\nexport const ClientProfileLastNameControlContent = defineContentType({\n id: 'client-profile-last-name',\n title: 'Client Profile Last Name Control',\n description: \"The last-name control's label.\",\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string', title: 'Label', format: 'icu-message', messageSource: 'Last name' },\n },\n },\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The `$data` slice forwarded by the reactive runtime — the ClientProfile sibling entity, unwrapped. */\nexport type ClientProfileFieldsetData = {\n firstName?: string | null;\n lastName?: string | null;\n phone?: string | null;\n document?: string | null;\n} | null;\n\n/** The four keys this fieldset registers under its namespace. */\ntype ProfileFieldKey = 'firstName' | 'lastName' | 'phone' | 'document';\n\n/** What the fieldset publishes to its controls. Carries no live value — react-hook-form owns those. */\ntype ClientProfileFieldsetContextValue = Readonly<{\n namespace: 'clientProfile';\n /** Seeds, resolved from `$data`. Empty string, never null, so a control never seeds `undefined`. */\n saved: Readonly<Record<ProfileFieldKey, string>>;\n /** True when the session reports `canEditData: false`. */\n readOnly: boolean;\n /** Phone mask/validation country, from the fieldset's own prop. */\n country: PhoneCountry;\n /** Locale document type; the document control renders only when supported. */\n documentType: string | undefined;\n /** The fieldset's own validation rules, per key. Present and empty today (Decision 6). */\n rules: Readonly<Partial<Record<ProfileFieldKey, FieldRule>>>;\n}>;\n\n/** No control publishes a rule today — a blocking `RegisterOptions` key would reopen the same submit\n * block for a read-only session (Decision 6): `readOnly` disables a control's rendered `<input>` via a\n * plain HTML attribute, never react-hook-form's own `disabled` registration option (`field.tsx`'s\n * `useController` call takes no `disabled`), so a required field would stay fully registered and\n * validated while the shopper has no way to focus or edit it. Kept as a stable empty object so the\n * context value's identity does not churn on every render. */\nconst NO_RULES: Readonly<Partial<Record<ProfileFieldKey, FieldRule>>> = {};\n\n/**\n * Rows `ClientProfileFieldsetSkeleton` draws when nobody says otherwise: one per control in the full\n * anatomy — first name, last name, phone, document. It is a default and not a derivation, because\n * the composed children are opaque here. A page that composes fewer sets `skeletonCount` to what it\n * composed, or the form jumps by the difference when the controls take the skeleton's place.\n */\nconst CLIENT_PROFILE_SKELETON_ROWS = 4;\n\nconst CLIENT_PROFILE_FIELDSET_UNSET = Symbol('ClientProfileFieldsetContextUnset');\n\nconst ClientProfileFieldsetContext = createContext<\n ClientProfileFieldsetContextValue | typeof CLIENT_PROFILE_FIELDSET_UNSET\n>(CLIENT_PROFILE_FIELDSET_UNSET);\n\nfunction useClientProfileFieldsetContext(): ClientProfileFieldsetContextValue {\n const ctx = useContext(ClientProfileFieldsetContext);\n if (ctx === CLIENT_PROFILE_FIELDSET_UNSET) {\n throw new Error('ClientProfileFieldset controls must be used inside ClientProfileFieldset.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport type ClientProfileFieldsetProps = MessageLocaleProp & {\n /** Phone mask/validation country, provided to the phone control via context. */\n country?: PhoneCountry;\n /** Locale document type; the document control renders only when supported. */\n documentType?: string;\n /** Placeholder rows the loading skeleton draws. Set it to the number of controls composed here. */\n skeletonCount?: number;\n /** The loading and loaded announcements and the accessible group name. */\n $content?: ContentValue<typeof ClientProfileFieldsetContent>;\n className?: string;\n children?: ReactNode;\n /** `ClientProfileFieldsetData` slice forwarded by the reactive runtime. */\n $data?: ClientProfileFieldsetData;\n /** Compiler-injected; carries `identity.clientProfileUpdate`. */\n $actions?: ComponentActions;\n};\n\ntype ProfileTextControlProps<T extends ContentTypeDefinition> = MessageLocaleProp & {\n placeholder?: string;\n /** The control's label. */\n $content?: ContentValue<T>;\n className?: string;\n children?: ReactNode;\n};\n\nexport type ClientProfileFirstNameControlProps = ProfileTextControlProps<typeof ClientProfileFirstNameControlContent>;\nexport type ClientProfileLastNameControlProps = ProfileTextControlProps<typeof ClientProfileLastNameControlContent>;\n\nexport type ClientProfileFieldsetPhoneControlProps = MessageLocaleProp & {\n placeholder?: string;\n /**\n * Raises the field to required. The composite owns it; the contract carries no rule (Decision 6),\n * so here the raise is the whole of the resolution. Unset is no opinion, which leaves the phone\n * optional.\n */\n requirement?: 'mandatory' | 'optional';\n /** The label and the invalid and required messages. */\n $content?: ContentValue<typeof ClientProfileFieldsetPhoneControlContent>;\n className?: string;\n /** Given, replaces PhoneField's default Field.Label + PhoneFieldInput + Field.Error anatomy. */\n children?: ReactNode;\n};\n\nexport type ClientProfileDocumentControlProps = {\n label?: string;\n placeholder?: string;\n errorMessage?: string;\n className?: string;\n /** Given, replaces DocumentField's default Field.Label + DocumentFieldInput + Field.Error anatomy. */\n children?: ReactNode;\n};\n\n// ---------------------------------------------------------------------------\n// Definitions\n// ---------------------------------------------------------------------------\n\nexport const ClientProfileFieldsetDefinition = defineComponent<ClientProfileFieldsetProps>({\n name: 'ClientProfileFieldset',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFieldset,\n content: ClientProfileFieldsetContent,\n fragment,\n fetchStrategy: 'reactive',\n skeleton: ClientProfileFieldsetSkeleton,\n requiresContext: ['form', 'session'],\n providesContext: 'client-profile-fieldset',\n actions: { identity: ['clientProfileUpdate'] },\n editor: { label: 'Client Profile Fieldset', category: 'identity' },\n schema: {\n country: { type: 'string', default: 'US', label: 'Phone country (US or BR)' },\n documentType: { type: 'string', label: 'Document type (e.g. CPF)' },\n skeletonCount: { type: 'number', default: 4, label: 'Skeleton rows' },\n },\n guideline:\n 'Registers a batched write of the ClientProfile entity with the enclosing FormRoot; renders one Fieldset.Root and no <form>. Must be inside a FormRoot with a SessionRoot ancestor. Compose ClientProfileFirstNameControl / ClientProfileLastNameControl / ClientProfileFieldsetPhoneControl / ClientProfileDocumentControl as children, in any order. The controls mount only once the profile 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; it reads the $content fields loadingLabel and loadedLabel. Dispatches only the fields the shopper changed. The $content field groupLabel names the group as its accessible name; an unauthored one emits no aria-label, and a composed FieldsetLegend wins over it.',\n});\n\nexport const ClientProfileFirstNameControlDefinition = defineComponent<ClientProfileFirstNameControlProps>({\n name: 'ClientProfileFirstNameControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFirstNameControl,\n content: ClientProfileFirstNameControlContent,\n requiresContext: 'client-profile-fieldset',\n providesContext: 'field',\n editor: { label: 'Client Profile First Name Control', category: 'identity' },\n schema: {\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline:\n \"The bound first-name control, labelled by the $content field label; must be a descendant of ClientProfileFieldset. Renders Field.Root > Field.Label + Field.Control + Field.Error by default, or the composed children in the author's own order.\",\n});\n\nexport const ClientProfileLastNameControlDefinition = defineComponent<ClientProfileLastNameControlProps>({\n name: 'ClientProfileLastNameControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileLastNameControl,\n content: ClientProfileLastNameControlContent,\n requiresContext: 'client-profile-fieldset',\n providesContext: 'field',\n editor: { label: 'Client Profile Last Name Control', category: 'identity' },\n schema: {\n placeholder: { type: 'string', label: 'Placeholder' },\n },\n guideline:\n \"The bound last-name control, labelled by the $content field label; must be a descendant of ClientProfileFieldset. Renders Field.Root > Field.Label + Field.Control + Field.Error by default, or the composed children in the author's own order.\",\n});\n\nexport const ClientProfileFieldsetPhoneControlDefinition = defineComponent<ClientProfileFieldsetPhoneControlProps>({\n name: 'ClientProfileFieldsetPhoneControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileFieldsetPhoneControl,\n content: ClientProfileFieldsetPhoneControlContent,\n requiresContext: 'client-profile-fieldset',\n // Provides both names (mirrors shipping-address.tsx:595's Decision 7): 'field' is what every\n // fieldset Control declares (RFC:503), but this control also composes PhoneField, whose\n // PhoneFieldInput part requires 'phone-field' — a page composing\n // ClientProfileFieldsetPhoneControl > PhoneFieldInput would otherwise fail the build with a\n // context-constraint violation, since PhoneField itself (the only 'phone-field' provider) never\n // appears in the page schema (finding F1).\n providesContext: ['field', 'phone-field'],\n editor: { label: 'Client Profile Fieldset Phone Control', category: 'identity' },\n schema: {\n placeholder: { type: 'string', label: 'Placeholder' },\n // No default: an unset requirement is no opinion, not a raise to mandatory.\n requirement: { type: ['mandatory', 'optional'] as const, label: 'Requirement' },\n },\n guideline:\n \"The bound phone control; must be a descendant of ClientProfileFieldset. Its label and its invalid and required messages are the $content fields label, errorInvalid and errorRequired. Distinct from ClientProfilePhoneControl (matter/client-profile), which writes on blur and requires the client-profile context — the two cannot compile into each other's container. Composes the PhoneField particle: recomposable (RFC:503) — given children, they replace PhoneField's default Field.Label + PhoneFieldInput + Field.Error anatomy, in any order; childless keeps today's order. Its className styles PhoneField's own root, the node that lays out label, input and error — not the wrapper, which carries only the data-fs-client-profile-fieldset-field=\\\"phone\\\" styling hook. A store that does not want a phone field omits this element from the page: requirement only governs required validation, never visibility.\",\n});\n\nexport const ClientProfileDocumentControlDefinition = defineComponent<ClientProfileDocumentControlProps>({\n name: 'ClientProfileDocumentControl',\n importPath: '@vtex/faststore/components',\n component: ClientProfileDocumentControl,\n requiresContext: 'client-profile-fieldset',\n // Provides both names, same reasoning as ClientProfileFieldsetPhoneControlDefinition above: this\n // control composes DocumentField, whose DocumentFieldInput part requires 'document-field' — a page\n // composing ClientProfileDocumentControl > DocumentFieldInput would otherwise fail the build\n // (finding F1).\n providesContext: ['field', 'document-field'],\n editor: { label: 'Client Profile Document Control', category: 'identity' },\n schema: {\n // No default (Decision 1): absence means the platform's value, applied at render time by\n // the control itself, not baked into the schema.\n label: { type: 'string', label: 'Label' },\n placeholder: { type: 'string', label: 'Placeholder' },\n errorMessage: { type: 'string', label: 'Error message' },\n },\n guideline:\n \"The bound tax-document control; must be a descendant of ClientProfileFieldset. Renders nothing, and registers no field name, when the fieldset's documentType is unsupported. Composes the DocumentField particle: recomposable (RFC:503) — given children, they replace DocumentField's default Field.Label + DocumentFieldInput + Field.Error anatomy, in any order; childless keeps today's order.\",\n});\n\n// ---------------------------------------------------------------------------\n// Fieldset root\n// ---------------------------------------------------------------------------\n\n/**\n * Registers a batched write of the `ClientProfile` entity with the enclosing `FormRoot`\n * (`registerFieldset`, namespace `clientProfile`) on mount, unconditionally — so this fieldset keeps its\n * original dispatch slot even while its own query is still resolving. Its children — the seed values and\n * the field-name registry its controls need — render only once the entity has resolved; until then the\n * `Fieldset.Root` carries `-pending` and renders `ClientProfileFieldsetSkeleton` (Decision 5).\n * `dispatch` and `toPayload` are `useCallback([])`-stable and read `$actions`/`country`/`documentType`\n * through a ref, so the registration effect runs exactly once per mount regardless of how often the\n * parent re-renders.\n *\n * \"Resolved\" is two conditions, because `$data` alone cannot answer it. Under the reactive runtime the\n * slice is defined from the first render — `useReactiveEntity` hands down `fallbackData` while the cache\n * read is incomplete — so an empty server answer looks exactly like a resolved one, and the controls\n * would mount and seed `''` before the shopper's real profile arrives. `useSeedAdoption` re-seeds a\n * clean field with `defaultValue` on every render, but once the field turns dirty no later seed\n * ever reaches it again: a shopper who starts typing before the real profile arrives locks that\n * empty seed in for good, and even a shopper who does not type sees the field flash from `''` to\n * the real data. `useReactiveDataSettled` supplies the missing half: the page query's own\n * in-flight state, latched so it only ever goes pending → settled. The `$data === undefined` half still\n * carries 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 polite\n * live region that announces the `loadingLabel` and then the `loadedLabel` message. Style the region `sr-only` — it is\n * text meant for a screen reader, not for the page.\n */\nexport function ClientProfileFieldset({\n country = 'US',\n documentType,\n skeletonCount = CLIENT_PROFILE_SKELETON_ROWS,\n $content,\n $locale,\n className,\n children,\n $data: $dataProp,\n $actions: $actionsProp,\n}: ClientProfileFieldsetProps) {\n // Nesting fieldsets has no legitimate use: useFieldsetField resolves the *nearest*\n // FieldsetFieldContext, not the one owning a control's actual namespace, so a control nested two\n // fieldsets deep would silently register under the wrong one and its write would be discarded on\n // submit. Runtime registry integrity, mirroring the namespace-collision throw FormRoot already ships\n // (form.tsx:280-288).\n useNoAncestorFieldset('ClientProfileFieldset');\n\n const $data = useDataOverride($dataProp);\n\n const $actions = useActionsOverride($actionsProp);\n const messages = useMessageFormatter(ClientProfileFieldsetContent, $content);\n const { format } = messages;\n const groupLabel = format('groupLabel');\n // Three conditions, not two. `useReactiveDataSettled` latches one way and never re-arms, so on its\n // own it answers \"has this page ever resolved\", not \"is what I am holding right now the server's\n // answer\" — after the page query's entity ref moves to one this cache never stored, or its root is\n // skipped for want of a variable, the slice silently regresses to `fallbackData` while the latch\n // still reads settled. `useEntityDataResolved` is the per-entity half: unlatched, so it follows the\n // slice back down and returns this fieldset to its skeleton instead of leaving live controls seeded\n // from a placeholder.\n const settled = useReactiveDataSettled();\n const sliceResolved = useEntityDataResolved();\n const resolved = settled && sliceResolved && $data !== undefined;\n // Also enforces the SessionRoot ancestor: useSession() throws when rendered outside one.\n const { canEditData } = useSession();\n const readOnly = !canEditData;\n\n // Runs before useFormContext() below: useFormRegistry() throws the friendly \"Form parts must be used\n // inside FormRoot.\" error when no FormRoot is above, so a FormRoot-less render fails there rather than\n // reaching the getFieldState destructure, which throws an unhelpful TypeError instead (useFormContext()\n // resolves to null outside a FormRoot, and destructuring null throws).\n const { registerFieldset } = useFormRegistry();\n\n // Decision 3, as later narrowed: this fieldset still reads dirtiness imperatively, but the rule is no\n // longer the form's. `FormRoot` subscribes `dirtyFields` in render and decides which fieldsets to\n // dispatch from it, by the fields each one has mounted, on react-hook-form's documented contract.\n //\n // The imperative read survives here because it asks a different question in a different place: which\n // of *this* fieldset's own fields changed, resolved inside `toPayload` at submit time, by full\n // registered field name — the shape `getFieldState` documents. `useFormContext()` adds no\n // `formState` subscription of its own; one is created only when a caller reads a formState key off\n // the `useForm`/`useFormState` proxy (or hands that already-subscribed object to `getFieldState`'s\n // second argument). Calling `getFieldState(name)` with no second argument reads the current internal\n // state directly, so this fieldset root still does not re-render on a keystroke.\n const { getFieldState } = useFormContext();\n\n const latest = useRef({ $actions, country, documentType, readOnly, getFieldState, messages });\n useEffect(() => {\n latest.current = { $actions, country, documentType, readOnly, getFieldState, messages };\n }, [$actions, country, documentType, readOnly, getFieldState, messages]);\n\n const { registry: fieldsetRegistry, getFieldNames } = useFieldsetFieldNames('clientProfile');\n\n const dispatch = useCallback(async (payload: Record<string, unknown>) => {\n // Defence-in-depth: the UI disables every input while read-only, but `FormClear` sets values (and\n // marks them dirty) on every registered field regardless of that disabled attribute — react-hook-\n // form's own `useController` calls never receive a `disabled` registration option, so it has no\n // notion of \"disabled\" of its own. Guarding here keeps the write from reaching the network even if\n // some other composition dirties this fieldset while canEditData is false (the server also refuses,\n // but a client-side guard should not depend on that).\n if (latest.current.readOnly) {\n throw new Error('ClientProfileFieldset cannot dispatch while the session is read-only.');\n }\n const update = latest.current.$actions?.identity?.clientProfileUpdate;\n // Throwing is the contract's failure path: FormRoot catches it and records this fieldset's failure\n // (form.tsx:264-266). Returning [] would report an unqualified success for a write that never\n // happened.\n if (!update) throw new Error('ClientProfileFieldset requires $actions.identity.clientProfileUpdate.');\n const userErrors = await update(payload as ClientProfileUpdateInput);\n return userErrors.map((error) => wordClientProfileError(error, latest.current.messages));\n }, []);\n\n const toPayload = useCallback((values: Record<string, unknown>): Record<string, unknown> => {\n const { country: activeCountry, documentType: activeDocumentType, getFieldState } = latest.current;\n // FR-5: a key is emitted only when the shopper actually changed it — presence in `values` alone\n // (every registered field is always present) is not enough. `dirtyFields` is not read directly;\n // `getFieldState` is called with no second argument, which reads react-hook-form's current\n // internal state without subscribing to it (Decision 3).\n const isDirty = (key: ProfileFieldKey) => getFieldState(`clientProfile.${key}`).isDirty;\n const payload: Record<string, string> = {};\n if ('firstName' in values && isDirty('firstName')) payload.firstName = String(values.firstName ?? '').trim();\n if ('lastName' in values && isDirty('lastName')) payload.lastName = String(values.lastName ?? '').trim();\n if ('phone' in values && isDirty('phone')) {\n const raw = String(values.phone ?? '').trim();\n // toE164 on a blank value returns the bare country code, which would write \"+55\" over the\n // shopper's number and fail every later save.\n payload.phone = raw ? toE164(raw, activeCountry) : '';\n }\n // The type's own sanitiser (digits for CPF, SSN and SIN, letters kept for RFC). Omitted when the type is\n // not supported: a value for a control that is no longer shown is never sent.\n if ('document' in values && isDirty('document') && isSupportedDocumentType(activeDocumentType)) {\n // The control only ever writes a string (the masked input's own value); `values` is typed `unknown`\n // because the fieldset contract carries every field's value, so it is narrowed here, not stringified.\n const rawDocument = typeof values.document === 'string' ? values.document : '';\n payload.document = DOCUMENTS[activeDocumentType].sanitize(rawDocument);\n }\n return payload;\n }, []);\n\n useEffect(\n () =>\n registerFieldset({\n namespace: 'clientProfile',\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` (`clientProfile` → `client-profile`) — not authored per\n // page (Decision 2).\n label: 'client-profile',\n }),\n [registerFieldset, getFieldNames, dispatch, toPayload],\n );\n\n const saved = useMemo<Readonly<Record<ProfileFieldKey, string>>>(\n () => ({\n firstName: $data?.firstName ?? '',\n lastName: $data?.lastName ?? '',\n phone: $data?.phone ?? '',\n document: $data?.document ?? '',\n }),\n [$data],\n );\n\n const contextValue = useMemo<ClientProfileFieldsetContextValue>(\n () => ({ namespace: 'clientProfile', saved, readOnly, country, documentType, rules: NO_RULES }),\n [saved, readOnly, country, documentType],\n );\n\n // Assistive technology only reports a change inside a region that was already in the tree, so a\n // region mounted together with its text announces nothing. The region therefore sits in both\n // branches and starts empty, with the wait written on the pass after mount and replaced — not\n // cleared — once the controls are up: the skeleton is `aria-hidden`, so without this second\n // message the form would materialise in silence (WCAG 2.1 SC 4.1.3).\n const [announcement, setAnnouncement] = useState('');\n const announced = format(resolved ? 'loadedLabel' : 'loadingLabel');\n useEffect(() => {\n setAnnouncement(announced);\n }, [announced]);\n\n return (\n <Fieldset.Root\n className={className}\n disabled={readOnly}\n aria-busy={resolved ? undefined : true}\n // FR-12: a missing message means no name is exposed. On the root itself (FR-13), so it is identical whether the fieldset\n // is pending or resolved; a page-composed FieldsetLegend still wins via aria-labelledby.\n {...(groupLabel.trim() ? { 'aria-label': groupLabel } : {})}\n data-fs-client-profile-fieldset=\"\"\n {...(resolved ? {} : { 'data-fs-client-profile-fieldset-pending': '' })}\n {...(readOnly ? { 'data-fs-client-profile-fieldset-readonly': '' } : {})}\n >\n {resolved ? (\n <FieldsetFieldContext.Provider value={fieldsetRegistry}>\n <ClientProfileFieldsetContext.Provider value={contextValue}>{children}</ClientProfileFieldsetContext.Provider>\n </FieldsetFieldContext.Provider>\n ) : (\n <ClientProfileFieldsetSkeleton count={skeletonCount} />\n )}\n <output aria-live=\"polite\" data-fs-client-profile-fieldset-announcement=\"\">\n {announcement}\n </output>\n </Fieldset.Root>\n );\n}\n\n/**\n * The loading state of the fieldset, rendered in place of the controls until the entity resolves and\n * declared as the definition's `skeleton`. Purely visual: the wait is spoken by the fieldset's own live\n * region, so this is hidden from assistive technology rather than announced twice.\n */\nexport function ClientProfileFieldsetSkeleton({\n count = CLIENT_PROFILE_SKELETON_ROWS,\n className,\n ...props\n}: ComponentPropsWithRef<'div'> & { count?: number }) {\n return (\n <div {...props} className={className} data-fs-client-profile-fieldset-skeleton=\"\" aria-hidden=\"true\">\n {Array.from({ length: count }, (_, i) => (\n <span key={i} data-fs-client-profile-fieldset-skeleton-field=\"\" />\n ))}\n </div>\n );\n}\n\nClientProfileFieldset.Skeleton = ClientProfileFieldsetSkeleton;\n\n// ---------------------------------------------------------------------------\n// Text controls — first name, last name\n// ---------------------------------------------------------------------------\n\nfunction ProfileTextControl({\n fieldKey,\n attr,\n autoComplete,\n label,\n placeholder,\n className,\n children,\n}: Readonly<{\n fieldKey: 'firstName' | 'lastName';\n attr: string;\n autoComplete: string;\n /** Formatted by the owning control. */\n label: string;\n placeholder?: string;\n className?: string;\n children?: ReactNode;\n}>) {\n const { namespace, saved, readOnly, rules } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, fieldKey);\n\n return (\n <FieldBinding\n name={name}\n label={label}\n placeholder={placeholder}\n defaultValue={saved[fieldKey]}\n rule={rules[fieldKey]}\n disabled={readOnly}\n autoComplete={autoComplete}\n >\n <Field.Root className={className} data-fs-client-profile-fieldset-field={attr}>\n {children ?? (\n <>\n <Field.Label />\n <Field.Control />\n <Field.Error />\n </>\n )}\n </Field.Root>\n </FieldBinding>\n );\n}\n\nexport function ClientProfileFirstNameControl({\n placeholder,\n $content,\n $locale,\n className,\n children,\n}: ClientProfileFirstNameControlProps) {\n const { format } = useMessageFormatter(ClientProfileFirstNameControlContent, $content);\n return (\n <ProfileTextControl\n fieldKey=\"firstName\"\n attr=\"first-name\"\n autoComplete=\"given-name\"\n label={format('label')}\n placeholder={placeholder}\n className={className}\n >\n {children}\n </ProfileTextControl>\n );\n}\n\nexport function ClientProfileLastNameControl({\n placeholder,\n $content,\n $locale,\n className,\n children,\n}: ClientProfileLastNameControlProps) {\n const { format } = useMessageFormatter(ClientProfileLastNameControlContent, $content);\n return (\n <ProfileTextControl\n fieldKey=\"lastName\"\n attr=\"last-name\"\n autoComplete=\"family-name\"\n label={format('label')}\n placeholder={placeholder}\n className={className}\n >\n {children}\n </ProfileTextControl>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Phone control — the fieldset-bound counterpart of ClientProfilePhoneControl\n// ---------------------------------------------------------------------------\n\n/**\n * Composes `PhoneField` inside a `FieldBinding`, wrapped in a `data-fs-client-profile-fieldset-field=\"phone\"`\n * node — the same styling hook attribute the text controls carry on their own `Field.Root`.\n * `useFieldsetField` runs unconditionally, before `requirement` is even read — there is no suppressed\n * state for this control to second-guess; `requirement` only ever raises the field to required,\n * and left unset it raises nothing.\n */\nexport function ClientProfileFieldsetPhoneControl({\n placeholder,\n requirement,\n $content,\n $locale,\n className,\n children,\n}: ClientProfileFieldsetPhoneControlProps) {\n const { namespace, saved, readOnly, rules, country } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, 'phone');\n const { format } = useMessageFormatter(ClientProfileFieldsetPhoneControlContent, $content);\n\n const binding = (\n <FieldBinding\n name={name}\n label={format('label')}\n placeholder={placeholder}\n defaultValue={saved.phone}\n rule={rules.phone}\n disabled={readOnly}\n >\n <PhoneField\n country={country}\n requirement={requirement}\n errorInvalid={format('errorInvalid')}\n errorRequired={format('errorRequired')}\n className={className}\n >\n {children}\n </PhoneField>\n </FieldBinding>\n );\n\n // The wrapper carries no className of its own (Decision 1): className lands on PhoneField's own\n // Field.Root, the node that actually stacks label, input and error, so it needs no flex slot here.\n return <div data-fs-client-profile-fieldset-field=\"phone\">{binding}</div>;\n}\n\n// ---------------------------------------------------------------------------\n// Document control — self-gates on documentType, through an inner component\n// ---------------------------------------------------------------------------\n\ntype ClientProfileDocumentControlInnerProps = ClientProfileDocumentControlProps & { documentType: DocumentType };\n\n/**\n * `useFieldsetField` (through `useClientProfileFieldsetContext`'s namespace) lives only in this inner\n * component, mounted only once `ClientProfileDocumentControl` has already decided the document type is\n * supported. Splitting the decision from the registration this way (Decision 8) keeps a control that\n * renders nothing from registering a field name `FormClear` would otherwise dirty and dispatch.\n */\nfunction ClientProfileDocumentControlInner({\n documentType,\n label,\n placeholder,\n errorMessage,\n className,\n children,\n}: ClientProfileDocumentControlInnerProps) {\n const { namespace, saved, readOnly, rules } = useClientProfileFieldsetContext();\n const name = useFieldsetField(namespace, 'document');\n\n return (\n <FieldBinding\n name={name}\n label={label ?? DOCUMENTS[documentType].name}\n placeholder={placeholder}\n defaultValue={saved.document}\n rule={rules.document}\n disabled={readOnly}\n >\n <DocumentField\n documentType={documentType}\n errorMessage={errorMessage}\n className={className}\n data-fs-client-profile-fieldset-field=\"document\"\n >\n {children}\n </DocumentField>\n </FieldBinding>\n );\n}\n\nexport function ClientProfileDocumentControl({\n label,\n placeholder,\n errorMessage,\n className,\n children,\n}: ClientProfileDocumentControlProps) {\n const { documentType } = useClientProfileFieldsetContext();\n if (!isSupportedDocumentType(documentType)) return null;\n\n return (\n <ClientProfileDocumentControlInner\n documentType={documentType}\n label={label}\n placeholder={placeholder}\n errorMessage={errorMessage}\n className={className}\n >\n {children}\n </ClientProfileDocumentControlInner>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ContentValue, MessageLocaleProp } from "../../core/dist/define-content-type.js";
|
|
1
2
|
import { ComponentDefinition } from "../../core/dist/define-component.js";
|
|
2
3
|
import "../../core/dist/index.js";
|
|
3
4
|
import { ShippingOption } from "../shipping-simulator/shipping-simulator.js";
|
|
@@ -5,11 +6,9 @@ import { ComponentActions } from "../../sdk/actions/types.js";
|
|
|
5
6
|
import { RawDeliveryOptionsData } from "./use-delivery-option-selection.js";
|
|
6
7
|
import { ComponentPropsWithRef } from "react";
|
|
7
8
|
//#region src/matter/delivery-options/delivery-options-accordion.d.ts
|
|
8
|
-
export type DeliveryOptionsAccordionProps = ComponentPropsWithRef<'button'> & {
|
|
9
|
+
export type DeliveryOptionsAccordionProps = ComponentPropsWithRef<'button'> & MessageLocaleProp & {
|
|
9
10
|
/** Optional prefix shown before the summary value on the trigger row (e.g. "Forma de entrega"). */
|
|
10
11
|
label?: string;
|
|
11
|
-
/** Text shown on the trigger row while nothing is selected. */
|
|
12
|
-
placeholder?: string;
|
|
13
12
|
/** Separator between the selected option name and price on the trigger row. */
|
|
14
13
|
separator?: string;
|
|
15
14
|
/** Disclosure icon shown on the trigger. The compiler's per-route sprite is built from explicit
|
|
@@ -23,8 +22,54 @@ export type DeliveryOptionsAccordionProps = ComponentPropsWithRef<'button'> & {
|
|
|
23
22
|
$actions?: ComponentActions;
|
|
24
23
|
/** Local/dev fallback rows, used only when the reactive fetch resolves no options. */
|
|
25
24
|
mockOptions?: ShippingOption[];
|
|
25
|
+
/** The placeholder, the text that replaces a zero price, and the selection error messages. */
|
|
26
|
+
$content?: ContentValue<typeof DeliveryOptionsAccordionContent>;
|
|
27
|
+
};
|
|
28
|
+
export declare const DeliveryOptionsAccordionContent: {
|
|
29
|
+
readonly id: "delivery-options-accordion";
|
|
30
|
+
readonly title: "Delivery Options Accordion";
|
|
31
|
+
readonly description: "Text shown on the trigger while nothing is selected, instead of a zero price for the selected option, and when a selection is refused.";
|
|
32
|
+
readonly schema: {
|
|
33
|
+
readonly type: "object";
|
|
34
|
+
readonly additionalProperties: false;
|
|
35
|
+
readonly properties: {
|
|
36
|
+
readonly placeholder: {
|
|
37
|
+
readonly type: "string";
|
|
38
|
+
readonly title: "Placeholder";
|
|
39
|
+
readonly format: "icu-message";
|
|
40
|
+
readonly messageSource: "Select a delivery option";
|
|
41
|
+
};
|
|
42
|
+
readonly freeLabel: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
readonly title: "Free price label";
|
|
45
|
+
readonly format: "icu-message";
|
|
46
|
+
readonly messageSource: "Free";
|
|
47
|
+
};
|
|
48
|
+
readonly optionUnavailableMessage: {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
readonly title: "Option unavailable message";
|
|
51
|
+
readonly description: "Shown when the picked option is no longer offered for the cart.";
|
|
52
|
+
readonly format: "icu-message";
|
|
53
|
+
readonly messageSource: "This delivery option is no longer available. Choose another one.";
|
|
54
|
+
};
|
|
55
|
+
readonly missingAddressMessage: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
readonly title: "Missing address message";
|
|
58
|
+
readonly description: "Shown when no delivery address is saved on the cart yet.";
|
|
59
|
+
readonly format: "icu-message";
|
|
60
|
+
readonly messageSource: "Enter a delivery address before choosing a delivery option.";
|
|
61
|
+
};
|
|
62
|
+
readonly genericErrorMessage: {
|
|
63
|
+
readonly type: "string";
|
|
64
|
+
readonly title: "Generic failure message";
|
|
65
|
+
readonly description: "Shown for a network failure and for every refusal the shopper cannot act on.";
|
|
66
|
+
readonly format: "icu-message";
|
|
67
|
+
readonly messageSource: "Unable to update the delivery option. Please try again.";
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
};
|
|
26
71
|
};
|
|
27
72
|
export declare const DeliveryOptionsAccordionDefinition: ComponentDefinition<DeliveryOptionsAccordionProps>;
|
|
28
|
-
export declare function DeliveryOptionsAccordion({
|
|
73
|
+
export declare function DeliveryOptionsAccordion({ $content, $locale, label, separator, icon, panelClassName, $data, $actions: $actionsProp, mockOptions, className, children, ...props }: DeliveryOptionsAccordionProps): import("react/jsx-runtime").JSX.Element;
|
|
29
74
|
//#endregion
|
|
30
75
|
//# sourceMappingURL=delivery-options-accordion.d.ts.map
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { defineComponent } from "../../core/dist/define-component.js";
|
|
3
|
+
import { defineContentType } from "../../core/dist/define-content-type.js";
|
|
3
4
|
import "../../core/dist/index.js";
|
|
5
|
+
import { useMessageFormatter } from "../../sdk/i18n/use-message-formatter.js";
|
|
4
6
|
import { useActionsOverride } from "../../sdk/actions/actions-override-context.js";
|
|
7
|
+
import { formatErrorCode } from "../../sdk/i18n/format-error-code.js";
|
|
5
8
|
import { Icon } from "../../particles/icon/icon.js";
|
|
6
9
|
import { RadioGroup, RadioRoot } from "../../particles/radio/radio.js";
|
|
7
|
-
import { OptionItemContext, ShippingSimulatorContext, ShippingSimulatorOptionName, ShippingSimulatorOptionPrice } from "../shipping-simulator/shipping-simulator.js";
|
|
10
|
+
import { OptionItemContext, ShippingSimulatorContext, ShippingSimulatorOptionName, ShippingSimulatorOptionPrice, isFreeAmount } from "../shipping-simulator/shipping-simulator.js";
|
|
8
11
|
import { useDeliveryOptionSelection } from "./use-delivery-option-selection.js";
|
|
9
12
|
import { AccordionHeader, AccordionItem, AccordionPanel, AccordionRoot, AccordionTrigger } from "../../particles/accordion/accordion.js";
|
|
10
13
|
import { useState } from "react";
|
|
@@ -61,10 +64,63 @@ const fragment = `
|
|
|
61
64
|
`;
|
|
62
65
|
const ACCORDION_ITEM_VALUE = "delivery-options";
|
|
63
66
|
const DEFAULT_PANEL_CLASS = "overflow-hidden transition-[height] duration-200 ease-out h-[var(--accordion-panel-height)] data-starting-style:h-0 data-ending-style:h-0";
|
|
67
|
+
const DeliveryOptionsAccordionContent = defineContentType({
|
|
68
|
+
id: "delivery-options-accordion",
|
|
69
|
+
title: "Delivery Options Accordion",
|
|
70
|
+
description: "Text shown on the trigger while nothing is selected, instead of a zero price for the selected option, and when a selection is refused.",
|
|
71
|
+
schema: {
|
|
72
|
+
type: "object",
|
|
73
|
+
additionalProperties: false,
|
|
74
|
+
properties: {
|
|
75
|
+
placeholder: {
|
|
76
|
+
type: "string",
|
|
77
|
+
title: "Placeholder",
|
|
78
|
+
format: "icu-message",
|
|
79
|
+
messageSource: "Select a delivery option"
|
|
80
|
+
},
|
|
81
|
+
freeLabel: {
|
|
82
|
+
type: "string",
|
|
83
|
+
title: "Free price label",
|
|
84
|
+
format: "icu-message",
|
|
85
|
+
messageSource: "Free"
|
|
86
|
+
},
|
|
87
|
+
optionUnavailableMessage: {
|
|
88
|
+
type: "string",
|
|
89
|
+
title: "Option unavailable message",
|
|
90
|
+
description: "Shown when the picked option is no longer offered for the cart.",
|
|
91
|
+
format: "icu-message",
|
|
92
|
+
messageSource: "This delivery option is no longer available. Choose another one."
|
|
93
|
+
},
|
|
94
|
+
missingAddressMessage: {
|
|
95
|
+
type: "string",
|
|
96
|
+
title: "Missing address message",
|
|
97
|
+
description: "Shown when no delivery address is saved on the cart yet.",
|
|
98
|
+
format: "icu-message",
|
|
99
|
+
messageSource: "Enter a delivery address before choosing a delivery option."
|
|
100
|
+
},
|
|
101
|
+
genericErrorMessage: {
|
|
102
|
+
type: "string",
|
|
103
|
+
title: "Generic failure message",
|
|
104
|
+
description: "Shown for a network failure and for every refusal the shopper cannot act on.",
|
|
105
|
+
format: "icu-message",
|
|
106
|
+
messageSource: "Unable to update the delivery option. Please try again."
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
/** The message for each code a selection can resolve. A code this map does not know shows genericErrorMessage. */
|
|
112
|
+
const DELIVERY_OPTIONS_ACCORDION_ERROR_FIELDS = {
|
|
113
|
+
OPTION_UNAVAILABLE: "optionUnavailableMessage",
|
|
114
|
+
MISSING_SHIPPING_ADDRESS: "missingAddressMessage",
|
|
115
|
+
MISSING_CART_CONTEXT: "genericErrorMessage",
|
|
116
|
+
CART_NOT_FOUND: "genericErrorMessage",
|
|
117
|
+
NETWORK_ERROR: "genericErrorMessage"
|
|
118
|
+
};
|
|
64
119
|
const DeliveryOptionsAccordionDefinition = defineComponent({
|
|
65
120
|
name: "DeliveryOptionsAccordion",
|
|
66
121
|
importPath: "@vtex/faststore/components",
|
|
67
122
|
component: DeliveryOptionsAccordion,
|
|
123
|
+
content: DeliveryOptionsAccordionContent,
|
|
68
124
|
fragment,
|
|
69
125
|
fetchStrategy: "reactive",
|
|
70
126
|
actions: { shipping: ["selectOption"] },
|
|
@@ -77,11 +133,6 @@ const DeliveryOptionsAccordionDefinition = defineComponent({
|
|
|
77
133
|
type: "string",
|
|
78
134
|
label: "Trigger label prefix"
|
|
79
135
|
},
|
|
80
|
-
placeholder: {
|
|
81
|
-
type: "string",
|
|
82
|
-
default: "Selecionar forma de entrega",
|
|
83
|
-
label: "Placeholder"
|
|
84
|
-
},
|
|
85
136
|
separator: {
|
|
86
137
|
type: "string",
|
|
87
138
|
default: " — ",
|
|
@@ -98,9 +149,9 @@ const DeliveryOptionsAccordionDefinition = defineComponent({
|
|
|
98
149
|
}
|
|
99
150
|
},
|
|
100
151
|
providesContext: ["shipping-simulator", "shipping-simulator-option"],
|
|
101
|
-
guideline: "Collapsed delivery-option picker: a single summary row that expands the whole-cart option list inline (an accordion, not an overlay) and collapses it the moment a row is picked, echoing the choice (name + price) back on the trigger or
|
|
152
|
+
guideline: "Collapsed delivery-option picker: a single summary row that expands the whole-cart option list inline (an accordion, not an overlay) and collapses it the moment a row is picked, echoing the choice (name + price) back on the trigger or its $content.placeholder when nothing is selected; its $content.freeLabel replaces a zero price in that echo. Reuses the FSPG-832 option leaves (ShippingSimulatorOption, OptionName, OptionEstimate, OptionPrice, OptionFreeBadge) as the per-option template placed as children, exactly like DeliveryOptionsRoot. Selecting a row dispatches $actions.shipping.selectOption; a refusal shows inline, worded by its code from its $content (genericErrorMessage for a network failure, every refusal the shopper cannot act on, and an unknown code). mockOptions is a local/dev-only fallback whose selection stays local. Use instead of a DeliveryOptionsController overlay (Dialog/Drawer) when the picker should expand in the page flow rather than surface in an overlay."
|
|
102
153
|
});
|
|
103
|
-
function DeliveryOptionsAccordion({
|
|
154
|
+
function DeliveryOptionsAccordion({ $content, $locale, label, separator = " — ", icon = "caret-down", panelClassName = DEFAULT_PANEL_CLASS, $data, $actions: $actionsProp, mockOptions, className, children, ...props }) {
|
|
104
155
|
const $actions = useActionsOverride($actionsProp);
|
|
105
156
|
const { options, selectedOptionId, selectionError, selectOption, contextValue } = useDeliveryOptionSelection({
|
|
106
157
|
$data,
|
|
@@ -108,7 +159,9 @@ function DeliveryOptionsAccordion({ label, placeholder = "Selecionar forma de en
|
|
|
108
159
|
mockOptions
|
|
109
160
|
});
|
|
110
161
|
const [open, setOpen] = useState(false);
|
|
162
|
+
const { format } = useMessageFormatter(DeliveryOptionsAccordionContent, $content);
|
|
111
163
|
const selectedOption = options.find((option) => option.id === selectedOptionId) ?? null;
|
|
164
|
+
const errorMessage = selectionError ? formatErrorCode(DeliveryOptionsAccordionContent, DELIVERY_OPTIONS_ACCORDION_ERROR_FIELDS, selectionError, format, "genericErrorMessage") : null;
|
|
112
165
|
function handleValueChange(optionId) {
|
|
113
166
|
selectOption(optionId, { onSettled: (ok) => {
|
|
114
167
|
if (ok) setOpen(false);
|
|
@@ -144,12 +197,12 @@ function DeliveryOptionsAccordion({ label, placeholder = "Selecionar forma de en
|
|
|
144
197
|
"data-fs-delivery-options-accordion-separator": "",
|
|
145
198
|
children: separator
|
|
146
199
|
}),
|
|
147
|
-
/* @__PURE__ */ jsx(ShippingSimulatorOptionPrice, {})
|
|
200
|
+
/* @__PURE__ */ jsx(ShippingSimulatorOptionPrice, { children: isFreeAmount(selectedOption.price.amount) ? format("freeLabel") : void 0 })
|
|
148
201
|
]
|
|
149
202
|
})
|
|
150
203
|
}) : /* @__PURE__ */ jsx("span", {
|
|
151
204
|
"data-fs-delivery-options-accordion-placeholder": "",
|
|
152
|
-
children: placeholder
|
|
205
|
+
children: format("placeholder")
|
|
153
206
|
}),
|
|
154
207
|
/* @__PURE__ */ jsx("span", {
|
|
155
208
|
"data-fs-delivery-options-accordion-icon": "",
|
|
@@ -163,11 +216,11 @@ function DeliveryOptionsAccordion({ label, placeholder = "Selecionar forma de en
|
|
|
163
216
|
children: /* @__PURE__ */ jsxs("div", {
|
|
164
217
|
"data-fs-delivery-options": "",
|
|
165
218
|
className: "pt-3",
|
|
166
|
-
children: [
|
|
219
|
+
children: [errorMessage === null ? null : /* @__PURE__ */ jsx("div", {
|
|
167
220
|
role: "alert",
|
|
168
221
|
"data-fs-delivery-options-error": "",
|
|
169
|
-
children:
|
|
170
|
-
})
|
|
222
|
+
children: errorMessage
|
|
223
|
+
}), options.length > 0 ? /* @__PURE__ */ jsx(RadioGroup, {
|
|
171
224
|
value: selectedOptionId ?? "",
|
|
172
225
|
onValueChange: handleValueChange,
|
|
173
226
|
className: "flex flex-col gap-3",
|
|
@@ -186,6 +239,6 @@ function DeliveryOptionsAccordion({ label, placeholder = "Selecionar forma de en
|
|
|
186
239
|
});
|
|
187
240
|
}
|
|
188
241
|
//#endregion
|
|
189
|
-
export { DeliveryOptionsAccordion, DeliveryOptionsAccordionDefinition };
|
|
242
|
+
export { DELIVERY_OPTIONS_ACCORDION_ERROR_FIELDS, DeliveryOptionsAccordion, DeliveryOptionsAccordionContent, DeliveryOptionsAccordionDefinition };
|
|
190
243
|
|
|
191
244
|
//# sourceMappingURL=delivery-options-accordion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery-options-accordion.js","names":[],"sources":["../../../src/matter/delivery-options/delivery-options-accordion.tsx"],"sourcesContent":["'use client';\n\nimport { defineComponent } from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { useState } from 'react';\nimport {\n AccordionHeader,\n AccordionItem,\n AccordionPanel,\n AccordionRoot,\n AccordionTrigger,\n} from '../../particles/accordion/accordion.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { RadioGroup, RadioRoot } from '../../particles/radio/radio.js';\nimport { useActionsOverride } from '../../sdk/actions/actions-override-context.js';\nimport type { ComponentActions } from '../../sdk/actions/types.js';\nimport {\n OptionItemContext,\n type ShippingOption,\n ShippingSimulatorContext,\n ShippingSimulatorOptionName,\n ShippingSimulatorOptionPrice,\n} from '../shipping-simulator/shipping-simulator.js';\nimport { type RawDeliveryOptionsData, useDeliveryOptionSelection } from './use-delivery-option-selection.js';\n\n/**\n * `DeliveryOptionsAccordion` presents the whole-cart delivery-option list as a single summary/trigger\n * row that expands the full list inline, then collapses it once an option is picked and the selection\n * succeeds — with the trigger reflecting the chosen option's name + price (or a placeholder when\n * nothing is selected yet).\n * It is the inline (non-overlay) sibling of the `DeliveryOptionsController` Dialog/Drawer surfaces:\n * same fragment, `$data` shape, selection rule, and reuse of the FSPG-832 option leaves as the per-option\n * template placed as `children`, but the option list expands/collapses in the normal page flow\n * directly below the trigger instead of surfacing in an overlay — no Portal, no Backdrop, no\n * fixed/z-index positioning.\n *\n * The Accordion particle differs from Drawer/Dialog in the control surface this component adapts to:\n * it has no `open`/`onOpenChange` boolean; Base UI models disclosure as a controlled *array* of open\n * item values (`value` + `onValueChange`), so a single-open accordion is `[]` (collapsed) or\n * `[ACCORDION_ITEM_VALUE]` (expanded). There is no overlay chrome (title bar, close button, swipe\n * edge), so those props are dropped; the panel collapse is a height animation rather than a slide.\n *\n * It owns the expand/collapse state and the selection→collapse coordination internally (neither is\n * expressible by composing `Accordion` + `DeliveryOptionsRoot` in a schema), and shares the selection\n * engine with `DeliveryOptionsRoot` via `useDeliveryOptionSelection`. Real options dispatch\n * `$actions.shipping.selectOption` and the panel collapses only once the mutation resolves without a\n * `userError` — a rejected option keeps the panel open with an inline `role=\"alert\"` (US-4);\n * `mockOptions` update local state only and collapse immediately.\n */\n\nconst fragment = /* GraphQL */ `\n fragment DeliveryOptionsAccordionData on Query {\n shipping {\n id\n options {\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n }\n`;\n\n// Stable value identifying the single accordion item; the controlled open state is `[]` (collapsed)\n// or `[ACCORDION_ITEM_VALUE]` (expanded).\nconst ACCORDION_ITEM_VALUE = 'delivery-options';\n\n// Base UI drives the collapse with the `--accordion-panel-height` CSS var it sets on the panel, so\n// the list expands/collapses in flow with a height transition (overflow-hidden clips it mid-animation).\nconst DEFAULT_PANEL_CLASS =\n 'overflow-hidden transition-[height] duration-200 ease-out h-[var(--accordion-panel-height)] data-starting-style:h-0 data-ending-style:h-0';\n\nexport type DeliveryOptionsAccordionProps = ComponentPropsWithRef<'button'> & {\n /** Optional prefix shown before the summary value on the trigger row (e.g. \"Forma de entrega\"). */\n label?: string;\n /** Text shown on the trigger row while nothing is selected. */\n placeholder?: string;\n /** Separator between the selected option name and price on the trigger row. */\n separator?: string;\n /** Disclosure icon shown on the trigger. The compiler's per-route sprite is built from explicit\n * `icon`-typed prop values in the schema, so a page must set this rather than rely on the default. */\n icon?: string;\n /** Overrides the default collapsible panel styling (height-animation + overflow clip). */\n panelClassName?: string;\n /** Shipping slice forwarded by the reactive runtime; `null` until shipping resolves. */\n $data?: RawDeliveryOptionsData | null;\n /** Compiler-injected action surface; carries `shipping.selectOption`. */\n $actions?: ComponentActions;\n /** Local/dev fallback rows, used only when the reactive fetch resolves no options. */\n mockOptions?: ShippingOption[];\n};\n\nexport const DeliveryOptionsAccordionDefinition = defineComponent<DeliveryOptionsAccordionProps>({\n name: 'DeliveryOptionsAccordion',\n importPath: '@vtex/faststore/components',\n component: DeliveryOptionsAccordion,\n fragment,\n fetchStrategy: 'reactive',\n actions: { shipping: ['selectOption'] },\n editor: { label: 'Delivery Options Accordion', category: 'commerce' },\n schema: {\n label: { type: 'string', label: 'Trigger label prefix' },\n placeholder: { type: 'string', default: 'Selecionar forma de entrega', label: 'Placeholder' },\n separator: { type: 'string', default: ' — ', label: 'Summary separator' },\n icon: { type: 'icon', default: 'caret-down', label: 'Disclosure icon' },\n mockOptions: { type: 'array', label: 'Mock options (local/dev fallback, ignored once real data has options)' },\n },\n // Re-provides the reused option leaves' runtime contexts (Decision 2): `shipping-simulator-option`\n // for the leaves composed as direct children here, plus the outer `shipping-simulator` this\n // accordion also provides at runtime.\n providesContext: ['shipping-simulator', 'shipping-simulator-option'],\n guideline:\n 'Collapsed delivery-option picker: a single summary row that expands the whole-cart option list inline (an accordion, not an overlay) and collapses it the moment a row is picked, echoing the choice (name + price) back on the trigger or a placeholder when nothing is selected. Reuses the FSPG-832 option leaves (ShippingSimulatorOption, OptionName, OptionEstimate, OptionPrice, OptionFreeBadge) as the per-option template placed as children, exactly like DeliveryOptionsRoot. Selecting a row dispatches $actions.shipping.selectOption; mockOptions is a local/dev-only fallback whose selection stays local. Use instead of a DeliveryOptionsController overlay (Dialog/Drawer) when the picker should expand in the page flow rather than surface in an overlay.',\n});\n\nexport function DeliveryOptionsAccordion({\n label,\n placeholder = 'Selecionar forma de entrega',\n separator = ' — ',\n icon = 'caret-down',\n panelClassName = DEFAULT_PANEL_CLASS,\n $data,\n $actions: $actionsProp,\n mockOptions,\n className,\n children,\n ...props\n}: DeliveryOptionsAccordionProps) {\n const $actions = useActionsOverride($actionsProp);\n const { options, selectedOptionId, selectionError, selectOption, contextValue } = useDeliveryOptionSelection({\n $data,\n $actions,\n mockOptions,\n });\n const [open, setOpen] = useState(false);\n const selectedOption = options.find((option) => option.id === selectedOptionId) ?? null;\n\n function handleValueChange(optionId: string) {\n selectOption(optionId, {\n onSettled: (ok) => {\n if (ok) setOpen(false);\n },\n });\n }\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <AccordionRoot\n openMultiple={false}\n value={open ? [ACCORDION_ITEM_VALUE] : []}\n onValueChange={(value) => setOpen(value.length > 0)}\n data-fs-delivery-options-accordion=\"\"\n >\n <AccordionItem value={ACCORDION_ITEM_VALUE}>\n <AccordionHeader className=\"m-0\">\n <AccordionTrigger {...props} className={className} data-fs-delivery-options-accordion-trigger=\"\">\n {label ? <span data-fs-delivery-options-accordion-label=\"\">{label}</span> : null}\n {selectedOption ? (\n <OptionItemContext value={selectedOption}>\n <span data-fs-delivery-options-accordion-value=\"\">\n <ShippingSimulatorOptionName />\n <span data-fs-delivery-options-accordion-separator=\"\">{separator}</span>\n <ShippingSimulatorOptionPrice />\n </span>\n </OptionItemContext>\n ) : (\n <span data-fs-delivery-options-accordion-placeholder=\"\">{placeholder}</span>\n )}\n <span data-fs-delivery-options-accordion-icon=\"\">\n <Icon name={icon} />\n </span>\n </AccordionTrigger>\n </AccordionHeader>\n <AccordionPanel className={panelClassName} data-fs-delivery-options-accordion-panel=\"\">\n <div data-fs-delivery-options=\"\" className=\"pt-3\">\n {selectionError ? (\n <div role=\"alert\" data-fs-delivery-options-error=\"\">\n {selectionError}\n </div>\n ) : null}\n {options.length > 0 ? (\n <RadioGroup\n value={selectedOptionId ?? ''}\n onValueChange={handleValueChange}\n className=\"flex flex-col gap-3\"\n >\n {options.map((option) => (\n <OptionItemContext key={option.id} value={option}>\n <RadioRoot value={option.id}>{children}</RadioRoot>\n </OptionItemContext>\n ))}\n </RadioGroup>\n ) : null}\n </div>\n </AccordionPanel>\n </AccordionItem>\n </AccordionRoot>\n </ShippingSimulatorContext>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"delivery-options-accordion.js","names":[],"sources":["../../../src/matter/delivery-options/delivery-options-accordion.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ContentValue,\n defineComponent,\n defineContentType,\n type MessageFieldName,\n type MessageLocaleProp,\n} from '@vtex/fs-core';\nimport type { ComponentPropsWithRef } from 'react';\nimport { useState } from 'react';\nimport {\n AccordionHeader,\n AccordionItem,\n AccordionPanel,\n AccordionRoot,\n AccordionTrigger,\n} from '../../particles/accordion/accordion.js';\nimport { Icon } from '../../particles/icon/icon.js';\nimport { RadioGroup, RadioRoot } from '../../particles/radio/radio.js';\nimport { useActionsOverride } from '../../sdk/actions/actions-override-context.js';\nimport type { ComponentActions } from '../../sdk/actions/types.js';\nimport { formatErrorCode } from '../../sdk/i18n/format-error-code.js';\nimport { useMessageFormatter } from '../../sdk/i18n/use-message-formatter.js';\nimport {\n isFreeAmount,\n OptionItemContext,\n type ShippingOption,\n ShippingSimulatorContext,\n ShippingSimulatorOptionName,\n ShippingSimulatorOptionPrice,\n} from '../shipping-simulator/shipping-simulator.js';\nimport {\n type DeliveryOptionSelectErrorCode,\n type RawDeliveryOptionsData,\n useDeliveryOptionSelection,\n} from './use-delivery-option-selection.js';\n\n/**\n * `DeliveryOptionsAccordion` presents the whole-cart delivery-option list as a single summary/trigger\n * row that expands the full list inline, then collapses it once an option is picked and the selection\n * succeeds — with the trigger reflecting the chosen option's name + price (or a placeholder when\n * nothing is selected yet).\n * It is the inline (non-overlay) sibling of the `DeliveryOptionsController` Dialog/Drawer surfaces:\n * same fragment, `$data` shape, selection rule, and reuse of the FSPG-832 option leaves as the per-option\n * template placed as `children`, but the option list expands/collapses in the normal page flow\n * directly below the trigger instead of surfacing in an overlay — no Portal, no Backdrop, no\n * fixed/z-index positioning.\n *\n * The Accordion particle differs from Drawer/Dialog in the control surface this component adapts to:\n * it has no `open`/`onOpenChange` boolean; Base UI models disclosure as a controlled *array* of open\n * item values (`value` + `onValueChange`), so a single-open accordion is `[]` (collapsed) or\n * `[ACCORDION_ITEM_VALUE]` (expanded). There is no overlay chrome (title bar, close button, swipe\n * edge), so those props are dropped; the panel collapse is a height animation rather than a slide.\n *\n * It owns the expand/collapse state and the selection→collapse coordination internally (neither is\n * expressible by composing `Accordion` + `DeliveryOptionsRoot` in a schema), and shares the selection\n * engine with `DeliveryOptionsRoot` via `useDeliveryOptionSelection`. Real options dispatch\n * `$actions.shipping.selectOption` and the panel collapses only once the mutation resolves without a\n * `userError` — a rejected option keeps the panel open with an inline `role=\"alert\"` (US-4);\n * `mockOptions` update local state only and collapse immediately.\n */\n\nconst fragment = /* GraphQL */ `\n fragment DeliveryOptionsAccordionData on Query {\n shipping {\n id\n options {\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n }\n`;\n\n// Stable value identifying the single accordion item; the controlled open state is `[]` (collapsed)\n// or `[ACCORDION_ITEM_VALUE]` (expanded).\nconst ACCORDION_ITEM_VALUE = 'delivery-options';\n\n// Base UI drives the collapse with the `--accordion-panel-height` CSS var it sets on the panel, so\n// the list expands/collapses in flow with a height transition (overflow-hidden clips it mid-animation).\nconst DEFAULT_PANEL_CLASS =\n 'overflow-hidden transition-[height] duration-200 ease-out h-[var(--accordion-panel-height)] data-starting-style:h-0 data-ending-style:h-0';\n\nexport type DeliveryOptionsAccordionProps = ComponentPropsWithRef<'button'> &\n MessageLocaleProp & {\n /** Optional prefix shown before the summary value on the trigger row (e.g. \"Forma de entrega\"). */\n label?: string;\n /** Separator between the selected option name and price on the trigger row. */\n separator?: string;\n /** Disclosure icon shown on the trigger. The compiler's per-route sprite is built from explicit\n * `icon`-typed prop values in the schema, so a page must set this rather than rely on the default. */\n icon?: string;\n /** Overrides the default collapsible panel styling (height-animation + overflow clip). */\n panelClassName?: string;\n /** Shipping slice forwarded by the reactive runtime; `null` until shipping resolves. */\n $data?: RawDeliveryOptionsData | null;\n /** Compiler-injected action surface; carries `shipping.selectOption`. */\n $actions?: ComponentActions;\n /** Local/dev fallback rows, used only when the reactive fetch resolves no options. */\n mockOptions?: ShippingOption[];\n /** The placeholder, the text that replaces a zero price, and the selection error messages. */\n $content?: ContentValue<typeof DeliveryOptionsAccordionContent>;\n };\n\nexport const DeliveryOptionsAccordionContent = defineContentType({\n id: 'delivery-options-accordion',\n title: 'Delivery Options Accordion',\n description:\n 'Text shown on the trigger while nothing is selected, instead of a zero price for the selected option, and when a selection is refused.',\n schema: {\n type: 'object',\n additionalProperties: false,\n properties: {\n placeholder: {\n type: 'string',\n title: 'Placeholder',\n format: 'icu-message',\n messageSource: 'Select a delivery option',\n },\n freeLabel: { type: 'string', title: 'Free price label', format: 'icu-message', messageSource: 'Free' },\n optionUnavailableMessage: {\n type: 'string',\n title: 'Option unavailable message',\n description: 'Shown when the picked option is no longer offered for the cart.',\n format: 'icu-message',\n messageSource: 'This delivery option is no longer available. Choose another one.',\n },\n missingAddressMessage: {\n type: 'string',\n title: 'Missing address message',\n description: 'Shown when no delivery address is saved on the cart yet.',\n format: 'icu-message',\n messageSource: 'Enter a delivery address before choosing a delivery option.',\n },\n genericErrorMessage: {\n type: 'string',\n title: 'Generic failure message',\n description: 'Shown for a network failure and for every refusal the shopper cannot act on.',\n format: 'icu-message',\n messageSource: 'Unable to update the delivery option. Please try again.',\n },\n },\n },\n});\n\n/** The message for each code a selection can resolve. A code this map does not know shows genericErrorMessage. */\nexport const DELIVERY_OPTIONS_ACCORDION_ERROR_FIELDS = {\n OPTION_UNAVAILABLE: 'optionUnavailableMessage',\n MISSING_SHIPPING_ADDRESS: 'missingAddressMessage',\n MISSING_CART_CONTEXT: 'genericErrorMessage',\n CART_NOT_FOUND: 'genericErrorMessage',\n NETWORK_ERROR: 'genericErrorMessage',\n} as const satisfies Record<DeliveryOptionSelectErrorCode, MessageFieldName<typeof DeliveryOptionsAccordionContent>>;\n\nexport const DeliveryOptionsAccordionDefinition = defineComponent<DeliveryOptionsAccordionProps>({\n name: 'DeliveryOptionsAccordion',\n importPath: '@vtex/faststore/components',\n component: DeliveryOptionsAccordion,\n content: DeliveryOptionsAccordionContent,\n fragment,\n fetchStrategy: 'reactive',\n actions: { shipping: ['selectOption'] },\n editor: { label: 'Delivery Options Accordion', category: 'commerce' },\n schema: {\n label: { type: 'string', label: 'Trigger label prefix' },\n separator: { type: 'string', default: ' — ', label: 'Summary separator' },\n icon: { type: 'icon', default: 'caret-down', label: 'Disclosure icon' },\n mockOptions: { type: 'array', label: 'Mock options (local/dev fallback, ignored once real data has options)' },\n },\n // Re-provides the reused option leaves' runtime contexts (Decision 2): `shipping-simulator-option`\n // for the leaves composed as direct children here, plus the outer `shipping-simulator` this\n // accordion also provides at runtime.\n providesContext: ['shipping-simulator', 'shipping-simulator-option'],\n guideline:\n 'Collapsed delivery-option picker: a single summary row that expands the whole-cart option list inline (an accordion, not an overlay) and collapses it the moment a row is picked, echoing the choice (name + price) back on the trigger or its $content.placeholder when nothing is selected; its $content.freeLabel replaces a zero price in that echo. Reuses the FSPG-832 option leaves (ShippingSimulatorOption, OptionName, OptionEstimate, OptionPrice, OptionFreeBadge) as the per-option template placed as children, exactly like DeliveryOptionsRoot. Selecting a row dispatches $actions.shipping.selectOption; a refusal shows inline, worded by its code from its $content (genericErrorMessage for a network failure, every refusal the shopper cannot act on, and an unknown code). mockOptions is a local/dev-only fallback whose selection stays local. Use instead of a DeliveryOptionsController overlay (Dialog/Drawer) when the picker should expand in the page flow rather than surface in an overlay.',\n});\n\nexport function DeliveryOptionsAccordion({\n $content,\n $locale,\n label,\n separator = ' — ',\n icon = 'caret-down',\n panelClassName = DEFAULT_PANEL_CLASS,\n $data,\n $actions: $actionsProp,\n mockOptions,\n className,\n children,\n ...props\n}: DeliveryOptionsAccordionProps) {\n const $actions = useActionsOverride($actionsProp);\n const { options, selectedOptionId, selectionError, selectOption, contextValue } = useDeliveryOptionSelection({\n $data,\n $actions,\n mockOptions,\n });\n const [open, setOpen] = useState(false);\n const { format } = useMessageFormatter(DeliveryOptionsAccordionContent, $content);\n const selectedOption = options.find((option) => option.id === selectedOptionId) ?? null;\n const errorMessage = selectionError\n ? formatErrorCode(\n DeliveryOptionsAccordionContent,\n DELIVERY_OPTIONS_ACCORDION_ERROR_FIELDS,\n selectionError,\n format,\n 'genericErrorMessage',\n )\n : null;\n\n function handleValueChange(optionId: string) {\n selectOption(optionId, {\n onSettled: (ok) => {\n if (ok) setOpen(false);\n },\n });\n }\n\n return (\n <ShippingSimulatorContext value={contextValue}>\n <AccordionRoot\n openMultiple={false}\n value={open ? [ACCORDION_ITEM_VALUE] : []}\n onValueChange={(value) => setOpen(value.length > 0)}\n data-fs-delivery-options-accordion=\"\"\n >\n <AccordionItem value={ACCORDION_ITEM_VALUE}>\n <AccordionHeader className=\"m-0\">\n <AccordionTrigger {...props} className={className} data-fs-delivery-options-accordion-trigger=\"\">\n {label ? <span data-fs-delivery-options-accordion-label=\"\">{label}</span> : null}\n {selectedOption ? (\n <OptionItemContext value={selectedOption}>\n <span data-fs-delivery-options-accordion-value=\"\">\n <ShippingSimulatorOptionName />\n <span data-fs-delivery-options-accordion-separator=\"\">{separator}</span>\n <ShippingSimulatorOptionPrice>\n {isFreeAmount(selectedOption.price.amount) ? format('freeLabel') : undefined}\n </ShippingSimulatorOptionPrice>\n </span>\n </OptionItemContext>\n ) : (\n <span data-fs-delivery-options-accordion-placeholder=\"\">{format('placeholder')}</span>\n )}\n <span data-fs-delivery-options-accordion-icon=\"\">\n <Icon name={icon} />\n </span>\n </AccordionTrigger>\n </AccordionHeader>\n <AccordionPanel className={panelClassName} data-fs-delivery-options-accordion-panel=\"\">\n <div data-fs-delivery-options=\"\" className=\"pt-3\">\n {errorMessage === null ? null : (\n <div role=\"alert\" data-fs-delivery-options-error=\"\">\n {errorMessage}\n </div>\n )}\n {options.length > 0 ? (\n <RadioGroup\n value={selectedOptionId ?? ''}\n onValueChange={handleValueChange}\n className=\"flex flex-col gap-3\"\n >\n {options.map((option) => (\n <OptionItemContext key={option.id} value={option}>\n <RadioRoot value={option.id}>{children}</RadioRoot>\n </OptionItemContext>\n ))}\n </RadioGroup>\n ) : null}\n </div>\n </AccordionPanel>\n </AccordionItem>\n </AccordionRoot>\n </ShippingSimulatorContext>\n );\n}\n"],"mappings":"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"}
|