@vtex/faststore 0.0.1
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 +18 -0
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/actions.json +334 -0
- package/dist/catalog.json +6615 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.js +8 -0
- package/dist/components.d.ts +87 -0
- package/dist/components.js +87 -0
- package/dist/content-types.json +684 -0
- package/dist/core/dist/actions/mock-action.d.ts +24 -0
- package/dist/core/dist/actions/mock-action.js +28 -0
- package/dist/core/dist/actions/mock-action.js.map +1 -0
- package/dist/core/dist/actions/registry.d.ts +24 -0
- package/dist/core/dist/actions/registry.js +28 -0
- package/dist/core/dist/actions/registry.js.map +1 -0
- package/dist/core/dist/define-component.d.ts +100 -0
- package/dist/core/dist/define-component.js +8 -0
- package/dist/core/dist/define-component.js.map +1 -0
- package/dist/core/dist/define-content-type.d.ts +95 -0
- package/dist/core/dist/define-content-type.js +283 -0
- package/dist/core/dist/define-content-type.js.map +1 -0
- package/dist/core/dist/index.d.ts +7 -0
- package/dist/core/dist/index.js +5 -0
- package/dist/core/dist/schema/generated/schema.d.ts +28 -0
- package/dist/core/dist/types.d.ts +1 -0
- package/dist/docs/access-code-field.md +100 -0
- package/dist/docs/access-code-sign-in.md +174 -0
- package/dist/docs/account-entry-point.md +155 -0
- package/dist/docs/address-summary.md +50 -0
- package/dist/docs/buy-button.md +162 -0
- package/dist/docs/carousel.md +105 -0
- package/dist/docs/cart-item.md +162 -0
- package/dist/docs/cart-totalizer.md +197 -0
- package/dist/docs/cart.md +495 -0
- package/dist/docs/client-preferences.md +184 -0
- package/dist/docs/client-profile-form.md +192 -0
- package/dist/docs/client-profile.md +117 -0
- package/dist/docs/container.md +97 -0
- package/dist/docs/document-field.md +97 -0
- package/dist/docs/email-field.md +93 -0
- package/dist/docs/email-identification.md +102 -0
- package/dist/docs/footer-copyright.md +112 -0
- package/dist/docs/footer-link-group.md +162 -0
- package/dist/docs/footer-root.md +145 -0
- package/dist/docs/footer-social.md +151 -0
- package/dist/docs/free-shipping-progress.md +87 -0
- package/dist/docs/gallery.md +84 -0
- package/dist/docs/header-root.md +150 -0
- package/dist/docs/identity-edit.md +88 -0
- package/dist/docs/identity-summary.md +106 -0
- package/dist/docs/incentives.md +151 -0
- package/dist/docs/logo.md +135 -0
- package/dist/docs/meter.md +67 -0
- package/dist/docs/navigation-link-list.md +171 -0
- package/dist/docs/navigation-link.md +163 -0
- package/dist/docs/navigation-menu.md +264 -0
- package/dist/docs/payment-methods.md +139 -0
- package/dist/docs/phone-field.md +106 -0
- package/dist/docs/postal-code-field.md +126 -0
- package/dist/docs/pricing.md +499 -0
- package/dist/docs/product-gallery.md +409 -0
- package/dist/docs/product-information.md +295 -0
- package/dist/docs/product-list.md +170 -0
- package/dist/docs/product-quantity.md +88 -0
- package/dist/docs/product-shelf.md +141 -0
- package/dist/docs/promotion.md +109 -0
- package/dist/docs/region.md +225 -0
- package/dist/docs/session.md +123 -0
- package/dist/docs/shipping-address.md +390 -0
- package/dist/docs/shipping-simulator.md +147 -0
- package/dist/docs/sign-in-form.md +117 -0
- package/dist/docs/tabs.md +176 -0
- package/dist/docs/toast.md +124 -0
- package/dist/docs/variant-selector.md +450 -0
- package/dist/graphql/define-subgraph.d.ts +12 -0
- package/dist/graphql/define-subgraph.js +15 -0
- package/dist/graphql/define-subgraph.js.map +1 -0
- package/dist/graphql/gql.d.ts +10 -0
- package/dist/graphql/gql.js +16 -0
- package/dist/graphql/gql.js.map +1 -0
- package/dist/graphql/types.d.ts +88 -0
- package/dist/graphql.d.ts +4 -0
- package/dist/graphql.js +3 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +5 -0
- package/dist/internal/client.d.ts +24 -0
- package/dist/internal/client.js +23 -0
- package/dist/internal/content.d.ts +2 -0
- package/dist/internal/content.js +2 -0
- package/dist/internal/server.d.ts +7 -0
- package/dist/internal/server.js +6 -0
- package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +111 -0
- package/dist/matter/access-code-sign-in/access-code-sign-in.js +387 -0
- package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.d.ts +64 -0
- package/dist/matter/account-entry-point/account-entry-point.js +151 -0
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -0
- package/dist/matter/breadcrumb/breadcrumb.d.ts +40 -0
- package/dist/matter/breadcrumb/breadcrumb.js +155 -0
- package/dist/matter/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/matter/buy-button/buy-button.d.ts +95 -0
- package/dist/matter/buy-button/buy-button.js +259 -0
- package/dist/matter/buy-button/buy-button.js.map +1 -0
- package/dist/matter/cart/cart-namespace.d.ts +48 -0
- package/dist/matter/cart/cart-namespace.js +50 -0
- package/dist/matter/cart/cart-namespace.js.map +1 -0
- package/dist/matter/cart/cart.d.ts +312 -0
- package/dist/matter/cart/cart.js +1034 -0
- package/dist/matter/cart/cart.js.map +1 -0
- package/dist/matter/cart-item/cart-item.d.ts +103 -0
- package/dist/matter/cart-item/cart-item.js +672 -0
- package/dist/matter/cart-item/cart-item.js.map +1 -0
- package/dist/matter/cart-item-compositions/cart-item-compositions.d.ts +49 -0
- package/dist/matter/cart-item-compositions/cart-item-compositions.js +165 -0
- package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -0
- package/dist/matter/cart-item-customizations/cart-item-customizations.d.ts +28 -0
- package/dist/matter/cart-item-customizations/cart-item-customizations.js +73 -0
- package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -0
- package/dist/matter/cart-item-discounts/cart-item-discounts.d.ts +33 -0
- package/dist/matter/cart-item-discounts/cart-item-discounts.js +70 -0
- package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -0
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.d.ts +24 -0
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +54 -0
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -0
- package/dist/matter/cart-item-variations/cart-item-variations.d.ts +27 -0
- package/dist/matter/cart-item-variations/cart-item-variations.js +69 -0
- package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -0
- package/dist/matter/cart-totalizer/cart-totalizer.d.ts +78 -0
- package/dist/matter/cart-totalizer/cart-totalizer.js +220 -0
- package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -0
- package/dist/matter/client-preferences/client-preferences.d.ts +50 -0
- package/dist/matter/client-preferences/client-preferences.js +206 -0
- package/dist/matter/client-preferences/client-preferences.js.map +1 -0
- package/dist/matter/client-profile/client-profile.d.ts +59 -0
- package/dist/matter/client-profile/client-profile.js +185 -0
- package/dist/matter/client-profile/client-profile.js.map +1 -0
- package/dist/matter/client-profile-form/client-profile-form.d.ts +126 -0
- package/dist/matter/client-profile-form/client-profile-form.js +660 -0
- package/dist/matter/client-profile-form/client-profile-form.js.map +1 -0
- package/dist/matter/delivery-options/delivery-options-accordion.d.ts +30 -0
- package/dist/matter/delivery-options/delivery-options-accordion.js +189 -0
- package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -0
- package/dist/matter/delivery-options/delivery-options-controller.d.ts +49 -0
- package/dist/matter/delivery-options/delivery-options-controller.js +203 -0
- package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -0
- package/dist/matter/delivery-options/delivery-options.d.ts +31 -0
- package/dist/matter/delivery-options/delivery-options.js +103 -0
- package/dist/matter/delivery-options/delivery-options.js.map +1 -0
- package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +9 -0
- package/dist/matter/delivery-options/use-delivery-option-selection.js +76 -0
- package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -0
- package/dist/matter/email-identification/email-identification.d.ts +37 -0
- package/dist/matter/email-identification/email-identification.js +111 -0
- package/dist/matter/email-identification/email-identification.js.map +1 -0
- package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +44 -0
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +170 -0
- package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -0
- package/dist/matter/identity-edit/identity-edit.d.ts +52 -0
- package/dist/matter/identity-edit/identity-edit.js +148 -0
- package/dist/matter/identity-edit/identity-edit.js.map +1 -0
- package/dist/matter/identity-summary/identity-summary.d.ts +128 -0
- package/dist/matter/identity-summary/identity-summary.js +344 -0
- package/dist/matter/identity-summary/identity-summary.js.map +1 -0
- package/dist/matter/pricing/pricing.d.ts +162 -0
- package/dist/matter/pricing/pricing.js +793 -0
- package/dist/matter/pricing/pricing.js.map +1 -0
- package/dist/matter/product-gallery/product-gallery.d.ts +23 -0
- package/dist/matter/product-gallery/product-gallery.js +188 -0
- package/dist/matter/product-gallery/product-gallery.js.map +1 -0
- package/dist/matter/product-information/product-information.d.ts +61 -0
- package/dist/matter/product-information/product-information.js +355 -0
- package/dist/matter/product-information/product-information.js.map +1 -0
- package/dist/matter/product-list/product-list.d.ts +86 -0
- package/dist/matter/product-list/product-list.js +342 -0
- package/dist/matter/product-list/product-list.js.map +1 -0
- package/dist/matter/product-quantity/product-quantity.d.ts +50 -0
- package/dist/matter/product-quantity/product-quantity.js +111 -0
- package/dist/matter/product-quantity/product-quantity.js.map +1 -0
- package/dist/matter/product-shelf/product-shelf.d.ts +125 -0
- package/dist/matter/product-shelf/product-shelf.js +376 -0
- package/dist/matter/product-shelf/product-shelf.js.map +1 -0
- package/dist/matter/region/region.d.ts +211 -0
- package/dist/matter/region/region.js +579 -0
- package/dist/matter/region/region.js.map +1 -0
- package/dist/matter/session/session.d.ts +58 -0
- package/dist/matter/session/session.js +112 -0
- package/dist/matter/session/session.js.map +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +101 -0
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -0
- package/dist/matter/shipping-address/shipping-address.d.ts +284 -0
- package/dist/matter/shipping-address/shipping-address.js +1036 -0
- package/dist/matter/shipping-address/shipping-address.js.map +1 -0
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +143 -0
- package/dist/matter/shipping-simulator/shipping-simulator.js +644 -0
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -0
- package/dist/matter/sign-in-form/sign-in-form.d.ts +79 -0
- package/dist/matter/sign-in-form/sign-in-form.js +226 -0
- package/dist/matter/sign-in-form/sign-in-form.js.map +1 -0
- package/dist/matter/variant-selector/variant-selector.d.ts +183 -0
- package/dist/matter/variant-selector/variant-selector.js +840 -0
- package/dist/matter/variant-selector/variant-selector.js.map +1 -0
- package/dist/message-locales.json +7 -0
- package/dist/particles/access-code-field/access-code-field.d.ts +33 -0
- package/dist/particles/access-code-field/access-code-field.js +95 -0
- package/dist/particles/access-code-field/access-code-field.js.map +1 -0
- package/dist/particles/accordion/accordion.d.ts +45 -0
- package/dist/particles/accordion/accordion.js +156 -0
- package/dist/particles/accordion/accordion.js.map +1 -0
- package/dist/particles/address-summary/address-summary.d.ts +50 -0
- package/dist/particles/address-summary/address-summary.js +129 -0
- package/dist/particles/address-summary/address-summary.js.map +1 -0
- package/dist/particles/badge/badge.d.ts +10 -0
- package/dist/particles/badge/badge.js +27 -0
- package/dist/particles/badge/badge.js.map +1 -0
- package/dist/particles/button/button.d.ts +18 -0
- package/dist/particles/button/button.js +37 -0
- package/dist/particles/button/button.js.map +1 -0
- package/dist/particles/carousel/carousel.d.ts +60 -0
- package/dist/particles/carousel/carousel.js +335 -0
- package/dist/particles/carousel/carousel.js.map +1 -0
- package/dist/particles/checkbox/checkbox.d.ts +40 -0
- package/dist/particles/checkbox/checkbox.js +82 -0
- package/dist/particles/checkbox/checkbox.js.map +1 -0
- package/dist/particles/container/container.d.ts +20 -0
- package/dist/particles/container/container.js +36 -0
- package/dist/particles/container/container.js.map +1 -0
- package/dist/particles/dialog/dialog.d.ts +54 -0
- package/dist/particles/dialog/dialog.js +192 -0
- package/dist/particles/dialog/dialog.js.map +1 -0
- package/dist/particles/document-field/document-field.d.ts +61 -0
- package/dist/particles/document-field/document-field.js +146 -0
- package/dist/particles/document-field/document-field.js.map +1 -0
- package/dist/particles/drawer/drawer.d.ts +52 -0
- package/dist/particles/drawer/drawer.js +183 -0
- package/dist/particles/drawer/drawer.js.map +1 -0
- package/dist/particles/email-field/email-field.d.ts +37 -0
- package/dist/particles/email-field/email-field.js +106 -0
- package/dist/particles/email-field/email-field.js.map +1 -0
- package/dist/particles/field/field.d.ts +50 -0
- package/dist/particles/field/field.js +133 -0
- package/dist/particles/field/field.js.map +1 -0
- package/dist/particles/fieldset/fieldset.d.ts +16 -0
- package/dist/particles/fieldset/fieldset.js +52 -0
- package/dist/particles/fieldset/fieldset.js.map +1 -0
- package/dist/particles/footer-copyright/footer-copyright.d.ts +32 -0
- package/dist/particles/footer-copyright/footer-copyright.js +50 -0
- package/dist/particles/footer-copyright/footer-copyright.js.map +1 -0
- package/dist/particles/footer-link-group/footer-link-group.d.ts +66 -0
- package/dist/particles/footer-link-group/footer-link-group.js +154 -0
- package/dist/particles/footer-link-group/footer-link-group.js.map +1 -0
- package/dist/particles/footer-root/footer-root.d.ts +21 -0
- package/dist/particles/footer-root/footer-root.js +38 -0
- package/dist/particles/footer-root/footer-root.js.map +1 -0
- package/dist/particles/footer-social/footer-social.d.ts +79 -0
- package/dist/particles/footer-social/footer-social.js +176 -0
- package/dist/particles/footer-social/footer-social.js.map +1 -0
- package/dist/particles/gallery/gallery.d.ts +181 -0
- package/dist/particles/gallery/gallery.js +920 -0
- package/dist/particles/gallery/gallery.js.map +1 -0
- package/dist/particles/header-root/header-root.d.ts +21 -0
- package/dist/particles/header-root/header-root.js +38 -0
- package/dist/particles/header-root/header-root.js.map +1 -0
- package/dist/particles/icon/icon.d.ts +22 -0
- package/dist/particles/icon/icon.js +48 -0
- package/dist/particles/icon/icon.js.map +1 -0
- package/dist/particles/image/image.d.ts +13 -0
- package/dist/particles/image/image.js +59 -0
- package/dist/particles/image/image.js.map +1 -0
- package/dist/particles/incentives/incentives.d.ts +85 -0
- package/dist/particles/incentives/incentives.js +200 -0
- package/dist/particles/incentives/incentives.js.map +1 -0
- package/dist/particles/input/input.d.ts +9 -0
- package/dist/particles/input/input.js +28 -0
- package/dist/particles/input/input.js.map +1 -0
- package/dist/particles/logo/logo.d.ts +55 -0
- package/dist/particles/logo/logo.js +96 -0
- package/dist/particles/logo/logo.js.map +1 -0
- package/dist/particles/menu/menu.d.ts +103 -0
- package/dist/particles/menu/menu.js +409 -0
- package/dist/particles/menu/menu.js.map +1 -0
- package/dist/particles/menubar/menubar.d.ts +18 -0
- package/dist/particles/menubar/menubar.js +42 -0
- package/dist/particles/menubar/menubar.js.map +1 -0
- package/dist/particles/meter/meter.d.ts +36 -0
- package/dist/particles/meter/meter.js +132 -0
- package/dist/particles/meter/meter.js.map +1 -0
- package/dist/particles/navigation-link/navigation-link.d.ts +43 -0
- package/dist/particles/navigation-link/navigation-link.js +82 -0
- package/dist/particles/navigation-link/navigation-link.js.map +1 -0
- package/dist/particles/navigation-link-list/navigation-link-list.d.ts +59 -0
- package/dist/particles/navigation-link-list/navigation-link-list.js +103 -0
- package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -0
- package/dist/particles/navigation-menu/navigation-menu.d.ts +78 -0
- package/dist/particles/navigation-menu/navigation-menu.js +295 -0
- package/dist/particles/navigation-menu/navigation-menu.js.map +1 -0
- package/dist/particles/number-field/number-field.d.ts +46 -0
- package/dist/particles/number-field/number-field.js +169 -0
- package/dist/particles/number-field/number-field.js.map +1 -0
- package/dist/particles/password-field/password-field.d.ts +31 -0
- package/dist/particles/password-field/password-field.js +109 -0
- package/dist/particles/password-field/password-field.js.map +1 -0
- package/dist/particles/payment-methods/payment-methods.d.ts +72 -0
- package/dist/particles/payment-methods/payment-methods.js +151 -0
- package/dist/particles/payment-methods/payment-methods.js.map +1 -0
- package/dist/particles/phone-field/phone-field.d.ts +67 -0
- package/dist/particles/phone-field/phone-field.js +250 -0
- package/dist/particles/phone-field/phone-field.js.map +1 -0
- package/dist/particles/popover/popover.d.ts +68 -0
- package/dist/particles/popover/popover.js +284 -0
- package/dist/particles/popover/popover.js.map +1 -0
- package/dist/particles/postal-code-field/postal-code-field.d.ts +75 -0
- package/dist/particles/postal-code-field/postal-code-field.js +169 -0
- package/dist/particles/postal-code-field/postal-code-field.js.map +1 -0
- package/dist/particles/promotion/promotion.d.ts +46 -0
- package/dist/particles/promotion/promotion.js +78 -0
- package/dist/particles/promotion/promotion.js.map +1 -0
- package/dist/particles/quantity-selector/quantity-selector.d.ts +30 -0
- package/dist/particles/quantity-selector/quantity-selector.js +116 -0
- package/dist/particles/quantity-selector/quantity-selector.js.map +1 -0
- package/dist/particles/radio/radio.d.ts +36 -0
- package/dist/particles/radio/radio.js +76 -0
- package/dist/particles/radio/radio.js.map +1 -0
- package/dist/particles/scroll-area/scroll-area.d.ts +36 -0
- package/dist/particles/scroll-area/scroll-area.js +145 -0
- package/dist/particles/scroll-area/scroll-area.js.map +1 -0
- package/dist/particles/select/select.d.ts +125 -0
- package/dist/particles/select/select.js +478 -0
- package/dist/particles/select/select.js.map +1 -0
- package/dist/particles/separator/separator.d.ts +12 -0
- package/dist/particles/separator/separator.js +33 -0
- package/dist/particles/separator/separator.js.map +1 -0
- package/dist/particles/shared/input-mask.d.ts +5 -0
- package/dist/particles/shared/input-mask.js +58 -0
- package/dist/particles/shared/input-mask.js.map +1 -0
- package/dist/particles/spinner/spinner.d.ts +13 -0
- package/dist/particles/spinner/spinner.js +31 -0
- package/dist/particles/spinner/spinner.js.map +1 -0
- package/dist/particles/switch/switch.d.ts +27 -0
- package/dist/particles/switch/switch.js +59 -0
- package/dist/particles/switch/switch.js.map +1 -0
- package/dist/particles/tabs/tabs.d.ts +45 -0
- package/dist/particles/tabs/tabs.js +164 -0
- package/dist/particles/tabs/tabs.js.map +1 -0
- package/dist/particles/text/text.d.ts +24 -0
- package/dist/particles/text/text.js +40 -0
- package/dist/particles/text/text.js.map +1 -0
- package/dist/particles/toast/toast.d.ts +83 -0
- package/dist/particles/toast/toast.js +194 -0
- package/dist/particles/toast/toast.js.map +1 -0
- package/dist/particles/toggle/toggle.d.ts +26 -0
- package/dist/particles/toggle/toggle.js +61 -0
- package/dist/particles/toggle/toggle.js.map +1 -0
- package/dist/particles/tooltip/tooltip.d.ts +61 -0
- package/dist/particles/tooltip/tooltip.js +240 -0
- package/dist/particles/tooltip/tooltip.js.map +1 -0
- package/dist/schema.graphql +2953 -0
- package/dist/sdk/actions/cart-action-provider.d.ts +19 -0
- package/dist/sdk/actions/cart-action-provider.js +23 -0
- package/dist/sdk/actions/cart-action-provider.js.map +1 -0
- package/dist/sdk/actions/identity-action-provider.d.ts +15 -0
- package/dist/sdk/actions/identity-action-provider.js +19 -0
- package/dist/sdk/actions/identity-action-provider.js.map +1 -0
- package/dist/sdk/actions/index.d.ts +7 -0
- package/dist/sdk/actions/index.js +6 -0
- package/dist/sdk/actions/inject-actions.d.ts +14 -0
- package/dist/sdk/actions/inject-actions.js +36 -0
- package/dist/sdk/actions/inject-actions.js.map +1 -0
- package/dist/sdk/actions/region-action-provider.d.ts +15 -0
- package/dist/sdk/actions/region-action-provider.js +19 -0
- package/dist/sdk/actions/region-action-provider.js.map +1 -0
- package/dist/sdk/actions/session-action-provider.d.ts +15 -0
- package/dist/sdk/actions/session-action-provider.js +19 -0
- package/dist/sdk/actions/session-action-provider.js.map +1 -0
- package/dist/sdk/actions/shipping-action-provider.d.ts +15 -0
- package/dist/sdk/actions/shipping-action-provider.js +19 -0
- package/dist/sdk/actions/shipping-action-provider.js.map +1 -0
- package/dist/sdk/actions/types.d.ts +21 -0
- package/dist/sdk/cache/storefront-cache.js +35 -0
- package/dist/sdk/cache/storefront-cache.js.map +1 -0
- package/dist/sdk/cart/operations.d.ts +31 -0
- package/dist/sdk/cart/operations.js +215 -0
- package/dist/sdk/cart/operations.js.map +1 -0
- package/dist/sdk/cart/optimistic.d.ts +24 -0
- package/dist/sdk/cart/optimistic.js +164 -0
- package/dist/sdk/cart/optimistic.js.map +1 -0
- package/dist/sdk/cart/use-cart-actions.d.ts +56 -0
- package/dist/sdk/cart/use-cart-actions.js +348 -0
- package/dist/sdk/cart/use-cart-actions.js.map +1 -0
- package/dist/sdk/cart/use-cart-validate-on-open.js +50 -0
- package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -0
- package/dist/sdk/cart/write-gate.js +54 -0
- package/dist/sdk/cart/write-gate.js.map +1 -0
- package/dist/sdk/client/assert-api-url.js +20 -0
- package/dist/sdk/client/assert-api-url.js.map +1 -0
- package/dist/sdk/client/create-client.d.ts +23 -0
- package/dist/sdk/client/create-client.js +46 -0
- package/dist/sdk/client/create-client.js.map +1 -0
- package/dist/sdk/client/fetch-page-data.d.ts +39 -0
- package/dist/sdk/client/fetch-page-data.js +33 -0
- package/dist/sdk/client/fetch-page-data.js.map +1 -0
- package/dist/sdk/client/register-preload-query.d.ts +24 -0
- package/dist/sdk/client/register-preload-query.js +33 -0
- package/dist/sdk/client/register-preload-query.js.map +1 -0
- package/dist/sdk/content/create-content-runtime.d.ts +68 -0
- package/dist/sdk/content/create-content-runtime.js +503 -0
- package/dist/sdk/content/create-content-runtime.js.map +1 -0
- package/dist/sdk/context/headers.d.ts +15 -0
- package/dist/sdk/context/headers.js +21 -0
- package/dist/sdk/context/headers.js.map +1 -0
- package/dist/sdk/context/storefront-context.d.ts +11 -0
- package/dist/sdk/context/storefront-context.js +29 -0
- package/dist/sdk/context/storefront-context.js.map +1 -0
- package/dist/sdk/data/data-override-context.d.ts +12 -0
- package/dist/sdk/data/data-override-context.js +19 -0
- package/dist/sdk/data/data-override-context.js.map +1 -0
- package/dist/sdk/data/entity-subscriber.js +28 -0
- package/dist/sdk/data/entity-subscriber.js.map +1 -0
- package/dist/sdk/data/hot-data-provider.d.ts +19 -0
- package/dist/sdk/data/hot-data-provider.js +33 -0
- package/dist/sdk/data/hot-data-provider.js.map +1 -0
- package/dist/sdk/data/index.d.ts +8 -0
- package/dist/sdk/data/index.js +8 -0
- package/dist/sdk/data/list-item-ref-context.d.ts +20 -0
- package/dist/sdk/data/list-item-ref-context.js +11 -0
- package/dist/sdk/data/list-item-ref-context.js.map +1 -0
- package/dist/sdk/data/multiple-reactive-data-provider.d.ts +32 -0
- package/dist/sdk/data/multiple-reactive-data-provider.js +20 -0
- package/dist/sdk/data/multiple-reactive-data-provider.js.map +1 -0
- package/dist/sdk/data/page-reactive-data-root.d.ts +53 -0
- package/dist/sdk/data/page-reactive-data-root.js +153 -0
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -0
- package/dist/sdk/data/reactive-data-provider.d.ts +25 -0
- package/dist/sdk/data/reactive-data-provider.js +24 -0
- package/dist/sdk/data/reactive-data-provider.js.map +1 -0
- package/dist/sdk/data/reactive-list-item-data-provider.d.ts +26 -0
- package/dist/sdk/data/reactive-list-item-data-provider.js +42 -0
- package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -0
- package/dist/sdk/data/use-reactive-entity.js +40 -0
- package/dist/sdk/data/use-reactive-entity.js.map +1 -0
- package/dist/sdk/format/client.d.ts +12 -0
- package/dist/sdk/format/client.js +20 -0
- package/dist/sdk/format/client.js.map +1 -0
- package/dist/sdk/format/formatters.d.ts +32 -0
- package/dist/sdk/format/formatters.js +45 -0
- package/dist/sdk/format/formatters.js.map +1 -0
- package/dist/sdk/generated/fragment-types.js +23 -0
- package/dist/sdk/generated/fragment-types.js.map +1 -0
- package/dist/sdk/generated/gql.js +51 -0
- package/dist/sdk/generated/gql.js.map +1 -0
- package/dist/sdk/generated/graphql.d.ts +622 -0
- package/dist/sdk/generated/graphql.js +11917 -0
- package/dist/sdk/generated/graphql.js.map +1 -0
- package/dist/sdk/graphql-tag.d.ts +10 -0
- package/dist/sdk/graphql-tag.js +21 -0
- package/dist/sdk/graphql-tag.js.map +1 -0
- package/dist/sdk/i18n/client.d.ts +4 -0
- package/dist/sdk/i18n/client.js +4 -0
- package/dist/sdk/i18n/locales.d.ts +8 -0
- package/dist/sdk/i18n/locales.js +57 -0
- package/dist/sdk/i18n/locales.js.map +1 -0
- package/dist/sdk/i18n/messages/en-US.js +24 -0
- package/dist/sdk/i18n/messages/en-US.js.map +1 -0
- package/dist/sdk/i18n/messages/en-US.json +19 -0
- package/dist/sdk/i18n/messages/en-US.json.d.ts +23 -0
- package/dist/sdk/i18n/messages/es-ES.js +24 -0
- package/dist/sdk/i18n/messages/es-ES.js.map +1 -0
- package/dist/sdk/i18n/messages/es-ES.json +19 -0
- package/dist/sdk/i18n/messages/pt-BR.js +24 -0
- package/dist/sdk/i18n/messages/pt-BR.js.map +1 -0
- package/dist/sdk/i18n/messages/pt-BR.json +19 -0
- package/dist/sdk/i18n/provider.d.ts +1 -0
- package/dist/sdk/i18n/provider.js +30 -0
- package/dist/sdk/i18n/provider.js.map +1 -0
- package/dist/sdk/i18n/server.d.ts +28 -0
- package/dist/sdk/i18n/server.js +59 -0
- package/dist/sdk/i18n/server.js.map +1 -0
- package/dist/sdk/identity/operations.d.ts +34 -0
- package/dist/sdk/identity/operations.js +78 -0
- package/dist/sdk/identity/operations.js.map +1 -0
- package/dist/sdk/identity/use-identity-actions.d.ts +62 -0
- package/dist/sdk/identity/use-identity-actions.js +180 -0
- package/dist/sdk/identity/use-identity-actions.js.map +1 -0
- package/dist/sdk/provider/index.d.ts +2 -0
- package/dist/sdk/provider/index.js +2 -0
- package/dist/sdk/provider/storefront-provider.d.ts +32 -0
- package/dist/sdk/provider/storefront-provider.js +111 -0
- package/dist/sdk/provider/storefront-provider.js.map +1 -0
- package/dist/sdk/region/operations.d.ts +6 -0
- package/dist/sdk/region/region-operations.d.ts +30 -0
- package/dist/sdk/region/region-operations.js +23 -0
- package/dist/sdk/region/region-operations.js.map +1 -0
- package/dist/sdk/region/use-region-actions.d.ts +23 -0
- package/dist/sdk/region/use-region-actions.js +66 -0
- package/dist/sdk/region/use-region-actions.js.map +1 -0
- package/dist/sdk/seller.js +11 -0
- package/dist/sdk/seller.js.map +1 -0
- package/dist/sdk/session/auth-operations.d.ts +47 -0
- package/dist/sdk/session/auth-operations.js +79 -0
- package/dist/sdk/session/auth-operations.js.map +1 -0
- package/dist/sdk/session/operations.d.ts +6 -0
- package/dist/sdk/session/use-session-actions.d.ts +27 -0
- package/dist/sdk/session/use-session-actions.js +126 -0
- package/dist/sdk/session/use-session-actions.js.map +1 -0
- package/dist/sdk/shipping/cart-operations.d.ts +3 -0
- package/dist/sdk/shipping/cart-operations.js +33 -0
- package/dist/sdk/shipping/cart-operations.js.map +1 -0
- package/dist/sdk/shipping/operations.d.ts +3 -0
- package/dist/sdk/shipping/operations.js +33 -0
- package/dist/sdk/shipping/operations.js.map +1 -0
- package/dist/sdk/shipping/option-select-operations.d.ts +24 -0
- package/dist/sdk/shipping/option-select-operations.js +45 -0
- package/dist/sdk/shipping/option-select-operations.js.map +1 -0
- package/dist/sdk/shipping/request-timeout.js +41 -0
- package/dist/sdk/shipping/request-timeout.js.map +1 -0
- package/dist/sdk/shipping/shipping-operations.d.ts +38 -0
- package/dist/sdk/shipping/shipping-operations.js +77 -0
- package/dist/sdk/shipping/shipping-operations.js.map +1 -0
- package/dist/sdk/shipping/use-cart-shipping-simulation.d.ts +7 -0
- package/dist/sdk/shipping/use-cart-shipping-simulation.js +72 -0
- package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -0
- package/dist/sdk/shipping/use-shipping-actions.d.ts +27 -0
- package/dist/sdk/shipping/use-shipping-actions.js +113 -0
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -0
- package/dist/sdk/shipping/use-shipping-simulation.d.ts +7 -0
- package/dist/sdk/shipping/use-shipping-simulation.js +72 -0
- package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -0
- package/dist/sdk/state/cart.d.ts +42 -0
- package/dist/sdk/state/cart.js +64 -0
- package/dist/sdk/state/cart.js.map +1 -0
- package/dist/sdk/state/index.js +3 -0
- package/dist/sdk/state/variant-selector.d.ts +17 -0
- package/dist/sdk/state/variant-selector.js +14 -0
- package/dist/sdk/state/variant-selector.js.map +1 -0
- package/dist/utils/safe-href.js +63 -0
- package/dist/utils/safe-href.js.map +1 -0
- package/package.json +84 -0
- package/src/styles/tailwind.css +32 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# ProductInformation
|
|
2
|
+
|
|
3
|
+
**Category:** commerce
|
|
4
|
+
**Purpose:** Renders textual product information on a PDP — title, description, brand, SKU, and reference ID. Reads from the active product via GraphQL fragment.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Visual cues (how to identify in an image)
|
|
9
|
+
|
|
10
|
+
A ProductInformation block is present when you see:
|
|
11
|
+
|
|
12
|
+
- The **product name / title** rendered as a heading.
|
|
13
|
+
- A **brand name** near the title.
|
|
14
|
+
- A **product description** — short or long paragraph(s) of text.
|
|
15
|
+
- A **SKU or reference code** label (e.g. "Ref: 12345", "SKU: ABC-001").
|
|
16
|
+
|
|
17
|
+
Each of these is a separate sub-component. Include only the ones visible in the image.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## When to use
|
|
22
|
+
|
|
23
|
+
- PDP product information block — the canonical use.
|
|
24
|
+
|
|
25
|
+
## When NOT to use
|
|
26
|
+
|
|
27
|
+
- Product shelf / PLP cards — use a shelf-specific title component.
|
|
28
|
+
- Cart item names — use `CartItemName`.
|
|
29
|
+
- Static text unrelated to a product — use a plain layout text element.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Composition
|
|
34
|
+
|
|
35
|
+
`ProductInformationRoot` declares `providesContext: 'product-information'`. Every sub-component declares `requiresContext: 'product-information'`, so the schema compiler rejects any page where a `ProductInformation*` sub-component is not nested inside **any element whose component provides that context** (`ContextConstraintError` — fails the build before any file is emitted). The check is contract-based: a `B2BProductInformationRoot` (or any future variant) that declares the same `providesContext: 'product-information'` value substitutes for `ProductInformationRoot` with no edit to the consumers. Each sub-component also renders `null` when its data field is absent — include only what is visible in the image.
|
|
36
|
+
|
|
37
|
+
Child order reflects visual order — place sub-components in the same sequence they appear in the image.
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
<any element with providesContext: 'product-information'> # ProductInformationRoot, B2BProductInformationRoot, …
|
|
41
|
+
├── ProductInformationBrand (renders only when brand or vendor is present)
|
|
42
|
+
├── ProductInformationTitle (always renders when data is available)
|
|
43
|
+
├── ProductInformationDescription (renders only when description exists)
|
|
44
|
+
├── ProductInformationSku (renders only when variants exist)
|
|
45
|
+
└── ProductInformationReferenceId (renders only when referenceId exists)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Any subset, any order. Intermediate containers (e.g. `Container`) between the provider and the sub-components are fine — the contract is "some ancestor provides it", not "the immediate parent provides it".
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Components
|
|
53
|
+
|
|
54
|
+
### ProductInformationRoot
|
|
55
|
+
|
|
56
|
+
Root container. Declares the GraphQL fragment and provides context to all descendants. Reads `$data` reactively through the data-override context — when a future SKU Selector writes a new selected variant into the cache, the Root recomposes its subtree without a refetch.
|
|
57
|
+
|
|
58
|
+
No schema props — it is a pure data provider.
|
|
59
|
+
|
|
60
|
+
**Data:** declares `fragment ProductInformationData on Query`. Fetches: `id`, `title`, `description`, `descriptionHtml`, `referenceId`, `vendor`, `brand.name`, the first variant's `id` / `sku` / `name`, and `seo.title`. `variant.name` powers `ProductInformationTitle`'s `separator` composition; `seo.title` is exposed on the context for the future page-level `<title>` resolver (no current sub-component reads it).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### ProductInformationTitle
|
|
65
|
+
|
|
66
|
+
Renders the product title. Always renders when inside a Root with valid data.
|
|
67
|
+
|
|
68
|
+
| Prop | Type | Default | Notes |
|
|
69
|
+
|------|------|---------|-------|
|
|
70
|
+
| `as` | `h1\|h2\|h3\|h4\|h5\|h6` | `h1` | HTML tag to render. Use `h1` on the PDP. Use `h2` or lower when embedded in a card or secondary context. Non-heading tags are rejected so the PDP keeps its heading hierarchy. |
|
|
71
|
+
| `separator` | string | _unset_ | When set **and** a variant with a non-null `name` is selected, the rendered text composes as `${title}${separator}${variant.name}` — e.g. `Running Shoe - Red, Size 10`. Without `separator`, or when the variant has no name, the title renders alone. Leave unset on PDPs that have no SKU Selector. The merchant picks the visible delimiter (`" - "`, `" · "`, `" — "`, `"/"`, …). An empty string is a valid value — it concatenates without a delimiter. |
|
|
72
|
+
|
|
73
|
+
Emits `data-fs-product-information-title-as={as}` (alongside the existing `data-fs-product-information-title=""` presence attribute) for per-heading-level styling — e.g. `data-[fs-product-information-title-as=h2]:text-xl` applies only to title instances rendered as `<h2>`.
|
|
74
|
+
|
|
75
|
+
**Composition truth table** (only relevant when the page also wires a SKU Selector via the data layer):
|
|
76
|
+
|
|
77
|
+
| `separator` | `variant.name` | Rendered text |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| _unset_ | any | `title` |
|
|
80
|
+
| set | `null` or `""` | `title` |
|
|
81
|
+
| set to `" - "` | `"Red, Size 10"` | `"title - Red, Size 10"` |
|
|
82
|
+
| set to `""` | `"Red, Size 10"` | `"titleRed, Size 10"` |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### ProductInformationDescription
|
|
87
|
+
|
|
88
|
+
Renders the product description, optionally collapsed behind a "show more" toggle.
|
|
89
|
+
|
|
90
|
+
| Prop | Type | Default | Notes |
|
|
91
|
+
|------|------|---------|-------|
|
|
92
|
+
| `format` | `'auto' \| 'plain' \| 'html'` | `'auto'` | Selects which source to render. `'auto'` prefers `descriptionHtml` and falls back to plain `description`. `'plain'` renders only `description` and never reads HTML. `'html'` renders only `descriptionHtml` via `dangerouslySetInnerHTML` and is strict — it never falls back. Returns nothing when the selected source is absent. |
|
|
93
|
+
| `collapse` | `'none' \| 'showMore' \| 'section'` | `'none'` | Selects the collapse pattern. `'none'` renders the full block with no toggle (today's behavior). `'showMore'` clamps the body to `collapsedLines` and reveals the rest with a trigger that flips the clamp. `'section'` collapses the whole panel behind one trigger; the body uses Base UI Collapsible with `hidden="until-found"` so the full text stays in the SSR DOM and remains indexable. |
|
|
94
|
+
| `defaultExpanded` | boolean | `true` | Initial open state for the panel. Only consulted when `collapse !== 'none'`. SSR-safe. |
|
|
95
|
+
| `collapsedLines` | number | `4` | Line count for the CSS clamp in `'showMore'` mode. Ignored for `'none'` and `'section'`. |
|
|
96
|
+
| `moreLabel` | string | `'Show more'` | Trigger label shown when the panel is collapsed. Localize per storefront (e.g. `'mais informações'` for pt-BR). |
|
|
97
|
+
| `lessLabel` | string | `'Show less'` | Trigger label shown when the panel is expanded (e.g. `'menos informações'`). |
|
|
98
|
+
|
|
99
|
+
The wrapper element follows from the resolved branch: plain text renders as `<p>` (semantic body-text exposure for screen-reader paragraph navigation and SEO); rich HTML renders as `<div>` so block-level markup inside `descriptionHtml` (`<p>`, `<ul>`, headings) stays valid DOM. The element that hosts the rendered description text carries `data-fs-text=""` so project-level `Text` typography defined in `global.json` cascades to the description automatically — no need to repeat font, size, color, leading, or tracking classes inline on every description node. With `collapse: 'none'` that element is the wrapper itself; with `collapse: 'showMore'` or `'section'` it is the panel (the `Collapsible.Root` and the trigger `<button>` deliberately do not carry it so body typography does not cascade onto the trigger label).
|
|
100
|
+
|
|
101
|
+
Rich HTML is rendered via `dangerouslySetInnerHTML`; Storefront API Core sanitizes `descriptionHtml` upstream, so this is safe for first-party catalogs.
|
|
102
|
+
|
|
103
|
+
When `collapse !== 'none'` the component renders a Base UI Collapsible: the root carries `data-fs-product-information-description-collapse={collapse}`, the trigger carries `data-fs-product-information-description-trigger=""`, and the panel carries `data-fs-product-information-description-panel=""`. Use these attributes from Tailwind arbitrary-attribute variants to style trigger and panel without sniffing tags — e.g. `[&_[data-fs-product-information-description-trigger]]:text-blue-600`.
|
|
104
|
+
|
|
105
|
+
The keyboard contract is owned by Base UI Collapsible: Enter / Space toggle the panel and `aria-expanded` flips. In `'showMore'`, the trigger always references the panel via `aria-controls`; in `'section'`, Base UI follows APG Disclosure behavior and omits `aria-controls` while collapsed. SSR keeps the full description text in the source HTML in every collapse state. For `'showMore'` the panel is a visible-but-clamped `<div>`, so the text is fully crawlable in the pre-hydration HTML. For `'section'` the panel ships with `hidden=""` server-side and is promoted to `hidden="until-found"` by Base UI's hydration effect, which lets JS-aware crawlers (including Google) reveal it via in-page find.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### ProductInformationBrand
|
|
110
|
+
|
|
111
|
+
Renders the brand name. Prefers `brand.name`; falls back to `vendor`. Returns `null` when both are absent. No props.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### ProductInformationSku
|
|
116
|
+
|
|
117
|
+
Renders the first-variant SKU code. Returns `null` when the product has no variants. No props.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### ProductInformationReferenceId
|
|
122
|
+
|
|
123
|
+
Renders the merchant reference ID. Returns `null` when absent. No props.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Canonical schema example
|
|
128
|
+
|
|
129
|
+
A full PDP information block — brand, title, and description visible:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"product-info": {
|
|
134
|
+
"type": "ProductInformationRoot",
|
|
135
|
+
"children": ["product-brand", "product-title", "product-description"]
|
|
136
|
+
},
|
|
137
|
+
"product-brand": { "type": "ProductInformationBrand" },
|
|
138
|
+
"product-title": { "type": "ProductInformationTitle", "props": { "as": "h1" } },
|
|
139
|
+
"product-description": { "type": "ProductInformationDescription" }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Minimal variant — title only:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"product-info": {
|
|
148
|
+
"type": "ProductInformationRoot",
|
|
149
|
+
"children": ["product-title"]
|
|
150
|
+
},
|
|
151
|
+
"product-title": { "type": "ProductInformationTitle", "props": { "as": "h1" } }
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
With SKU and reference ID visible:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"product-info": {
|
|
160
|
+
"type": "ProductInformationRoot",
|
|
161
|
+
"children": ["product-title", "product-sku", "product-ref"]
|
|
162
|
+
},
|
|
163
|
+
"product-title": { "type": "ProductInformationTitle", "props": { "as": "h1" } },
|
|
164
|
+
"product-sku": { "type": "ProductInformationSku" },
|
|
165
|
+
"product-ref": { "type": "ProductInformationReferenceId" }
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Composed title — page has a SKU Selector and the visible heading reads `"<product name> - <variant name>"`:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"product-info": {
|
|
174
|
+
"type": "ProductInformationRoot",
|
|
175
|
+
"children": ["product-title"]
|
|
176
|
+
},
|
|
177
|
+
"product-title": {
|
|
178
|
+
"type": "ProductInformationTitle",
|
|
179
|
+
"props": { "as": "h1", "separator": " - " }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Description with inline "show more" — a clamped description followed by a `'mais informações'` link that flips the clamp:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"product-info": {
|
|
189
|
+
"type": "ProductInformationRoot",
|
|
190
|
+
"children": ["product-title", "product-description"]
|
|
191
|
+
},
|
|
192
|
+
"product-title": { "type": "ProductInformationTitle", "props": { "as": "h1" } },
|
|
193
|
+
"product-description": {
|
|
194
|
+
"type": "ProductInformationDescription",
|
|
195
|
+
"props": {
|
|
196
|
+
"format": "html",
|
|
197
|
+
"collapse": "showMore",
|
|
198
|
+
"defaultExpanded": false,
|
|
199
|
+
"collapsedLines": 4,
|
|
200
|
+
"moreLabel": "mais informações",
|
|
201
|
+
"lessLabel": "menos informações"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Description as a collapsible section — PDP where the body sits behind a single toggle and the full text remains crawlable via `hidden="until-found"`. Use this when the design hides the description behind an explicit "show more" / "read full description" affordance rather than clamping it inline:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"pdp-description": {
|
|
212
|
+
"type": "ProductInformationRoot",
|
|
213
|
+
"children": ["pdp-description-body"]
|
|
214
|
+
},
|
|
215
|
+
"pdp-description-body": {
|
|
216
|
+
"type": "ProductInformationDescription",
|
|
217
|
+
"props": {
|
|
218
|
+
"format": "html",
|
|
219
|
+
"collapse": "section",
|
|
220
|
+
"defaultExpanded": false,
|
|
221
|
+
"moreLabel": "Ver descrição completa",
|
|
222
|
+
"lessLabel": "Ocultar descrição"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Common mistakes
|
|
231
|
+
|
|
232
|
+
- **Inventing `ProductTitle` or `ProductName`.** The correct name is `ProductInformationTitle`. There is no standalone `ProductTitle`.
|
|
233
|
+
- **Inventing `ProductDescription`.** The correct name is `ProductInformationDescription`.
|
|
234
|
+
- **Using `ProductInformationTitle` outside an element providing `product-information` context.** The schema compiler rejects the page with `ContextConstraintError` before emitting any file; the runtime context guard still throws if the component is rendered outside a provider through a non-compiler path (Storybook, tests). All sub-components require an ancestor that declares `providesContext: 'product-information'` — typically `ProductInformationRoot`.
|
|
235
|
+
- **Using `as="h1"` when the block is embedded in a card or secondary section.** Reserve `h1` for the main PDP heading; use `h2` or lower elsewhere.
|
|
236
|
+
- **Setting `as` to a non-heading tag like `as="div"` or `as="span"`.** The Title is always a heading — only `h1`–`h6` are accepted. Non-heading values are rejected at the type level (FSPG-628) so the PDP cannot silently lose its `<h1>`. If you need the title to *look* like body text, style it with `text-base font-normal` (or your equivalent swatch); keep the semantic tag as a heading.
|
|
237
|
+
- **Including `ProductInformationSku` or `ProductInformationReferenceId` when not visible in the image.** They render `null` silently, but add noise to the schema. Only include what's shown.
|
|
238
|
+
- **Setting `separator` on a PDP that has no SKU Selector.** The variant half stays inert (the cache is never written) and the title renders alone. In production a `console.warn` fires once when the null state persists across renders (NFR-3 — the SigNoz alert is a follow-up). Either add the SKU Selector or omit `separator`.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Styling
|
|
243
|
+
|
|
244
|
+
Style `ProductInformationRoot` as the text-block layout and each sub-component as its own typographic line. Read font size, weight, and color off the image.
|
|
245
|
+
|
|
246
|
+
### ProductInformationRoot
|
|
247
|
+
|
|
248
|
+
Stacks the title, description, and other lines. Typical: `flex flex-col gap-[4px] w-full` (use a larger gap like `gap-[8px]` when the image shows the lines spaced apart).
|
|
249
|
+
|
|
250
|
+
### ProductInformationTitle
|
|
251
|
+
|
|
252
|
+
The main heading — large and bold. Typical: `text-[20px] leading-[1.3] font-semibold text-[#1A1A1A] tracking-[-0.005em] m-0`. Scale `text-[...]` to the heading size in the image; read the ink color as an arbitrary hex.
|
|
253
|
+
|
|
254
|
+
### ProductInformationDescription
|
|
255
|
+
|
|
256
|
+
Body copy — smaller, lighter, comfortable line height. Typical: `text-[14px] leading-[1.6] font-normal text-[#666666]`. The element that hosts the text carries `data-fs-text=""` in every collapse mode (the wrapper itself for `collapse: 'none'`, the panel for `'showMore'` and `'section'`), so if the project's `global.json` defines `Text.base` with the body-text typography (font, size, leading, weight, color), those styles cascade to the description automatically and no inline typography classes are needed on the description node.
|
|
257
|
+
|
|
258
|
+
When `collapse` is `'showMore'` or `'section'`, the trigger element is a real `<button>` rendered as a sibling of the panel inside the Collapsible root. Style it via the `data-fs-product-information-description-trigger` attribute hook so the trigger inherits the description's flex container without being centered or stretched. Typical: `[&_[data-fs-product-information-description-trigger]]:self-start [&_[data-fs-product-information-description-trigger]]:text-[14px] [&_[data-fs-product-information-description-trigger]]:font-medium [&_[data-fs-product-information-description-trigger]]:underline`. Pair with the brand's link color via an arbitrary hex (e.g. `[&_[data-fs-product-information-description-trigger]]:text-[#e60014]`).
|
|
259
|
+
|
|
260
|
+
### ProductInformationBrand / Sku / ReferenceId
|
|
261
|
+
|
|
262
|
+
Secondary labels — small and muted. Typical: `text-[12px] leading-[1.4] font-normal text-[#8A8A8A]`. Use `uppercase tracking-[0.04em]` for an eyebrow-style brand label when the image shows it that way.
|
|
263
|
+
|
|
264
|
+
Styled example — brand, title, and description visible:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"product-info": {
|
|
269
|
+
"type": "ProductInformationRoot",
|
|
270
|
+
"children": ["product-brand", "product-title", "product-description"],
|
|
271
|
+
"style": ["flex", "flex-col", "gap-[4px]", "w-full"]
|
|
272
|
+
},
|
|
273
|
+
"product-brand": {
|
|
274
|
+
"type": "ProductInformationBrand",
|
|
275
|
+
"style": ["text-[12px]", "leading-[1.4]", "font-normal", "text-[#8A8A8A]", "uppercase", "tracking-[0.04em]"]
|
|
276
|
+
},
|
|
277
|
+
"product-title": {
|
|
278
|
+
"type": "ProductInformationTitle",
|
|
279
|
+
"props": { "as": "h1" },
|
|
280
|
+
"style": ["text-[20px]", "leading-[1.3]", "font-semibold", "text-[#1A1A1A]", "tracking-[-0.005em]", "m-0"]
|
|
281
|
+
},
|
|
282
|
+
"product-description": {
|
|
283
|
+
"type": "ProductInformationDescription",
|
|
284
|
+
"style": ["text-[14px]", "leading-[1.6]", "font-normal", "text-[#666666]"]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Related
|
|
292
|
+
|
|
293
|
+
- [[pricing]] — price block, sibling on the PDP.
|
|
294
|
+
- [[product-gallery]] — media gallery block, sibling on the PDP.
|
|
295
|
+
- [[buy-button]] — purchase action, sibling on the PDP.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# ProductList (card content parts)
|
|
2
|
+
|
|
3
|
+
**Category:** commerce
|
|
4
|
+
**Purpose:** The product-list matter and its **card content parts** — the pieces that render one product inside a repeated card. `ProductListRoot` provides a prop-driven products context (the PLP case); `ProductListGrid` repeats a card template one row per product. The card leaves — `ProductCardImage`, `ProductCardName`, `ProductCardPrice`, `ProductCardListPrice` — read a single product from the per-item context and render it. These same leaves are **source-agnostic**: they render identically under the PLP grid and under `ProductShelfItems` (the facet-sourced `ProductShelf`), because both publish the same per-item context.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
- **`ProductListRoot` + `ProductListGrid`**: a prop-driven product list (e.g. a PLP fed by the route/search), where the products are supplied to the root and each is rendered with a shared card template.
|
|
11
|
+
- **The `ProductCard*` content parts**: any card composition — under the PLP grid or under a `ProductShelf` — that needs the product image, name, selling price, and list price.
|
|
12
|
+
|
|
13
|
+
## When NOT to use
|
|
14
|
+
|
|
15
|
+
- A facet-sourced, data-owning shelf → use `ProductShelfRoot` (it owns a `products(filter:)` fragment); compose these same card parts inside its `ProductShelfItems`.
|
|
16
|
+
- PDP single-product pricing → use `PricingRoot`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Behavior model
|
|
21
|
+
|
|
22
|
+
- **Two context boundaries.** The root owns the products + tax-display config; each row owns exactly one item. Card leaves read the item through a guarded hook (`useProductListItem()`, which throws when used outside a grid/items row) and never take list-shaped props.
|
|
23
|
+
- **Content comes from the catalog.** `ProductCardName` renders `item.name` (the product title) and the prices render `item.price` / `item.listPrice` — never a manually authored CMS field.
|
|
24
|
+
- **List-price presence is state-driven.** `ProductCardListPrice` renders **only** when `item.listPrice > item.price`; otherwise it returns nothing. There is no `showListPrice` prop — composition decides the part *can* appear, item state decides it *does*.
|
|
25
|
+
- **Currency is resolved per item.** Both price leaves format with `item.currency ?? context.currency`, using the active storefront context's locale for number formatting, so the selling price and list price always agree on currency. The price *value* already reflects the session's sales channel / trade policy / price table via the data source.
|
|
26
|
+
- **Image layout is configurable.** `ProductCardImage` exposes `aspectRatio` (e.g. `1/1`, `3/4`, `16/9`) and `objectFit`; they are orthogonal — `aspectRatio` sizes the box, `objectFit` fits the pixels. Alt text comes from `item.image.alt` (the catalog alt text, falling back to the product name at the data source).
|
|
27
|
+
- **Availability is a derived card state.** The optional `ProductCard` wrapper emits `data-fs-product-card-out-of-stock` when `item.availableForSale === false || item.availableQuantity === 0` (unset ⇒ in stock), so a swatch can grey / reduce the opacity of the whole card. It is a derived state attribute, not a boolean prop, and the wrapper never suppresses its children — price and discount still render on an out-of-stock card. Dropping unavailable products entirely is the shelf's `availableOnly` config (`ProductShelfRoot`, T2), not a card concern.
|
|
28
|
+
- **The card border is a style toggle.** The `ProductCard` wrapper also takes a `bordered` prop (default `true`) and reflects it onto `data-fs-product-card-bordered` (`"true"` / `"false"`, always present). A border is not an independently placeable part, so it is a boolean appearance config, not compose-or-omit; the actual border look is a swatch keyed off the attribute value — the component ships none. Because the attribute carries an explicit value, a swatch can style both the bordered and the unbordered case (`[data-fs-product-card-bordered='true']` / `'false']`). It is orthogonal to the out-of-stock state and does not affect children.
|
|
29
|
+
- **Tax display is a config.** When the root config `usePriceWithTaxes` is on, `ProductCardPrice` and `ProductCardListPrice` render **tax-inclusive** values — `base × (1 + rate)` with `rate = item.taxPercentage ?? item.tax / item.price` (missing/zero-price tax data ⇒ rate `0`, prices unchanged). The same rate applies to both, so the list-price guard still compares the base prices. `ProductCardTaxLabel` renders the configured `taxesLabel` beside the price, but **only when `usePriceWithTaxes` is enabled** (state-driven presence — compose to place it, omit to hide). Default is tax-exclusive (off).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Props
|
|
34
|
+
|
|
35
|
+
### ProductListRoot
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Notes |
|
|
38
|
+
|------|------|---------|-------|
|
|
39
|
+
| `products` | `ProductListItem[]` | `[]` | The products to render; published through the products context |
|
|
40
|
+
| `usePriceWithTaxes` | boolean | `false` | When true, card prices render tax-inclusive and `ProductCardTaxLabel` shows |
|
|
41
|
+
| `taxesLabel` | string | `Tax included` | Text rendered by `ProductCardTaxLabel` when tax display is on |
|
|
42
|
+
|
|
43
|
+
`ProductShelfRoot` exposes the same `usePriceWithTaxes` / `taxesLabel` config (it publishes the same config context).
|
|
44
|
+
|
|
45
|
+
### ProductListGrid
|
|
46
|
+
|
|
47
|
+
Repeats its children once per product, wrapping each in the per-item context. No props beyond standard `div` attributes.
|
|
48
|
+
|
|
49
|
+
### ProductCard
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Default | Notes |
|
|
52
|
+
|------|------|---------|-------|
|
|
53
|
+
| `bordered` | boolean | `true` | Reflects onto `data-fs-product-card-bordered` (`"true"` / `"false"`); a swatch draws the border |
|
|
54
|
+
|
|
55
|
+
Optional card **wrapper** for the `ProductCard*` parts. It reads the item from the per-item context, always emits the `data-fs-product-card` identity hook, and adds `data-fs-product-card-out-of-stock` when the product is unavailable — `item.availableForSale === false || item.availableQuantity === 0` (unset availability ⇒ in stock, backward compatible). Availability is **derived state, not a prop**. The `bordered` prop is a purely visual toggle: it always emits `data-fs-product-card-bordered` carrying the stringified value, and the border look is a swatch keyed off it (the wrapper ships no baked border). It renders **all children unchanged** — an out-of-stock card still shows its price and discount (cross-feature rule). Standard `div` attributes pass through.
|
|
56
|
+
|
|
57
|
+
### ProductCardImage
|
|
58
|
+
|
|
59
|
+
| Prop | Type | Default | Notes |
|
|
60
|
+
|------|------|---------|-------|
|
|
61
|
+
| `aspectRatio` | string | — | CSS `aspect-ratio` for the image box (e.g. `1/1`, `3/4`, `16/9`) |
|
|
62
|
+
| `objectFit` | `contain \| cover \| fill \| none` | `cover` | How the image fits its box; orthogonal to `aspectRatio` |
|
|
63
|
+
|
|
64
|
+
Renders `item.image.src` with `item.image.alt`. Standard `img` attributes pass through.
|
|
65
|
+
|
|
66
|
+
### ProductCardName
|
|
67
|
+
|
|
68
|
+
Renders `item.name` (the product title). Standard `span` attributes pass through; pass children to override the text (rarely needed — the point is catalog data).
|
|
69
|
+
|
|
70
|
+
### ProductCardPrice
|
|
71
|
+
|
|
72
|
+
Renders the selling price `item.price` formatted with the active storefront context's locale and `item.currency ?? context.currency`. When `usePriceWithTaxes` is on, it renders the tax-inclusive value instead (`item.price × (1 + rate)`).
|
|
73
|
+
|
|
74
|
+
### ProductCardListPrice
|
|
75
|
+
|
|
76
|
+
Renders `item.listPrice` (strikethrough via swatch) formatted like the selling price — **only when `item.listPrice > item.price`**, otherwise renders nothing. When `usePriceWithTaxes` is on, it renders the tax-inclusive list price at the same rate as the selling price.
|
|
77
|
+
|
|
78
|
+
### ProductCardTaxLabel
|
|
79
|
+
|
|
80
|
+
Renders the config `taxesLabel` (default "Tax included") beside the price, **only when `usePriceWithTaxes` is enabled** — otherwise renders nothing (state-driven presence, no toggle: compose it to place the label, omit it to hide it). Children override the text. Emits `data-fs-product-card-tax-label` for styling. Reads only the config (not the item), so its placement in the card template is free.
|
|
81
|
+
|
|
82
|
+
### ProductCardDiscount
|
|
83
|
+
|
|
84
|
+
| Prop | Type | Default | Notes |
|
|
85
|
+
|------|------|---------|-------|
|
|
86
|
+
| `format` | `percentage \| absolute` | `percentage` | `percentage` → `-{pct}%`; `absolute` → `-{amount saved}` in the price currency |
|
|
87
|
+
|
|
88
|
+
A discount badge that **composes the `Badge` particle**. It auto-computes the markdown from the item's prices — `percentOff = round((listPrice − price) / listPrice × 100)`, `amountOff = listPrice − price` — and renders **only when `item.listPrice > item.price`** (state-driven, no toggle: compose the part to show it, omit it to hide it). Children override the computed label. It also emits `data-fs-product-card-discount-tier` (`low` / `medium` / `high`, from the percentage) for swatch color tiers. Uses `price` (not `spotPrice`); spot/Pix discount is out of scope.
|
|
89
|
+
|
|
90
|
+
> `ProductCardAddToCart` also exists in this matter, but its cart integration is out of scope for the Product Shelf feature.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Per-item context
|
|
95
|
+
|
|
96
|
+
Each row publishes a `ProductListItem`; the card content parts read these fields:
|
|
97
|
+
|
|
98
|
+
| Field | Used by |
|
|
99
|
+
|-------|---------|
|
|
100
|
+
| `image` (`{ src, alt }`) | `ProductCardImage` |
|
|
101
|
+
| `name` | `ProductCardName` |
|
|
102
|
+
| `price` | `ProductCardPrice`; `ProductCardDiscount` (discount base) |
|
|
103
|
+
| `listPrice` | `ProductCardListPrice` and `ProductCardDiscount` (rendered only when `> price`) |
|
|
104
|
+
| `currency` | price / discount formatting (falls back to the storefront context currency) |
|
|
105
|
+
| `availableForSale` / `availableQuantity` | `ProductCard` (out-of-stock state when `availableForSale === false` or `availableQuantity === 0`) |
|
|
106
|
+
| `tax` / `taxPercentage` | `ProductCardPrice` / `ProductCardListPrice` (tax-inclusive value when `usePriceWithTaxes` is on) |
|
|
107
|
+
|
|
108
|
+
The type is widened (optional `spotPrice`, `tax`, `taxPercentage`, `availableForSale`, `availableQuantity`, `currency`) so the same leaves compose under `ProductShelfItems`, which supplies those extra fields for the discount / out-of-stock / tax card parts.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Composition
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
ProductListRoot (owns products + tax-display config)
|
|
116
|
+
└── ProductListGrid (repeats the card template per product)
|
|
117
|
+
└── ProductCard (optional wrapper; data-fs-product-card [+ -bordered, + -out-of-stock])
|
|
118
|
+
├── ProductCardImage (aspectRatio, objectFit)
|
|
119
|
+
├── ProductCardName
|
|
120
|
+
├── ProductCardDiscount (badge; renders only when listPrice > price)
|
|
121
|
+
├── ProductCardPrice (tax-inclusive when usePriceWithTaxes)
|
|
122
|
+
├── ProductCardListPrice (renders only when listPrice > price)
|
|
123
|
+
└── ProductCardTaxLabel (renders only when usePriceWithTaxes)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The same card template composes inside a `ProductShelf` — swap `ProductListRoot > ProductListGrid` for `ProductShelfRoot > CarouselRoot > ProductShelfItems`.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Minimal schema example
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"list": {
|
|
135
|
+
"type": "ProductListRoot",
|
|
136
|
+
"props": { "usePriceWithTaxes": true, "taxesLabel": "Tax included" },
|
|
137
|
+
"children": ["grid"]
|
|
138
|
+
},
|
|
139
|
+
"grid": {
|
|
140
|
+
"type": "ProductListGrid",
|
|
141
|
+
"children": ["card"]
|
|
142
|
+
},
|
|
143
|
+
"card": {
|
|
144
|
+
"type": "ProductCard",
|
|
145
|
+
"props": { "bordered": true },
|
|
146
|
+
"children": ["card-image", "card-name", "card-discount", "card-price", "card-list-price", "card-tax-label"]
|
|
147
|
+
},
|
|
148
|
+
"card-image": { "type": "ProductCardImage", "props": { "aspectRatio": "1/1", "objectFit": "cover" } },
|
|
149
|
+
"card-name": { "type": "ProductCardName" },
|
|
150
|
+
"card-discount": { "type": "ProductCardDiscount", "props": { "format": "percentage" } },
|
|
151
|
+
"card-price": { "type": "ProductCardPrice" },
|
|
152
|
+
"card-list-price": { "type": "ProductCardListPrice" },
|
|
153
|
+
"card-tax-label": { "type": "ProductCardTaxLabel" }
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Styling
|
|
160
|
+
|
|
161
|
+
All appearance is chosen by swatches keyed off the structural hooks:
|
|
162
|
+
|
|
163
|
+
- `data-fs-product-list-root` / `data-fs-product-list-grid` — the container and grid
|
|
164
|
+
- `data-fs-product-card` — the optional card wrapper; `data-fs-product-card-bordered` carries `"true"` / `"false"` from the `bordered` toggle (draw the border here — e.g. `[data-fs-product-card-bordered='true']`); `data-fs-product-card-out-of-stock` is present only when the product is unavailable (grey / reduce opacity here; scope it so price/discount stay legible)
|
|
165
|
+
- `data-fs-product-card-image` — the image (carries `aspect-ratio` + `object-fit` styles)
|
|
166
|
+
- `data-fs-product-card-name` — the title text
|
|
167
|
+
- `data-fs-product-card-price` — the selling price
|
|
168
|
+
- `data-fs-product-card-list-price` — the list price (apply the strikethrough here)
|
|
169
|
+
- `data-fs-product-card-tax-label` — the tax label (present only when `usePriceWithTaxes` is on)
|
|
170
|
+
- `data-fs-product-card-discount` — the discount badge (also carries `data-fs-badge`); `data-fs-product-card-discount-tier` = `low` / `medium` / `high` for color tiers
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# ProductQuantity
|
|
2
|
+
|
|
3
|
+
**Category:** commerce
|
|
4
|
+
**Purpose:** Headless boundary that holds the purchase quantity for a single product on a PDP and shares it with the BuyButton and a bound quantity selector. Exposes the selected seller's stock as the selector `max`. Renders no DOM of its own.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Visual cues (how to identify in an image)
|
|
9
|
+
|
|
10
|
+
ProductQuantity has no visual of its own. You identify it indirectly when a PDP shows **both**:
|
|
11
|
+
|
|
12
|
+
- A **quantity stepper** (a number input flanked by `−` / `+` controls), and
|
|
13
|
+
- A **BuyButton** that should add that quantity to the cart.
|
|
14
|
+
|
|
15
|
+
The stepper itself is rendered by `ProductQuantitySelector` (wrapping the generic `QuantitySelectorRoot`); the `ProductQuantityRoot` is the invisible provider that connects it to the BuyButton.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
- A PDP where clicking the BuyButton must add the quantity chosen in the stepper.
|
|
22
|
+
|
|
23
|
+
## When NOT to use
|
|
24
|
+
|
|
25
|
+
- A standalone quantity stepper with no cart wiring — use the generic `QuantitySelectorRoot` particle directly.
|
|
26
|
+
- Cart line item quantity controls — use the cart-specific quantity components.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Composition
|
|
31
|
+
|
|
32
|
+
`ProductQuantityRoot` is a **headless context boundary**: it renders no element, so it never affects layout. It only needs to be an **ancestor** of both the BuyButton and the `ProductQuantitySelector` in the element tree — they do **not** need to be adjacent or share a visual container.
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
ProductQuantityRoot (headless — no DOM)
|
|
36
|
+
├── ... any layout blocks ...
|
|
37
|
+
│ └── BuyButtonRoot
|
|
38
|
+
│ └── BuyButtonButton
|
|
39
|
+
└── ... any other layout block ...
|
|
40
|
+
└── ProductQuantitySelector
|
|
41
|
+
├── NumberFieldGroup
|
|
42
|
+
│ ├── NumberFieldDecrement
|
|
43
|
+
│ ├── NumberFieldInput
|
|
44
|
+
│ └── NumberFieldIncrement
|
|
45
|
+
└── ProductQuantity.Message (optional — shows the max-exceeded message)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Placement
|
|
49
|
+
|
|
50
|
+
Because it renders nothing, place `ProductQuantityRoot` **as high as a single product's scope allows** — typically at the PDP page/layout root. The BuyButton and the selector can then sit in entirely different layout blocks below it.
|
|
51
|
+
|
|
52
|
+
### Scope
|
|
53
|
+
|
|
54
|
+
One `ProductQuantityRoot` represents **one product**. On a standard PDP that is the whole page, so a single high-level provider is correct. If a page ever offers **multiple independently purchasable products** (e.g. a "buy together" block), give each its own `ProductQuantityRoot` subtree instead of one shared provider — otherwise all of them would share a single quantity.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Components
|
|
59
|
+
|
|
60
|
+
### ProductQuantityRoot
|
|
61
|
+
|
|
62
|
+
Headless provider. Holds the selected quantity (default `1`) and derives the `max` from stock. Renders no DOM element.
|
|
63
|
+
|
|
64
|
+
| Prop | Type | Default | Notes |
|
|
65
|
+
|------|------|---------|-------|
|
|
66
|
+
| `defaultValue` | number | `1` | Initial quantity |
|
|
67
|
+
|
|
68
|
+
**Data:** declares `fragment ProductQuantityData on Query`. Reads the first variant's sellers and exposes the **default seller's** `offer.availableQuantity` as `max` (mirrors BuyButton's seller-selection rule so the cap matches the seller actually purchased). `max` is `null` when no data is provided.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### ProductQuantitySelector
|
|
73
|
+
|
|
74
|
+
Quantity stepper bound to the `ProductQuantityRoot` context. Renders the generic `QuantitySelectorRoot` wired to the shared quantity state, with `min` of `1` and `max` from stock. Pass-through props and children are forwarded to `QuantitySelectorRoot`.
|
|
75
|
+
|
|
76
|
+
Must be a descendant of `ProductQuantityRoot`. Without it, the selector falls back to a quantity of `1` and is effectively read-only.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### ProductQuantity.Message
|
|
81
|
+
|
|
82
|
+
Thin alias of the particle part `QuantitySelectorMessage`. Renders a message when a shopper enters a quantity above the stock-derived `max` and the value was clamped down; renders nothing otherwise. Place it inside `ProductQuantitySelector` so it reads the selector context. Set `children` to override the default copy — the text is operational UI, sourced in the component until the `@vtex/fs-i18n` catalog exists.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## BuyButton integration
|
|
87
|
+
|
|
88
|
+
`BuyButtonButton` reads the quantity from this context (via `useProductQuantity()`) and passes it to `cart.addItem()`. The hook has a safe default, so a BuyButton rendered **without** a `ProductQuantityRoot` ancestor still works and adds quantity `1` — the integration is opt-in by mounting the provider.
|