@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
package/dist/docs/card-entry.md
CHANGED
|
@@ -50,7 +50,7 @@ PaymentSectionRoot (or PaymentSectionController)
|
|
|
50
50
|
├── … other payment leaves (installments, save-card, billing, place-order)
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`CardEntry` renders its own four fields internally (number, holder name, expiration, CVV) — none of them are separately placeable schema elements. Holder name, expiration, and CVV each render conditionally, based on the detected payment method's validator config; the number field always renders. The CVV field is `type="text"`, same as the others, but carries an inline `-webkit-text-security: disc` style that renders its digits as dots
|
|
53
|
+
`CardEntry` renders its own four fields internally (number, holder name, expiration, CVV) — none of them are separately placeable schema elements. Holder name, expiration, and CVV each render conditionally, based on the detected payment method's validator config; the number field always renders. The CVV field is `type="text"`, same as the others, but carries an inline `-webkit-text-security: disc` style that renders its digits as dots while the field does not have focus: readable while the shopper is in the field, so they can read back what they just typed and catch a typo, and obscured the moment focus leaves it, with no length involved — a partial code is hidden on blur like a full one. Re-focusing a hidden code reveals it again, so a typo can be read and corrected. A disabled field counts as unfocused, because a browser fires no `blur` when a focused input becomes disabled; the focus flag is also reset when the card form collapses and when the input unmounts. The style is derived from the value and the focus flag on every render, never from an effect or a timer, so a paste or a browser autofill that delivers every digit while the field is unfocused, and the blur itself, open no legible window. The trade-off is deliberate: while the field has focus, a code the shopper just typed is on screen in the clear. `type="password"` was tried first and reverted: a real Chrome browser offered to save the security code to its password manager (synced to the signed-in account) the instant the field carried that type — pairing the expiration field as a fake "username" — which PCI-DSS forbids for a value that must not be retained past authorization. The CSS property obscures the digits without tripping that heuristic, since it never touches `type`. It is supported in Chromium and WebKit (and Firefox 114+, unverified on this branch); an engine without it renders the digits in the clear, exactly what shipped before this mechanism existed — not a regression. The declaration is an inline style, which outranks a class-based rule from a compound swatch at normal importance — but not one that reaches for Tailwind's `!` important modifier: swatch tokens reach `className` verbatim with no validation, so a store that authors an arbitrary-property utility ending in `!` can still unmask the field. Nothing in this package closes that hole; it is accepted rather than fixed. A helper line (`cvvDescription`) renders under the field by default, telling the shopper where to find the code; an empty string suppresses it (see Components below).
|
|
54
54
|
|
|
55
55
|
**Composition rules:**
|
|
56
56
|
|
|
@@ -72,7 +72,7 @@ Collapsing clears the security code field, and only the security code. The card
|
|
|
72
72
|
|
|
73
73
|
The authored `disabled` prop is independent of the collapse: a store that freezes the form with `disabled` sees no change, and a collapsed form may also be `disabled` — neither implies the other.
|
|
74
74
|
|
|
75
|
-
In the checkout, the card number, holder name, expiration, and security code are cleared after every outcome in which the card target ran: the card POST resolved clean, resolved with errors or threw, or the target refused before any request. They are kept when the submission was refused before the target ran (the form's own check, a refused or untrusted transaction, the submit gate, no method selected) so the shopper can fix them.
|
|
75
|
+
In the checkout, the card number, holder name, expiration, and security code are cleared after every outcome in which the card target ran: the card POST resolved clean, resolved with errors or threw, or the target refused before any request. They are kept when the submission was refused before the target ran (the form's own check, a refused or untrusted transaction, the submit gate, no method selected) so the shopper can fix them. The values stay while the card request is open and clear as soon as it settles, ahead of the confirmation callback, so a callback error or timeout finds the form already empty. While the order attempt is resume-only the form accepts no input, so a card cannot be typed into a form that the next click would ignore.
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
@@ -115,7 +115,7 @@ The card number and security code are typed into `CardEntry`'s raw fields and PO
|
|
|
115
115
|
{
|
|
116
116
|
"routes": ["/checkout"],
|
|
117
117
|
"headers": {
|
|
118
|
-
"Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https
|
|
118
|
+
"Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://acme.vtexassets.com; font-src 'self' data:; connect-src 'self' https://acme.vtexvault.com; form-action 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none'",
|
|
119
119
|
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -126,7 +126,7 @@ The card number and security code are typed into `CardEntry`'s raw fields and PO
|
|
|
126
126
|
- **The vault host in `connect-src` is `https://{account}.vtexvault.com`, for the account the store serves.** That is the `NEXT_PUBLIC_ACCOUNT` the store is built with, which is not always `store.account` in `foundation.json`. Write the served account, with no wildcard: `https://*.vtexvault.com` would let a compromised script send the card to any tenant's vault.
|
|
127
127
|
- **A policy that names the legacy payments host (`vtexpayments.com.br`) makes the browser block the card POST.** The order cannot be placed and nothing else on the page reports why. The generated app calls its own GraphQL at the relative `/api/graphql`, so `'self'` covers it; a store built with an absolute `NEXT_PUBLIC_STOREFRONT_API_URL` must add that origin.
|
|
128
128
|
- **A rule's `routes` must name the page that composes `CardEntry`**, as the page's `route` spells it (`/checkout`, `/reserva/checkout/payment`). Renaming that page fails the compile instead of dropping the policy. A page added later that composes `CardEntry` carries nothing until its route is added to the rule.
|
|
129
|
-
- **`script-src 'unsafe-inline'` is a known limit, and the policy does not stop injected script from sending the card off the page.** A static header cannot carry a nonce, so the inline scripts Next.js emits need it, and script injected into the page runs with the same rights. `connect-src` closes only `fetch`, XHR, beacons and WebSocket. The policy still leaves
|
|
129
|
+
- **`script-src 'unsafe-inline'` is a known limit, and the policy does not stop injected script from sending the card off the page.** A static header cannot carry a nonce, so the inline scripts Next.js emits need it, and script injected into the page runs with the same rights. `connect-src` closes only `fetch`, XHR, beacons and WebSocket. The policy still leaves one channel open to any https host: a navigation (CSP cannot restrict one). The image and form-post channels are closed: `img-src` names exactly one image origin, `https://{account}.vtexassets.com`, so a store whose page loads images from another origin must list that origin exactly (a bare `https:` fails the header check), and `form-action 'self'` stops a form from posting to another origin (the check accepts `'self'` or `'none'` and nothing else). What today's ruled policy does give is the vault origin pinned, no `'unsafe-eval'`, a page no other site can frame (`frame-ancestors 'none'`) and no `http:` or wildcard source. It does not replace keeping untrusted script off the payment page.
|
|
130
130
|
- **`frame-ancestors 'none'`** blanks the page inside any iframe, including an editor preview.
|
|
131
131
|
- **reCAPTCHA needs the anti-bot origins, and the ruled policy above does not declare them yet.** The challenge frame and script come from `https://www.google.com` and `https://www.gstatic.com`, the origins `sdk/anti-bot` declares. The frame is blocked by `default-src 'self'` (no `frame-src`) and the script by `script-src 'self' 'unsafe-inline'`, so both need the anti-bot origins. The stores add them together with whoever wires `getAntiBotToken`; the header check accepts a `frame-src` that names only those two origins and rejects any other.
|
|
132
132
|
- **Under `next dev` the served `script-src` also carries `'unsafe-eval'`; production does not.** React Refresh evaluates code in the browser, so the generated `next.config.ts` adds `'unsafe-eval'` to the `script-src` of every Content-Security-Policy it serves only when `NODE_ENV` is `development` (what `next dev` sets), which is what `pnpm dev:example` runs. Any build whose `NODE_ENV` is not `development` (the default for `next build` and `next start`) serves the declared policy byte for byte, so the live header check still runs against them: a dev response shows a `script-src` the store never declared, which `scripts/assert-payment-page-headers.mjs` rejects by design, so run that script against `next start`.
|
|
@@ -143,33 +143,44 @@ The only component. No internal sub-parts are separately schema-addressable.
|
|
|
143
143
|
|
|
144
144
|
| Prop | Type | Default | Notes |
|
|
145
145
|
|------|------|---------|-------|
|
|
146
|
-
| `legend` | string | `"Card details"` | Fieldset legend/title. |
|
|
147
|
-
| `numberLabel` | string | `"Card number"` | Card-number field label. |
|
|
148
146
|
| `numberPlaceholder` | string | — | Card-number field placeholder. |
|
|
149
|
-
| `holderNameLabel` | string | `"Cardholder name"` | Holder-name field label. Same noun as `holderNameRequiredMessage`, deliberately. |
|
|
150
147
|
| `holderNamePlaceholder` | string | — | Holder-name field placeholder. |
|
|
151
|
-
| `expirationLabel` | string | `"Expiration date"` | Expiration field label. |
|
|
152
|
-
| `expirationPlaceholder` | string | `"MM/YY"` | Expiration field placeholder. |
|
|
153
|
-
| `cvvLabel` | string | `"Security code"` | CVV field label. |
|
|
154
148
|
| `cvvPlaceholder` | string | — | CVV field placeholder. |
|
|
155
|
-
| `cvvDescription` | string | `"The 3-4 digit number on your card"` | Helper text under the CVV field. Empty string renders nothing. |
|
|
156
|
-
| `numberRequiredMessage` | string | `"Card number is required"` | Shown when the card-number field is left blank. |
|
|
157
|
-
| `numberInvalidMessage` | string | `"Enter a valid card number"` | Shown for a Luhn-invalid number, or one a configured network claims only as a prefix (the wrong length, or two networks at once). |
|
|
158
|
-
| `networkNotAcceptedMessage` | string | `"This card is not from a network the store accepts"` | Shown for a Luhn-valid number that no configured network claims at all. |
|
|
159
|
-
| `holderNameRequiredMessage` | string | `"Cardholder name is required"` | Shown when the holder-name field is left blank and the detected method requires it. |
|
|
160
|
-
| `expirationRequiredMessage` | string | `"Expiration date is required"` | Shown when the expiration field is left blank and the detected method requires it. |
|
|
161
|
-
| `expirationInvalidMessage` | string | `"Enter a valid expiration date"` | Shown for a structurally malformed `MM/YY`. |
|
|
162
|
-
| `expirationExpiredMessage` | string | `"This card has expired"` | Shown for a structurally valid `MM/YY` that has already passed. |
|
|
163
|
-
| `cvvRequiredMessage` | string | `"Security code is required"` | Shown when the CVV field is left blank and the detected method requires it. |
|
|
164
|
-
| `cvvInvalidMessage` | string | `"Enter a valid security code"` | Shown for a CVV that fails the detected method's format. |
|
|
165
149
|
| `disabled` | boolean | `false` | Disables every field. |
|
|
166
150
|
|
|
151
|
+
**Content model** (`card-entry`), every field read only from `$content` (a missing message renders empty and logs `message.missing`):
|
|
152
|
+
|
|
153
|
+
| Field | Source copy | Notes |
|
|
154
|
+
|-------|-------------|-------|
|
|
155
|
+
| `legend` | "Card details" | Fieldset legend/title. |
|
|
156
|
+
| `numberLabel` | "Card number" | Card-number field label. |
|
|
157
|
+
| `holderNameLabel` | "Cardholder name" | Holder-name field label. Same noun as `holderNameRequiredMessage`, deliberately. |
|
|
158
|
+
| `expirationLabel` | "Expiration date" | Expiration field label. |
|
|
159
|
+
| `expirationPlaceholder` | "MM/YY" | Expiration field placeholder. |
|
|
160
|
+
| `cvvLabel` | "Security code" | CVV field label. |
|
|
161
|
+
| `cvvDescription` | "The 3-4 digit number on your card" | Helper text under the CVV field. A blank message renders nothing. |
|
|
162
|
+
| `numberRequiredMessage` | "Card number is required" | Shown when the card-number field is left blank. |
|
|
163
|
+
| `numberInvalidMessage` | "Enter a valid card number" | Shown for a Luhn-invalid number, or one a configured network claims only as a prefix (the wrong length, or two networks at once). |
|
|
164
|
+
| `networkNotAcceptedMessage` | "This card is not from a network the store accepts" | Shown for a Luhn-valid number that no configured network claims at all. |
|
|
165
|
+
| `holderNameRequiredMessage` | "Cardholder name is required" | Shown when the holder-name field is left blank and the detected method requires it. |
|
|
166
|
+
| `expirationRequiredMessage` | "Expiration date is required" | Shown when the expiration field is left blank and the detected method requires it. |
|
|
167
|
+
| `expirationInvalidMessage` | "Enter a valid expiration date" | Shown for a structurally malformed `MM/YY`. |
|
|
168
|
+
| `expirationExpiredMessage` | "This card has expired" | Shown for a structurally valid `MM/YY` that has already passed. |
|
|
169
|
+
| `cvvRequiredMessage` | "Security code is required" | Shown when the CVV field is left blank and the detected method requires it. |
|
|
170
|
+
| `cvvInvalidMessage` | "Enter a valid security code" | Shown for a CVV that fails the detected method's format. |
|
|
171
|
+
|
|
167
172
|
**Data:** declares no fragment and no actions. Card masks, required-ness, and network regexes come from the `card-capture` context — at checkout, the payment section's own methods. It reads no cart, so it works where no purchase is underway; the `add_payment_info` event and the cart total it needs belong to the payment section root.
|
|
168
173
|
|
|
169
174
|
**Never a schema prop:** the card number and CVV. They exist only in this component's local state, for the lifetime of the mounted instance, and are never exposed as a bindable prop, a fragment field, or a value another component can read.
|
|
170
175
|
|
|
171
176
|
**Validation timing:** the draft is validated before the place-order sequence opens a transaction, not only when the order is submitted — an invalid number, holder name, expiration, or CVV refuses with an inline field message before anything is charged or opened. The submission itself re-validates the same way, so the two can never disagree.
|
|
172
177
|
|
|
178
|
+
**Field timing:** each field validates when the shopper leaves it. A blur writes or clears only that field's error, and editing a field clears its own error. A blur never moves focus: pulling focus back to a half-typed expiration would trap a shopper who tabs away. The first invalid field takes focus only when Place order refuses the draft.
|
|
179
|
+
|
|
180
|
+
**Keyboard hint:** the number, expiration, and security code inputs carry `inputmode="numeric"`; the holder name input carries none. The attribute is advisory, so a keyboard that ignores it still shows letters.
|
|
181
|
+
|
|
182
|
+
**A card from a network the store does not accept:** a Luhn-valid number that no configured network claims, exactly or as a prefix, is told apart from a malformed one. The number field shows `networkNotAcceptedMessage` when the shopper leaves it, and Place order refuses with the code `UNSUPPORTED_CARD_NETWORK`, rendered through `PlaceOrder`'s `unsupportedNetworkMessage`, whether or not a payment method is selected. The refusal comes before any transaction opens. With no method selected, the form gives the place-order sequence a side-effect-free explanation, asked only at the missing-method step, so the order of the checks (path, method, submit gate, card check) does not change; that click sets no field error and moves no focus, because the blur message is already on the field. With a method selected, the card check itself refuses with the same code, shows the field error, and focuses the number. A prefix claimed at the wrong length, a prefix two networks both claim, a Luhn-invalid number, and a blank number keep their existing refusals, and so does a store whose methods carry no number pattern, where detection never ran. The code and both messages are fixed copy: nothing derived from the typed number appears in them or in a log line.
|
|
183
|
+
|
|
173
184
|
**Selection timing:** network detection, the network mark, and the number's grouping follow every keystroke, but the detected method and the card's BIN (its first eight digits) reach the server only once the number field holds eight digits — never as a shorter prefix. Below eight digits nothing is sent, so the installments control and the persisted selection keep whatever was last recorded. The first digit typed off the new-card path does record that path, locally and with nothing sent, so a saved card that was checked stops being the selection as soon as the shopper starts a new number.
|
|
174
185
|
|
|
175
186
|
---
|
|
@@ -234,14 +245,16 @@ Style `CardEntry`'s root as a vertical stack of fields, matching a typical card
|
|
|
234
245
|
| Network mark slot (`data-fs-card-entry-networks`) | Positions the single mark inside the input's box; absent entirely until a network is recognized | `absolute right-[12px] top-1/2 -translate-y-1/2 flex items-center` |
|
|
235
246
|
| Network mark (`data-fs-card-entry-network`) | The recognized network itself — **at most one**, never a row. Carries `data-fs-card-entry-network-id` with the detected method's id | `flex items-center justify-center` |
|
|
236
247
|
| Network icon (`data-fs-card-entry-network-icon`) | The icon, when the recognized network's name maps to one | `w-[20px] h-[20px]` |
|
|
237
|
-
| Network fallback text (`data-fs-card-entry-network-fallback`) | The recognized network's name as text, when it maps to no icon; mutually exclusive with the icon | `text-[13px] font-medium text-[
|
|
238
|
-
| Field labels (`data-fs-field-label`) | Small, muted label above each input | `text-[13px] font-medium text-[
|
|
239
|
-
| Field inputs (`data-fs-field-control`) | The bordered text input | `border border-[
|
|
240
|
-
| Field errors (`data-fs-field-error`) | Inline validation message, small
|
|
241
|
-
| CVV helper text (`data-fs-card-entry-cvv-description`) | Small muted line under the CVV field | `text-[12px] text-[
|
|
248
|
+
| Network fallback text (`data-fs-card-entry-network-fallback`) | The recognized network's name as text, when it maps to no icon; mutually exclusive with the icon | `text-[13px] font-medium text-[var(--color-ink)]` |
|
|
249
|
+
| Field labels (`data-fs-field-label`) | Small, muted label above each input | `text-[13px] font-medium text-[var(--color-ink)] mb-[4px] block` |
|
|
250
|
+
| Field inputs (`data-fs-field-control`) | The bordered text input | `border border-[color-mix(in_srgb,var(--color-ink)_20%,transparent)] rounded-[var(--radius-base)] px-[12px] py-[10px] text-[15px] w-full` |
|
|
251
|
+
| Field errors (`data-fs-field-error`) | Inline validation message, small | `text-[12px] mt-[4px] block` |
|
|
252
|
+
| CVV helper text (`data-fs-card-entry-cvv-description`) | Small muted line under the CVV field | `text-[12px] text-[color-mix(in_srgb,var(--color-ink)_60%,transparent)] mt-[4px] block` |
|
|
242
253
|
| Placing (`data-fs-card-entry-placing`) | Present while an order-placement sequence is in flight (T28), and while the order attempt is resume-only (its card may already have been sent, so the fields do not accept input) until the attempt is freed; the whole root is also `inert` and `aria-disabled` at that point, so style this hook rather than relying on pointer events alone | `opacity-60 cursor-not-allowed` |
|
|
243
254
|
| Collapsed (`data-fs-card-entry-collapsed`) | Present on the styled root while the card payment is collapsed — the persisted selection is a method this section does not serve or one that is not a card, and a picker is composed to un-hide it (see Reveal and collapse); the root is also `inert`. **No transition or animation can run on it**: the actual hide is a `hidden` attribute one level up, on an unstyled wrapper this node cannot reach with any class, and an ancestor's `display:none` removes the whole subtree from rendering the instant it applies, before any transition on a descendant could ever paint. Use this hook only for one-shot conditional styling of the (already-unrendered) subtree, never for an entrance/exit animation | `opacity-60` |
|
|
244
255
|
|
|
256
|
+
A status color is a `visualIdentity` feedback role of the foundation: when the store declares them, color the error row `text-[var(--color-feedback-danger)]`, the success row `text-[var(--color-feedback-success)]` and the notice row `text-[var(--color-feedback-warning)]`, never with a hex.
|
|
257
|
+
|
|
245
258
|
Styled minimal example:
|
|
246
259
|
|
|
247
260
|
```json
|
|
@@ -260,7 +273,7 @@ Styled minimal example:
|
|
|
260
273
|
## Accessibility Contract
|
|
261
274
|
|
|
262
275
|
**What the platform promises:** the four fields sit inside a native `<fieldset>`/`<legend>` pair
|
|
263
|
-
(`legend
|
|
276
|
+
(the `legend` message) — the pattern every other grouped payment control now follows
|
|
264
277
|
(T38, Decision 1). Each field carries its own `Field.Label`, `aria-invalid`, and an error message
|
|
265
278
|
associated through `aria-describedby` once it fails validation; the CVV field's helper text
|
|
266
279
|
(`cvvDescription`) is linked the same way. There is no composite keyboard widget here — every rendered
|
|
@@ -59,7 +59,15 @@ Code only: it has no catalog entry and is never placed in a schema, because a sc
|
|
|
59
59
|
|
|
60
60
|
### CardSummary
|
|
61
61
|
|
|
62
|
-
The wrapper, `<span data-fs-card-summary>`. Carries `data-fs-card-summary-network="<icon>"` when the network has a mark and `data-fs-card-summary-labeled` when a label is present. No props
|
|
62
|
+
The wrapper, `<span data-fs-card-summary>`. Carries `data-fs-card-summary-network="<icon>"` when the network has a mark and `data-fs-card-summary-labeled` when a label is present. No props besides `$content`.
|
|
63
|
+
|
|
64
|
+
It formats its `endingIn` message and hands it to the `CardSummaryDigits` inside it. A missing message logs an error, and the digits are then read bare. A `CardSummary` has `$content` only when the store places it or a parent forwards a message to it, as `AccountSavedCardRemoveDescription` forwards its `cardEndingIn`.
|
|
65
|
+
|
|
66
|
+
Content type `card-summary`:
|
|
67
|
+
|
|
68
|
+
| Content field | Description |
|
|
69
|
+
|---|---|
|
|
70
|
+
| endingIn | The last digits as read to assistive technology, with the `lastDigits` argument |
|
|
63
71
|
|
|
64
72
|
### CardSummaryMark
|
|
65
73
|
|
|
@@ -90,7 +98,7 @@ Decoration for the hidden digits, always `aria-hidden`. Nothing when empty or wh
|
|
|
90
98
|
|
|
91
99
|
### CardSummaryDigits
|
|
92
100
|
|
|
93
|
-
The last four digits. Screen readers hear
|
|
101
|
+
The last four digits. Screen readers hear the `endingIn` message of the `CardSummary` around them, such as "ending in 1234"; the visible digits are hidden from them. Outside a `CardSummary`, or with its message missing, screen readers hear the bare digits. Nothing when the card has no digits. No props.
|
|
94
102
|
|
|
95
103
|
---
|
|
96
104
|
|
|
@@ -150,9 +158,9 @@ Digits first, with another mask:
|
|
|
150
158
|
|---|---|---|
|
|
151
159
|
| `CardSummary` | Lines the parts up | `inline-flex items-center gap-[8px]` |
|
|
152
160
|
| `CardSummaryMark` | Mark box; size the glyph through it | `inline-flex items-center [&_svg]:h-[24px] [&_svg]:w-[32px]` |
|
|
153
|
-
| `CardSummaryName` | Name typography | `text-[14px] font-medium text-[
|
|
154
|
-
| `CardSummaryMask` | Mask color and spacing | `text-[14px] tracking-[2px] text-[
|
|
155
|
-
| `CardSummaryDigits` | Digit typography | `text-[14px] tabular-nums text-[
|
|
161
|
+
| `CardSummaryName` | Name typography | `text-[14px] font-medium text-[var(--color-text)]` |
|
|
162
|
+
| `CardSummaryMask` | Mask color and spacing | `text-[14px] tracking-[2px] text-[var(--color-text-muted)]` |
|
|
163
|
+
| `CardSummaryDigits` | Digit typography | `text-[14px] tabular-nums text-[var(--color-text)]` |
|
|
156
164
|
|
|
157
165
|
`CardSummaryRoot` renders no element and is not styled.
|
|
158
166
|
|
|
@@ -160,12 +168,14 @@ Digits first, with another mask:
|
|
|
160
168
|
{
|
|
161
169
|
"card-summary": { "type": "CardSummary", "style": ["inline-flex", "items-center", "gap-[8px]"], "children": ["card-mark", "card-name", "card-mask", "card-digits"] },
|
|
162
170
|
"card-mark": { "type": "CardSummaryMark", "style": ["inline-flex", "items-center", "[&_svg]:h-[24px]", "[&_svg]:w-[32px]"] },
|
|
163
|
-
"card-name": { "type": "CardSummaryName", "style": ["text-[14px]", "font-medium", "text-[
|
|
164
|
-
"card-mask": { "type": "CardSummaryMask", "style": ["text-[14px]", "tracking-[2px]", "text-[
|
|
165
|
-
"card-digits": { "type": "CardSummaryDigits", "style": ["text-[14px]", "tabular-nums", "text-[
|
|
171
|
+
"card-name": { "type": "CardSummaryName", "style": ["text-[14px]", "font-medium", "text-[var(--color-text)]"] },
|
|
172
|
+
"card-mask": { "type": "CardSummaryMask", "style": ["text-[14px]", "tracking-[2px]", "text-[var(--color-text-muted)]"] },
|
|
173
|
+
"card-digits": { "type": "CardSummaryDigits", "style": ["text-[14px]", "tabular-nums", "text-[var(--color-text)]"] }
|
|
166
174
|
}
|
|
167
175
|
```
|
|
168
176
|
|
|
177
|
+
The colors that several elements share are variables of the page or layout `theme`, which declares them: `{"--color-text": "#1F1F1F", "--color-text-muted": "#6B6B6B"}`. A color used once stays a hex.
|
|
178
|
+
|
|
169
179
|
---
|
|
170
180
|
|
|
171
181
|
## Related
|
|
@@ -69,6 +69,8 @@ The field itself. Renders the `DocumentField` particle for the type `usePayment(
|
|
|
69
69
|
| `errorMessage` | `string` | `'Invalid '` + the type's name | Shown inline when the typed value fails the type's validation on blur. |
|
|
70
70
|
| `disabled` | `boolean` | `false` | Disables the input without hiding it — independent of the data-driven presence gate. |
|
|
71
71
|
|
|
72
|
+
The method decides whether the field shows and whether it is mandatory; the store's country decides which document it is. The type is the first displayable document the store's country row lists that this build knows, and a country row's own `required` flag is read by nobody. The SSN and SIN inputs carry `autocomplete="off"` so a browser does not offer them for autofill; the CPF and RFC inputs carry no `autocomplete` attribute, and every type stays `type="text"`.
|
|
73
|
+
|
|
72
74
|
No `documentType` prop — the store's country decides it. No `required` prop — requiredness is always read from the selected method's validator, never authored.
|
|
73
75
|
|
|
74
76
|
**Data:** declares no `fragment` of its own. It reads `selectedMethod`, `countryDocumentType`, `draft`, and `setDraftDocument` off the ambient `payment` context that `PaymentSectionRoot` / `PaymentSectionController` already fetches for.
|
|
@@ -109,8 +111,8 @@ No `documentType` prop — the store's country decides it. No `required` prop
|
|
|
109
111
|
|
|
110
112
|
## Known limitations
|
|
111
113
|
|
|
112
|
-
- **Four person documents, by store country.** The country comes from `Payment.storeCountryCode` and `Payment.countries`. A store whose country resolves to no document type shows no field, refuses nothing and sends no document. A document typed while the field was shown is posted only while the selected method still asks for one and the country still resolves a type; the draft itself is not cleared. `label`, `placeholder` and `errorMessage` have no catalog default (the right copy depends on the country), so leave them unset unless the store serves one country.
|
|
113
|
-
- **Server-driven requiredness renders the field correctly and is also enforced at submit time — but not by this component or by `CardEntry`.** This component marks the field required when the validator says so; a required-but-blank or malformed value (whether or not required) blocks Place Order client-side, before any transaction opens, **while the selected method's validator also says the document is displayable**. That gate lives in `matter/payment/use-payment-submit-gate.ts` (T24) and is consumed by `PlaceOrder`, not by this component or by `CardEntry`'s own `validateDraft` — this component's only job stays publishing `draft.document` via `setDraftDocument`. When the *currently* selected method's validator says `documentDisplayable: false`, the gate treats `draft.document` as inert either way (fix pass, findings R1/S4/S5): there is no field on screen for the shopper to read a leftover value from or correct it in, whether that value is left over from a previously selected, displayable method or simply blank.
|
|
114
|
+
- **Four person documents, by store country.** The country comes from `Payment.storeCountryCode` and `Payment.countries`. A store whose country resolves to no document type shows no field, refuses nothing and sends no document, even when the selected method says a document is required, so the order is not refused client-side for it. A document typed while the field was shown is posted only while the selected method still asks for one and the country still resolves a type; the draft itself is not cleared. `label`, `placeholder` and `errorMessage` have no catalog default (the right copy depends on the country), so leave them unset unless the store serves one country.
|
|
115
|
+
- **Server-driven requiredness renders the field correctly and is also enforced at submit time — but not by this component or by `CardEntry`.** This component marks the field required when the validator says so; a required-but-blank or malformed value (whether or not required) blocks Place Order client-side, before any transaction opens, **while the selected method's validator also says the document is displayable**. That gate lives in `matter/payment/use-payment-submit-gate.ts` (T24) and is consumed by `PlaceOrder`, not by this component or by `CardEntry`'s own `validateDraft` — this component's only job stays publishing `draft.document` via `setDraftDocument`. The gate checks the value against the same country-resolved type the field shows. When the *currently* selected method's validator says `documentDisplayable: false`, the gate treats `draft.document` as inert either way (fix pass, findings R1/S4/S5): there is no field on screen for the shopper to read a leftover value from or correct it in, whether that value is left over from a previously selected, displayable method or simply blank.
|
|
114
116
|
|
|
115
117
|
---
|
|
116
118
|
|
|
@@ -120,7 +122,7 @@ No `documentType` prop — the store's country decides it. No `required` prop
|
|
|
120
122
|
|
|
121
123
|
| Component | What you style | Plausible classes |
|
|
122
124
|
|---|---|---|
|
|
123
|
-
| `CardholderDocument` | The field's own label, input box, and inline error — same shape as a `Field.Root` | `flex flex-col gap-[4px] w-full` on the root; `text-[14px] font-medium text-[
|
|
125
|
+
| `CardholderDocument` | The field's own label, input box, and inline error — same shape as a `Field.Root` | `flex flex-col gap-[4px] w-full` on the root; `text-[14px] font-medium text-[var(--color-ink)]` for the label; `border border-[color-mix(in_srgb,var(--color-ink)_20%,transparent)] rounded-[var(--radius-base)] px-[12px] py-[8px] text-[14px]` for the input |
|
|
124
126
|
| Placing (`data-fs-cardholder-document-placing`) | Present while an order-placement sequence is in flight (T28); the field is also `inert` and `aria-disabled` at that point | `opacity-60 cursor-not-allowed` |
|
|
125
127
|
|
|
126
128
|
Styled example:
|
package/dist/docs/carousel.md
CHANGED
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
| `variant` | `'slide' \| 'scroll'` | `'slide'` | Transform slide vs. native overflow scroll |
|
|
36
36
|
| `itemsPerPage` | number | `1` | How many children are visible per page |
|
|
37
37
|
| `defaultPage` | number | `0` | Page selected on first render |
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
The region's `aria-label` comes from the `$content` field `label` (content type `carousel-root`).
|
|
39
40
|
|
|
40
41
|
### CarouselTrack
|
|
41
42
|
|
|
@@ -43,16 +44,16 @@ Lays out and counts the children. No props beyond standard `div` attributes. Pla
|
|
|
43
44
|
|
|
44
45
|
### CarouselPrevious / CarouselNext
|
|
45
46
|
|
|
46
|
-
Buttons that move one page. No props beyond standard `button` attributes; accept any children (Icon, text). Disabled at the respective end when `infiniteMode` is off.
|
|
47
|
+
Buttons that move one page. No props beyond standard `button` attributes; accept any children (Icon, text). Disabled at the respective end when `infiniteMode` is off. Their `aria-label` comes from the `$content` field `label` (content types `carousel-previous` and `carousel-next`).
|
|
47
48
|
|
|
48
49
|
### CarouselBullets
|
|
49
50
|
|
|
50
51
|
| Prop | Type | Default | Notes |
|
|
51
52
|
|------|------|---------|-------|
|
|
52
|
-
| `ariaLabel` | string | `'Choose page'` | Label for the bullets group |
|
|
53
|
-
| `bulletLabel` | string | `'Go to page {page}'` | Per-bullet label; `{page}` is the 1-based page number |
|
|
54
53
|
| `hideWhenSingle` | boolean | `true` | Render nothing when there is a single page |
|
|
55
54
|
|
|
55
|
+
The labels come from `$content` (content type `carousel-bullets`): `ariaLabel` names the bullets group, and `bulletLabel` names each bullet, an ICU message whose `{page}` argument is the 1-based page number.
|
|
56
|
+
|
|
56
57
|
Bullets support `ArrowLeft` / `ArrowRight` / `Home` / `End` keyboard navigation and mark the active page with `data-fs-carousel-bullet-selected="true"` and `aria-current`.
|
|
57
58
|
|
|
58
59
|
---
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
Look in the **top of the cart page's main column**, above the free-shipping bar and the line items:
|
|
11
11
|
|
|
12
12
|
- A single line reading **"Entregando em"** (or "Delivering to") followed by a **postal code and city, state**, beside a link such as **"Trocar localização?"**.
|
|
13
|
-
- With no destination yet, the
|
|
14
|
-
- Pressing the link swaps the line for **one
|
|
13
|
+
- With no destination yet, the bar shows just a prompt such as **"Informe seu CEP"**, often with a pin icon. Pressing it opens the field.
|
|
14
|
+
- Pressing the link (or the prompt) swaps the line for **one postal code field**, an **"Atualizar"** button and a **"Cancelar"** button.
|
|
15
15
|
|
|
16
16
|
The image is the source of truth for layout.
|
|
17
17
|
|
|
@@ -40,14 +40,14 @@ A postal code control in the **site header** is not this component: that is `Reg
|
|
|
40
40
|
CartDestinationRoot (provides 'cartDestination'; starts in read mode)
|
|
41
41
|
├── CartDestinationRead (read mode only)
|
|
42
42
|
│ ├── CartDestinationValue (the destination, once set)
|
|
43
|
-
│ ├── CartDestinationUnset (the
|
|
43
|
+
│ ├── CartDestinationUnset (button: the invitation, while none is set; opens edit mode)
|
|
44
|
+
│ │ ├── Icon (optional pin)
|
|
44
45
|
│ │ └── Text ("Informe seu CEP")
|
|
45
46
|
│ └── CartDestinationChange (opens edit mode)
|
|
46
47
|
└── CartDestinationForm (edit mode only)
|
|
47
48
|
├── CartDestinationPostalCodeControl
|
|
48
49
|
├── CartDestinationSubmit
|
|
49
50
|
├── CartDestinationCancel
|
|
50
|
-
├── Text (the help line, placed by the store)
|
|
51
51
|
└── CartDestinationError
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -85,7 +85,7 @@ The destination as prefix, postal code, city and state, each in its own element.
|
|
|
85
85
|
|
|
86
86
|
### CartDestinationUnset
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
A button that opens edit mode, with `aria-expanded` tied to the mode, exactly like `CartDestinationChange`. It renders only once the destination resolved and none is set. Its children are the invitation content (a `Text`, an `Icon`). Place it within `CartDestinationRead`. Its props are the props of a button; a consumer `onClick` runs before edit mode opens. When edit mode closes with no destination set, focus returns to this button. It ships no style of its own: like the change link, the store gives it a pointer cursor and an underline so it reads as clickable.
|
|
89
89
|
|
|
90
90
|
### CartDestinationChange
|
|
91
91
|
|
|
@@ -103,18 +103,23 @@ Renders only in edit mode. Enter in the field runs the submit, which flags an in
|
|
|
103
103
|
|
|
104
104
|
### CartDestinationPostalCodeControl
|
|
105
105
|
|
|
106
|
-
A
|
|
106
|
+
A plain text field bound to the draft, empty every time edit mode opens. Its limits (`maxLength`, `inputMode`) and its placeholder, the country's example postal code (`01310-100` for BRA), come from the postal code rules of the cart's country (`@vtex/country-forms`), which load when edit mode opens. There is no input mask: the shopper types the code as they know it, and Submit validates it against the country's rules.
|
|
107
|
+
|
|
108
|
+
While the rules load, the field and `CartDestinationSubmit` are disabled, and the field takes focus once it is enabled. If the load fails, the field is enabled as free text and nothing validates it. A country the rules do not cover (anything but ARG, BRA, CAN, CHL, COL, DEU, ECU, ESP, FRA, GBR, IRL, ITA, MEX, PER and USA) is free text too: no mask, no limit and no validation beyond a non-blank value.
|
|
109
|
+
|
|
110
|
+
The component keeps no mask table and does not read the shared country descriptors that `BillingAddress` and `ShippingAddress` use, so a Canadian or Mexican cart address is judged by the library's own rules for those countries and never by the Brazilian `99999-999` mask. For `CAN` the field takes at most 7 characters, shows the example `K1A 0A9`, accepts `k1a0b1` and writes it as `K1A 0B1`; the library refuses a first letter of D, F, I, O, Q, U or W and is looser than Canada Post elsewhere (`Z1A 0A9` passes). For `MEX` the field takes at most 5 characters on a numeric keyboard and refuses `00999` and `6600`; there is no mask. No case in `cart-destination.test.tsx` uses `CAN` or `MEX`: the behaviour comes from the same `@vtex/country-forms` rules and `sdk/address` functions the billing and shipping suites pin for those countries.
|
|
111
|
+
|
|
112
|
+
Because the rules come from the library, the cart can disagree with the other two forms where their descriptor patterns differ from the library. A US ZIP+4 typed without the hyphen (`021011234`) is refused here (`cart-destination.test.tsx` pins it) and accepted by billing and shipping.
|
|
107
113
|
|
|
108
114
|
| Prop | Type | Default | Notes |
|
|
109
115
|
|------|------|---------|-------|
|
|
110
|
-
| `mask` | string | the country's mask | `99999-999` for BRA; also the mask Submit checks the draft against, and the typed value must still match the country's pattern, so a mask the pattern rejects (9 digits in BRA, for example) keeps Submit disabled |
|
|
111
116
|
| `label` | string | — | Field label |
|
|
112
|
-
| `placeholder` | string |
|
|
113
|
-
| `invalidMessage` | string | — | Shown for a
|
|
117
|
+
| `placeholder` | string | the country's example postal code | Field placeholder; wins over the example the rules give |
|
|
118
|
+
| `invalidMessage` | string | — | Shown for a typed code the country's rules refuse, once the field loses focus or Submit is attempted |
|
|
114
119
|
|
|
115
120
|
### CartDestinationSubmit
|
|
116
121
|
|
|
117
|
-
Writes the typed postal code. Disabled until the
|
|
122
|
+
Writes the typed postal code. Disabled until the country's rules have loaded, the draft passes the country's postal code validation (any non-blank text when the rules failed to load or the country is not covered) and differs from the current postal code, and while a write is pending (`aria-busy`). The write sends the code in the country's own form (`04538132` becomes `04538-132`). A pending write also waits for any cart line write in flight.
|
|
118
123
|
|
|
119
124
|
| Prop | Type | Default | Notes |
|
|
120
125
|
|------|------|---------|-------|
|
|
@@ -135,13 +140,16 @@ Closes edit mode, discards the draft and any error, and writes nothing. Disabled
|
|
|
135
140
|
|
|
136
141
|
### CartDestinationError
|
|
137
142
|
|
|
138
|
-
An alert announcing a failed write; renders nothing otherwise.
|
|
143
|
+
An alert announcing a failed write; renders nothing otherwise. It words the error's `code` from its own content and never shows the server's text. A code it does not know (a newer server) shows `genericMessage` and logs `message.unknown-code`.
|
|
139
144
|
|
|
140
|
-
|
|
|
141
|
-
|
|
142
|
-
| `
|
|
145
|
+
| Code | Message field |
|
|
146
|
+
|------|---------------|
|
|
147
|
+
| `INVALID_POSTAL_CODE` | `invalidPostalCodeMessage` |
|
|
148
|
+
| `NETWORK_ERROR` and every other `ShippingAddressUpdateErrorCode` | `genericMessage` |
|
|
149
|
+
|
|
150
|
+
A postal code the platform refuses upstream reaches the client as `NETWORK_ERROR` today, so write `genericMessage` to cover it.
|
|
143
151
|
|
|
144
|
-
**Content model** (`cart-destination-error`): `genericMessage
|
|
152
|
+
**Content model** (`cart-destination-error`): `genericMessage`, `invalidPostalCodeMessage` (messages, no arguments).
|
|
145
153
|
|
|
146
154
|
---
|
|
147
155
|
|
|
@@ -160,7 +168,12 @@ An alert announcing a failed write; renders nothing otherwise. A refused postal
|
|
|
160
168
|
"children": ["cart-destination-value", "cart-destination-unset", "cart-destination-change"]
|
|
161
169
|
},
|
|
162
170
|
"cart-destination-value": { "type": "CartDestinationValue", "props": { "prefix": "Entregando em" }, "style": ["flex", "gap-1"] },
|
|
163
|
-
"cart-destination-unset": {
|
|
171
|
+
"cart-destination-unset": {
|
|
172
|
+
"type": "CartDestinationUnset",
|
|
173
|
+
"style": ["flex", "items-center", "gap-1", "cursor-pointer", "underline"],
|
|
174
|
+
"children": ["cart-destination-unset-icon", "cart-destination-invitation"]
|
|
175
|
+
},
|
|
176
|
+
"cart-destination-unset-icon": { "type": "Icon", "props": { "name": "map-pin" } },
|
|
164
177
|
"cart-destination-invitation": { "type": "Text", "props": { "as": "span", "children": "Informe seu CEP" } },
|
|
165
178
|
"cart-destination-change": {
|
|
166
179
|
"type": "CartDestinationChange",
|
|
@@ -174,20 +187,18 @@ An alert announcing a failed write; renders nothing otherwise. A refused postal
|
|
|
174
187
|
"cart-destination-control",
|
|
175
188
|
"cart-destination-submit",
|
|
176
189
|
"cart-destination-cancel",
|
|
177
|
-
"cart-destination-help",
|
|
178
190
|
"cart-destination-error"
|
|
179
191
|
]
|
|
180
192
|
},
|
|
181
193
|
"cart-destination-control": { "type": "CartDestinationPostalCodeControl", "props": { "label": "CEP" } },
|
|
182
194
|
"cart-destination-submit": { "type": "CartDestinationSubmit", "props": { "label": "Atualizar", "pendingLabel": "Atualizando…" } },
|
|
183
195
|
"cart-destination-cancel": { "type": "CartDestinationCancel", "props": { "label": "Cancelar" } },
|
|
184
|
-
"cart-destination-help": {
|
|
185
|
-
"type": "Text",
|
|
186
|
-
"props": { "as": "span", "children": "Após confirmar, a barra volta ao modo leitura com o novo CEP e cidade." }
|
|
187
|
-
},
|
|
188
196
|
"cart-destination-error": {
|
|
189
197
|
"type": "CartDestinationError",
|
|
190
|
-
"props": {
|
|
198
|
+
"props": {
|
|
199
|
+
"genericMessage": "Não foi possível usar esse CEP. Confira o número e tente de novo.",
|
|
200
|
+
"invalidPostalCodeMessage": "CEP inválido. Confira o número e tente de novo."
|
|
201
|
+
},
|
|
191
202
|
"style": ["text-sm", "text-red-700"]
|
|
192
203
|
}
|
|
193
204
|
}
|
|
@@ -205,7 +216,7 @@ An alert announcing a failed write; renders nothing otherwise. A refused postal
|
|
|
205
216
|
| `data-fs-cart-destination-read` | `CartDestinationRead` | Read mode |
|
|
206
217
|
| `data-fs-cart-destination-value` | `CartDestinationValue` | A destination is set |
|
|
207
218
|
| `data-fs-cart-destination-value-prefix`, `-postal-code`, `-city`, `-state` | The piece's element | The piece exists |
|
|
208
|
-
| `data-fs-cart-destination-unset` | `CartDestinationUnset` | No destination is set |
|
|
219
|
+
| `data-fs-cart-destination-unset` | `CartDestinationUnset` (a button) | No destination is set |
|
|
209
220
|
| `data-fs-cart-destination-change` | `CartDestinationChange` | Always |
|
|
210
221
|
| `data-fs-cart-destination-form` | `CartDestinationForm` | Edit mode |
|
|
211
222
|
| `data-fs-cart-destination-postal-code-control` | `CartDestinationPostalCodeControl` | Always |
|
|
@@ -225,14 +236,16 @@ No part ships CSS of its own. Spacing, the link look of the change control and t
|
|
|
225
236
|
- **Placing the postal code control, `CartDestinationSubmit` or `CartDestinationCancel` outside `CartDestinationForm`.** Only the form is bound to edit mode: outside it they render in read mode too, and Enter in the field no longer reaches the submit.
|
|
226
237
|
- **Looking for an `open` prop or a controller.** The root owns edit mode; nothing outside it can open it.
|
|
227
238
|
- **Omitting `CartDestinationUnset`.** With no destination the page then shows only the change link and no invitation.
|
|
239
|
+
- **Leaving `CartDestinationUnset` unstyled.** It is a button with no style of its own, so without a pointer cursor and an underline the invitation does not read as clickable. Give it the same look as `CartDestinationChange`.
|
|
240
|
+
- **Placing `CartDestinationChange` inside `CartDestinationUnset`.** The invitation is already a button, and a button cannot hold another. With no destination the regular change link repeats the invitation, so the store usually hides it while unset (for example with a `[&:has([data-fs-cart-destination-unset])>[data-fs-cart-destination-change]]:hidden` rule on `CartDestinationRead`).
|
|
228
241
|
- **Expecting the Value to show what the shopper just typed.** It shows what the cart confirms.
|
|
229
|
-
- **
|
|
242
|
+
- **Passing a `mask` to the postal code control.** There is none: the field is plain text and the country's rules validate it.
|
|
243
|
+
- **Authoring only `invalidPostalCodeMessage` for "CEP não encontrado".** A postal code the platform refuses upstream reaches the client as a network failure today, so `genericMessage` must cover it too.
|
|
230
244
|
|
|
231
245
|
---
|
|
232
246
|
|
|
233
247
|
## Related
|
|
234
248
|
|
|
235
249
|
- [[../free-shipping-progress/free-shipping-progress]] — the bar beside this component; it follows the destination write through the cache with no wiring.
|
|
236
|
-
- [[../region/region]] — the header's region control;
|
|
250
|
+
- [[../region/region]] — the header's region control; it keeps the masked postal code field and sets a cookie, with no cart write.
|
|
237
251
|
- [[../shipping-address/shipping-address]] — the full delivery address on checkout, which this component's write shares with.
|
|
238
|
-
- [[../../particles/postal-code-field/postal-code-field]] — the masked input this component composes.
|
package/dist/docs/cart-item.md
CHANGED
|
@@ -15,10 +15,11 @@ A **cart line** — a repeated row in a cart or mini-cart list: a product thumbn
|
|
|
15
15
|
|
|
16
16
|
## Composition
|
|
17
17
|
|
|
18
|
-
**`CartItemRoot` wraps the line-item template inside `CartList`.** The nesting is always:
|
|
18
|
+
**`CartItemRoot` wraps the line-item template inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.** The nesting is always:
|
|
19
19
|
|
|
20
20
|
```text
|
|
21
|
-
CartList (iterator — renders its children once per cart line
|
|
21
|
+
CartList (iterator — renders its children once per cart line; CartAvailableItems and
|
|
22
|
+
CartUnavailableItems iterate the purchasable and the unavailable lines the same way)
|
|
22
23
|
└─ CartItemRoot (per-line data provider — owns the core slice)
|
|
23
24
|
├─ CartItemImage (optionally wrapped in CartItemProductLink; see below)
|
|
24
25
|
├─ CartItemName
|
|
@@ -37,7 +38,7 @@ CartList (iterator — renders its children once per cart line)
|
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
- **`CartItemRoot` is required.** Every `CartItem*` core particle reads its data from the nearest `CartItemRoot` (build-time `requiresContext: 'cart-item-data'`). Placing a core particle directly inside `CartList` with no `CartItemRoot` between them is a build error. When authoring a cart or mini-cart line template, always insert a `CartItemRoot` between the `CartList` and the row's particles — it carries no visible styling of its own, so put the row layout classes on it (or on a `Container` inside it).
|
|
40
|
-
- **`CartItemRoot` must be inside `CartList`.** It requires the `cart-item` iteration context that
|
|
41
|
+
- **`CartItemRoot` must be inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.** It requires the `cart-item` iteration context that each of the three provides.
|
|
41
42
|
|
|
42
43
|
## Image placeholder
|
|
43
44
|
|
|
@@ -66,7 +67,7 @@ CartItemRoot
|
|
|
66
67
|
|
|
67
68
|
Navigation is client-side through the `NavigationLink` particle, which also owns `rel` hardening. The link is same-tab, and `target` is omitted from the props type rather than merely left out of the schema, because an image-only link cannot carry the "(opens in new tab)" cue a `_blank` destination needs.
|
|
68
69
|
|
|
69
|
-
**Known gap:** a mini-cart drawer does **not** dismiss itself when a client-side navigation leaves it, so the overlay stays open over the product page.
|
|
70
|
+
**Known gap:** a mini-cart drawer does **not** dismiss itself when a client-side navigation leaves it, so the overlay stays open over the product page. The product link behaves that way, and it belongs to the drawer composition, not to a line leaf. `CartGoCheckout` closes the drawer itself when it leaves for the checkout.
|
|
70
71
|
|
|
71
72
|
Renders `a[data-fs-cart-item-product-link]`, which also carries the particle's `data-fs-navigation-link`.
|
|
72
73
|
|
|
@@ -81,7 +82,7 @@ CartItemRoot
|
|
|
81
82
|
└─ CartItemRemove (removes this line from within its alert)
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
**Label-vs-children nuance:** passing children to `CartItemUnavailable` **replaces** its
|
|
85
|
+
**Label-vs-children nuance:** passing children to `CartItemUnavailable` **replaces** its state label, which is one `$content` message per state (`outOfStockLabel` for `OUT_OF_STOCK`, `cannotBeDeliveredLabel` for `UNAVAILABLE`, `unavailableLabel` for any other state; content type `cart-item-unavailable`), formatted only when no children are given. A remove-on-alert composition therefore renders the label as an explicit child (e.g. a `Text`) next to the `CartItemRemove`; nesting the remove control alone leaves the alert without a label. The whole subtree is availability-gated: when the line is `AVAILABLE`, neither the label nor the nested remove control renders.
|
|
85
86
|
|
|
86
87
|
For the cart-level counterparts (the "N items unavailable" summary and the bulk "remove all unavailable" button), see `cart.md` — Unavailable-item recovery.
|
|
87
88
|
|
|
@@ -90,8 +91,8 @@ For the cart-level counterparts (the "N items unavailable" summary and the bulk
|
|
|
90
91
|
`CartItemRemove` awaits the removal and tells the shopper when it went through:
|
|
91
92
|
|
|
92
93
|
- **Disabled while pending.** The button carries the native `disabled` attribute from the click until `removeItem` settles, so a second click sends no second request. A caller-passed `disabled` is kept.
|
|
93
|
-
- **Toast on a clean result only.** When `removeItem` resolves with an empty `userErrors` list, the button raises one `success` toast titled `removedMessage` (
|
|
94
|
-
- **`removedMessage`** is
|
|
94
|
+
- **Toast on a clean result only.** When `removeItem` resolves with an empty `userErrors` list, the button raises one `success` toast titled by the `removedMessage` message (content type `cart-item-remove`). A non-empty list, a missing `removeItem`, or a rejection raises no toast; failures keep surfacing through `CartError`.
|
|
95
|
+
- **`removedMessage`** is a `$content` field, not a prop. The toast carries the title alone: no description, no action.
|
|
95
96
|
- **Needs a `ToastProvider`.** The toast shows through the layout's `ToastList`. Without a `ToastProvider` above the line, no toast shows and the removal still works.
|
|
96
97
|
|
|
97
98
|
## Gift lines
|
|
@@ -101,17 +102,29 @@ A promotion can add a line the shopper never chose. `CartItem.gift` marks it, an
|
|
|
101
102
|
```text
|
|
102
103
|
CartItemRoot (row carries data-fs-cart-item-gift-line on a gift line)
|
|
103
104
|
├─ CartItemListPrice (renders: a gift's sellingPrice is 0, so listPrice > sellingPrice)
|
|
104
|
-
├─ CartItemGift (renders
|
|
105
|
+
├─ CartItemGift (renders its label message)
|
|
105
106
|
└─ CartItemRemove (renders nothing)
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
- **`CartItemGift`** is the free marker: a `span[data-fs-cart-item-gift][data-fs-text]` that renders **only** on a gift line, with the
|
|
109
|
+
- **`CartItemGift`** is the free marker: a `span[data-fs-cart-item-gift][data-fs-text]` that renders **only** on a gift line, with the `label` message (content type `cart-item-gift`). Passing children **replaces** the label, which is then not formatted, the same nuance `CartItemUnavailable` has. It is an **inline marker, not a wrapper** — its children are the label, so do not nest a block subtree in it. Place it beside `CartItemPrice`/`CartItemListPrice`.
|
|
109
110
|
- **`CartItemRemove` suppresses itself** on a gift line. A gift is not the shopper's to discard in this phase, and since one template serves every row, the rule lives in the component rather than in the composition. This covers the remove-on-alert composition too: an unavailable gift renders its alert with no remove control, and recovery is the cart-level `CartRemoveUnavailable` batch (which still batches gift lines) plus server-side cart validation.
|
|
110
111
|
- **`CartItemQuantity` suppresses itself** on a gift line too, the same way `CartItemRemove` does: a gift's quantity is promotion-controlled, and a `removeOnDecrement` stepper would otherwise let a shopper discard the gift by stepping it below the minimum — the one path the remove-control suppression did not cover. A store showing a gift's fixed quantity composes the read-only `CartItemQuantityValue`, which dispatches nothing.
|
|
111
112
|
- **The row is marked** with `data-fs-cart-item-gift-line`, so a swatch can restyle a gift row without a component per variation — that is how a store hides the `R$ 0,00` selling price on a gift row.
|
|
112
113
|
|
|
113
114
|
A gift whose `listPrice` is also 0 renders no list price (`CartItemListPrice`'s existing `listPrice <= sellingPrice` rule) and the marker carries the row alone.
|
|
114
115
|
|
|
116
|
+
## Copy
|
|
117
|
+
|
|
118
|
+
Every copy-bearing leaf reads its text only from its own `$content`, whose fields are ICU messages. An unauthored message renders empty and logs `message.missing`. A store without CMS authors the fields on the element; a CMS-bound store keeps them in content.
|
|
119
|
+
|
|
120
|
+
| Component | Content type | Fields |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `CartItemDiscountPercentage` | `cart-item-discount-percentage` | `template` (`percentage`, the integer percent) |
|
|
123
|
+
| `CartItemQuantity` | `cart-item-quantity` | `validationMessage` (`value`, the corrected amount) |
|
|
124
|
+
| `CartItemRemove` | `cart-item-remove` | `removedMessage` |
|
|
125
|
+
| `CartItemUnavailable` | `cart-item-unavailable` | `outOfStockLabel`, `cannotBeDeliveredLabel`, `unavailableLabel` |
|
|
126
|
+
| `CartItemGift` | `cart-item-gift` | `label` |
|
|
127
|
+
|
|
115
128
|
## Owned data
|
|
116
129
|
|
|
117
130
|
`CartItemRoot`'s core fragment owns each line's `id`, `quantity`, `price`/`listPrice`/`sellingPrice`, `gift`, `ownTotal`/`total`, `variant { variantId, sku, name, image, availability }`, and the `product` core. `variant.availability` stays here (not a sub-matter) because it is read cross-cuttingly: `CartItemAvailable`/`CartItemUnavailable` gate on it, and `CartCheckoutGuard` reads it across all lines. `gift` stays here for the same reason — `CartItemGift`, `CartItemRemove`'s suppression, and the row's state hook all read it.
|
|
@@ -137,7 +150,9 @@ The stepper shows the line's quantity **in the unit the merchant sells in**, not
|
|
|
137
150
|
|
|
138
151
|
Enforcement happens **on commit** — blur after typing, pointer release on the buttons, or a keyboard interaction — not per keystroke. A committed amount that is out of bounds or off the multiplier grid is clamped and snapped to the nearest valid amount (ties round up), then the remaining delta is dispatched as `increaseQuantity` / `decreaseQuantity` in purchasable units. No non-integer quantity can reach a mutation. Nothing is corrected at render time: a quantity already outside the authored bounds is displayed as-is and fires no write.
|
|
139
152
|
|
|
140
|
-
A snap renders a notice as the last child of the stepper: `div[role="alert"][data-fs-cart-item-quantity-validation]`, carrying the `validationMessage`
|
|
153
|
+
A snap renders a notice as the last child of the stepper: `div[role="alert"][data-fs-cart-item-quantity-validation]`, carrying the `validationMessage` message (content type `cart-item-quantity`), whose `value` argument is the corrected displayed amount, formatted in the locale. The root also carries `data-fs-cart-item-quantity-adjusted` plus `data-fs-cart-item-quantity-adjusted-reason="min" | "max" | "multiple" | "platform"` for per-reason styling, and `data-fs-cart-item-quantity-multiplier="<value>"` whenever the multiplier is not `1`, so a measured line can be styled differently from a counted one.
|
|
154
|
+
|
|
155
|
+
`"platform"` appears when the line lands below the amount the stepper asked for, after the write succeeds: the platform stores the quantity it has in stock (or the per-item limit) instead of the one requested. The notice reuses the `validationMessage` message and reports the quantity the line holds, replaces a local snap from the same commit, and goes away when the shopper types again, commits again, or the line reaches the requested amount. A write that fails (`userErrors`) raises no platform notice, though a local snap from the same commit still shows. The stepper remembers the requested amount until the next commit or typing, so a line the platform lowers on cart load shows none, but a line that later drops below an amount this stepper already asked for shows the notice again.
|
|
141
156
|
|
|
142
157
|
`removeOnDecrement`: a committed amount below the configured minimum removes the line instead of clamping, and no notice is raised. In that mode the decrement control is **not** disabled at the minimum — removal is the intended outcome there — and `data-fs-cart-item-at-min` still keys off the purchasable count. This never applies to a gift line: the stepper renders nothing there, so `removeOnDecrement` cannot discard a gift.
|
|
143
158
|
|
|
@@ -151,7 +166,7 @@ The measurement unit itself (`kg`, `un`) is not fetched, so a measured line rend
|
|
|
151
166
|
|
|
152
167
|
`CartItemDiscounts` is another **optional** per-line data owner: it owns the line's `discounts` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders one labeled row per featured promotion applied to the current cart line — the promotion `name` plus its amount (e.g. `Black Friday −R$ 20,00`, `Cupom −10%`) — so a shopper sees *which* promotion took *how much* off *this* item. It is the itemized companion to the aggregated `Discounts` totalizer line in the footer.
|
|
153
168
|
|
|
154
|
-
Each row branches on `isPercentual`: a currency discount (`false`) formats the amount from the active storefront context; a percentual discount (`true`) renders `−N%` and is **not** currency-formatted. Every amount carries a presentational leading `−` — the source `value` is a positive amount. It **renders null when the line has no discounts** (empty or unresolved), so it appears only where a promotion actually fired. Place it under the line, near the price area. Must be inside `CartList`.
|
|
169
|
+
Each row branches on `isPercentual`: a currency discount (`false`) formats the amount from the active storefront context; a percentual discount (`true`) renders `−N%` and is **not** currency-formatted. Every amount carries a presentational leading `−` — the source `value` is a positive amount. It **renders null when the line has no discounts** (empty or unresolved), so it appears only where a promotion actually fired. Place it under the line, near the price area. Must be inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.
|
|
155
170
|
|
|
156
171
|
**Distinct from `CartItemDiscountPercentage`.** `CartItemDiscountPercentage` is a single derived `−N%` **badge** computed from `listPrice`/`sellingPrice` with **no** promotion name; `CartItemDiscounts` is the **named list** of promotions sourced from the line's `discounts` field. They cover different concerns and may coexist on a line — the badge next to the price, the named list beneath it.
|
|
157
172
|
|
|
@@ -159,7 +174,7 @@ Renders a `div[data-fs-cart-item-discounts]` container with one `span[data-fs-ca
|
|
|
159
174
|
|
|
160
175
|
### CartItemCustomizations
|
|
161
176
|
|
|
162
|
-
`CartItemCustomizations` is an **optional** per-line data owner: it owns the line's `customizations` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders the form-based personalization a shopper applied to the line — engraving text, a size selection, an uploaded file's URL — as one group per assembly, each group listing its `entries` as `name` / `value` rows (e.g. `Text: MARIA`). It **renders null when the line has no customizations** (empty or unresolved). Must be inside `CartList`.
|
|
177
|
+
`CartItemCustomizations` is an **optional** per-line data owner: it owns the line's `customizations` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders the form-based personalization a shopper applied to the line — engraving text, a size selection, an uploaded file's URL — as one group per assembly, each group listing its `entries` as `name` / `value` rows (e.g. `Text: MARIA`). It **renders null when the line has no customizations** (empty or unresolved). Must be inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.
|
|
163
178
|
|
|
164
179
|
The group heading is the raw assembly `id` (e.g. `Engraving`); pretty display names are deferred (836 Decision 2). An uploaded-file value surfaces as its URL string and is rendered verbatim — there is no file-preview/download widget in v0 (836 exposes no file metadata; at parity with fastcheckout).
|
|
165
180
|
|
|
@@ -167,7 +182,7 @@ Renders a `div[data-fs-cart-item-customizations]` container with one `div[data-f
|
|
|
167
182
|
|
|
168
183
|
### CartItemCompositions
|
|
169
184
|
|
|
170
|
-
`CartItemCompositions` is an **optional** per-line data owner: it owns the line's `compositions` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders the nested bundle/assembly tree a shopper built under the line — each child row shows the child's `name`, `quantity` (`×N`), and formatted unit `price`. It **renders null when the line has no compositions** (empty or unresolved). Must be inside `CartList`.
|
|
185
|
+
`CartItemCompositions` is an **optional** per-line data owner: it owns the line's `compositions` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders the nested bundle/assembly tree a shopper built under the line — each child row shows the child's `name`, `quantity` (`×N`), and formatted unit `price`. It **renders null when the line has no compositions** (empty or unresolved). Must be inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.
|
|
171
186
|
|
|
172
187
|
**Recursion.** A composition child is itself an order-form line, so it can carry its own nested `compositions` (a sub-bundle) and its own `customizations` (836 Decision 8). The matter recurses over the in-slice `compositions` array with an internal render function: each node renders its row, its own customization groups (using the same `name`/`value` anatomy as `CartItemCustomizations`, so one swatch styles both), then its nested children at `depth + 1`. Recursion is over finite data — the server guarantees acyclic compositions (836 visited-index) and depth is bounded by the assembly config. React keys use the node `id`.
|
|
173
188
|
|
|
@@ -175,6 +190,6 @@ Renders a `div[data-fs-cart-item-compositions]` container with one `div[data-fs-
|
|
|
175
190
|
|
|
176
191
|
### CartItemVariations
|
|
177
192
|
|
|
178
|
-
`CartItemVariations` is another **optional** per-line data owner: it owns the line's `variant.selectedOptions` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders one labeled row per variation selected on the current cart line (e.g. `Cor: Vermelho`, `Tamanho: M`), so a shopper can tell two lines of the same product apart. It **renders null when the line has no selected options** (empty or unresolved), so it appears only where the SKU actually has variations. Place it near the product name. Must be inside `CartList`.
|
|
193
|
+
`CartItemVariations` is another **optional** per-line data owner: it owns the line's `variant.selectedOptions` subtree via its own `reactive-list-item` fragment and requires only `cart-item`, so its data is fetched **only** on pages that place it. It renders one labeled row per variation selected on the current cart line (e.g. `Cor: Vermelho`, `Tamanho: M`), so a shopper can tell two lines of the same product apart. It **renders null when the line has no selected options** (empty or unresolved), so it appears only where the SKU actually has variations. Place it near the product name. Must be inside `CartList`, `CartAvailableItems` or `CartUnavailableItems`.
|
|
179
194
|
|
|
180
195
|
Renders a `div[data-fs-cart-item-variations]` container with one `span[data-fs-cart-item-variation]` per option; each row wraps a `span[data-fs-cart-item-variation-name]` (e.g. `Cor`), a `span[data-fs-cart-item-variation-separator]` holding the `": "` delimiter, and a `span[data-fs-cart-item-variation-value]` (e.g. `Vermelho`). The separator is a hook of its own so a store can restyle or hide the delimiter without the punctuation riding along with the label; with no swatch applied a row still reads `Cor: Vermelho`. No props beyond the standard `div` attributes; the list is data-driven and `children` is not used to override it.
|