@shopify/hydrogen 2026.10.0-preview.2 → 2026.10.0-preview.4
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/README.md +34 -3
- package/dist/cli/index.mjs +578 -85
- package/dist/client/client.mjs +2 -2
- package/dist/client/errors.d.mts +19 -19
- package/dist/client/errors.mjs +19 -16
- package/dist/client/errors.mjs.map +1 -1
- package/dist/client/types.d.mts +91 -10
- package/dist/core/analytics/cart-tracker.d.mts +14 -0
- package/dist/core/analytics/cart-tracker.mjs +15 -1
- package/dist/core/analytics/cart-tracker.mjs.map +1 -1
- package/dist/core/analytics/custom-consent.mjs +12 -0
- package/dist/core/analytics/custom-consent.mjs.map +1 -0
- package/dist/core/analytics/events.d.mts +7 -0
- package/dist/core/analytics/events.mjs +7 -0
- package/dist/core/analytics/events.mjs.map +1 -1
- package/dist/core/analytics/index.d.mts +1 -1
- package/dist/core/analytics/types.d.mts +152 -16
- package/dist/core/cart/actions.d.mts +47 -3
- package/dist/core/cart/actions.mjs +29 -0
- package/dist/core/cart/actions.mjs.map +1 -1
- package/dist/core/cart/attach-quantity-input.d.mts +26 -0
- package/dist/core/cart/attach-quantity-input.mjs +26 -0
- package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
- package/dist/core/cart/cart.d.mts +106 -6
- package/dist/core/cart/cart.mjs +57 -6
- package/dist/core/cart/cart.mjs.map +1 -1
- package/dist/core/cart/cookie.d.mts +15 -0
- package/dist/core/cart/cookie.mjs +15 -0
- package/dist/core/cart/cookie.mjs.map +1 -1
- package/dist/core/cart/form.d.mts +61 -0
- package/dist/core/cart/form.mjs +18 -0
- package/dist/core/cart/form.mjs.map +1 -1
- package/dist/core/cart/get-cart.d.mts +43 -2
- package/dist/core/cart/get-cart.mjs +33 -0
- package/dist/core/cart/get-cart.mjs.map +1 -1
- package/dist/core/cart/index.d.mts +1 -1
- package/dist/core/cart/quantity.d.mts +17 -0
- package/dist/core/cart/quantity.mjs +17 -0
- package/dist/core/cart/quantity.mjs.map +1 -1
- package/dist/core/cart/queries.d.mts +402 -369
- package/dist/core/cart/queries.mjs +2 -1
- package/dist/core/cart/queries.mjs.map +1 -1
- package/dist/core/cart/server-handlers.d.mts +69 -0
- package/dist/core/cart/server-handlers.mjs +2 -10
- package/dist/core/cart/server-handlers.mjs.map +1 -1
- package/dist/core/cart/state.d.mts +133 -0
- package/dist/core/cart/state.mjs +8 -0
- package/dist/core/cart/state.mjs.map +1 -1
- package/dist/core/collection/collection.d.mts +18 -2
- package/dist/core/collection/collection.mjs +11 -0
- package/dist/core/collection/collection.mjs.map +1 -1
- package/dist/core/collection/index.d.mts +1 -1
- package/dist/core/collection/reconciler.d.mts +13 -4
- package/dist/core/collection/reconciler.mjs.map +1 -1
- package/dist/core/collection/state.d.mts +7 -2
- package/dist/core/collection/state.mjs.map +1 -1
- package/dist/core/collection/url.d.mts +3 -0
- package/dist/core/collection/url.mjs.map +1 -1
- package/dist/core/constants.d.mts +1 -1
- package/dist/core/constants.mjs +2 -2
- package/dist/core/constants.mjs.map +1 -1
- package/dist/core/headers.mjs +2 -2
- package/dist/core/headers.mjs.map +1 -1
- package/dist/core/index.d.mts +5 -5
- package/dist/core/logging/logging.mjs.map +1 -1
- package/dist/core/money/format.mjs +6 -3
- package/dist/core/money/format.mjs.map +1 -1
- package/dist/core/observable.mjs +0 -3
- package/dist/core/observable.mjs.map +1 -1
- package/dist/core/predictive-search/form.d.mts +1 -0
- package/dist/core/predictive-search/form.mjs +1 -0
- package/dist/core/predictive-search/form.mjs.map +1 -1
- package/dist/core/predictive-search/index.d.mts +1 -1
- package/dist/core/predictive-search/queries.d.mts +40 -4
- package/dist/core/predictive-search/queries.mjs +7 -1
- package/dist/core/predictive-search/queries.mjs.map +1 -1
- package/dist/core/predictive-search/search.d.mts +43 -10
- package/dist/core/predictive-search/search.mjs +34 -0
- package/dist/core/predictive-search/search.mjs.map +1 -1
- package/dist/core/predictive-search/server-handlers.d.mts +31 -5
- package/dist/core/predictive-search/server-handlers.mjs +5 -3
- package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
- package/dist/core/predictive-search/store.d.mts +3 -1
- package/dist/core/predictive-search/store.mjs.map +1 -1
- package/dist/core/predictive-search/url.d.mts +50 -8
- package/dist/core/predictive-search/url.mjs +9 -0
- package/dist/core/predictive-search/url.mjs.map +1 -1
- package/dist/core/product/form.d.mts +21 -2
- package/dist/core/product/form.mjs +13 -0
- package/dist/core/product/form.mjs.map +1 -1
- package/dist/core/product/index.d.mts +1 -1
- package/dist/core/product/options.d.mts +2 -2
- package/dist/core/product/options.mjs +2 -2
- package/dist/core/product/options.mjs.map +1 -1
- package/dist/core/product/product-form.d.mts +33 -1
- package/dist/core/product/product-form.mjs +30 -0
- package/dist/core/product/product-form.mjs.map +1 -1
- package/dist/core/product/state.d.mts +41 -0
- package/dist/core/product/url.d.mts +6 -0
- package/dist/core/product/url.mjs.map +1 -1
- package/dist/core/request-context.d.mts +8 -5
- package/dist/core/request-context.mjs +17 -39
- package/dist/core/request-context.mjs.map +1 -1
- package/dist/core/request-routing/handle-shopify-routes.mjs +4 -1
- package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/ajax-api.mjs +1 -1
- package/dist/core/request-routing/interceptors/api-proxy.mjs +1 -1
- package/dist/core/request-routing/interceptors/checkout.mjs +22 -6
- package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
- package/dist/core/request-routing/interceptors/proxy.mjs +36 -10
- package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs +35 -0
- package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
- package/dist/core/shopify-scripts/analytics.mjs +2 -2
- package/dist/core/shopify-scripts/analytics.mjs.map +1 -1
- package/dist/core/shopify-scripts/constants.mjs +4 -2
- package/dist/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/core/shopify-scripts/global.mjs +9 -4
- package/dist/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/core/shopify-scripts/index.d.mts +1 -0
- package/dist/core/shopify-scripts/index.mjs +14 -12
- package/dist/core/shopify-scripts/index.mjs.map +1 -1
- package/dist/core/shopify-scripts/initialize.d.mts +1 -0
- package/dist/core/shopify-scripts/initialize.mjs +10 -3
- package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
- package/dist/core/shopify-scripts/types.d.mts +6 -0
- package/dist/core/url.mjs +21 -2
- package/dist/core/url.mjs.map +1 -1
- package/dist/customer-account/client.d.mts +128 -4
- package/dist/customer-account/client.mjs +27 -1
- package/dist/customer-account/client.mjs.map +1 -1
- package/dist/customer-account/errors.d.mts +46 -0
- package/dist/customer-account/errors.mjs +46 -0
- package/dist/customer-account/errors.mjs.map +1 -1
- package/dist/customer-account/graphql.d.mts +68 -0
- package/dist/customer-account/graphql.mjs +47 -0
- package/dist/customer-account/graphql.mjs.map +1 -1
- package/dist/customer-account/session.d.mts +114 -23
- package/dist/customer-account/session.mjs +27 -12
- package/dist/customer-account/session.mjs.map +1 -1
- package/dist/customer-account/type-resolver.d.mts +23 -0
- package/dist/customer-account-api-types.d.ts +570 -374
- package/dist/customer-account.schema.json +2981 -1527
- package/dist/development/client/client.mjs +2 -2
- package/dist/development/client/errors.d.mts +19 -19
- package/dist/development/client/errors.mjs +20 -20
- package/dist/development/client/errors.mjs.map +1 -1
- package/dist/development/client/types.d.mts +91 -10
- package/dist/development/core/analytics/cart-tracker.d.mts +14 -0
- package/dist/development/core/analytics/cart-tracker.mjs +15 -1
- package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
- package/dist/development/core/analytics/custom-consent.mjs +12 -0
- package/dist/development/core/analytics/custom-consent.mjs.map +1 -0
- package/dist/development/core/analytics/events.d.mts +7 -0
- package/dist/development/core/analytics/events.mjs +7 -0
- package/dist/development/core/analytics/events.mjs.map +1 -1
- package/dist/development/core/analytics/index.d.mts +1 -1
- package/dist/development/core/analytics/types.d.mts +152 -16
- package/dist/development/core/cart/actions.d.mts +47 -3
- package/dist/development/core/cart/actions.mjs +29 -0
- package/dist/development/core/cart/actions.mjs.map +1 -1
- package/dist/development/core/cart/attach-quantity-input.d.mts +26 -0
- package/dist/development/core/cart/attach-quantity-input.mjs +26 -0
- package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
- package/dist/development/core/cart/cart.d.mts +106 -6
- package/dist/development/core/cart/cart.mjs +57 -6
- package/dist/development/core/cart/cart.mjs.map +1 -1
- package/dist/development/core/cart/cookie.d.mts +15 -0
- package/dist/development/core/cart/cookie.mjs +15 -0
- package/dist/development/core/cart/cookie.mjs.map +1 -1
- package/dist/development/core/cart/form.d.mts +61 -0
- package/dist/development/core/cart/form.mjs +18 -0
- package/dist/development/core/cart/form.mjs.map +1 -1
- package/dist/development/core/cart/get-cart.d.mts +43 -2
- package/dist/development/core/cart/get-cart.mjs +33 -0
- package/dist/development/core/cart/get-cart.mjs.map +1 -1
- package/dist/development/core/cart/index.d.mts +1 -1
- package/dist/development/core/cart/quantity.d.mts +17 -0
- package/dist/development/core/cart/quantity.mjs +17 -0
- package/dist/development/core/cart/quantity.mjs.map +1 -1
- package/dist/development/core/cart/queries.d.mts +345 -312
- package/dist/development/core/cart/queries.mjs +2 -1
- package/dist/development/core/cart/queries.mjs.map +1 -1
- package/dist/development/core/cart/server-handlers.d.mts +69 -0
- package/dist/development/core/cart/server-handlers.mjs +2 -10
- package/dist/development/core/cart/server-handlers.mjs.map +1 -1
- package/dist/development/core/cart/state.d.mts +133 -0
- package/dist/development/core/cart/state.mjs +8 -0
- package/dist/development/core/cart/state.mjs.map +1 -1
- package/dist/development/core/collection/collection.d.mts +18 -2
- package/dist/development/core/collection/collection.mjs +11 -0
- package/dist/development/core/collection/collection.mjs.map +1 -1
- package/dist/development/core/collection/index.d.mts +1 -1
- package/dist/development/core/collection/reconciler.d.mts +13 -4
- package/dist/development/core/collection/reconciler.mjs.map +1 -1
- package/dist/development/core/collection/state.d.mts +7 -2
- package/dist/development/core/collection/state.mjs.map +1 -1
- package/dist/development/core/collection/url.d.mts +3 -0
- package/dist/development/core/collection/url.mjs.map +1 -1
- package/dist/development/core/constants.mjs +1 -1
- package/dist/development/core/constants.mjs.map +1 -1
- package/dist/development/core/development.d.mts +5 -5
- package/dist/development/core/headers.mjs +2 -2
- package/dist/development/core/headers.mjs.map +1 -1
- package/dist/development/core/index.d.mts +4 -4
- package/dist/development/core/logging/logging.mjs.map +1 -1
- package/dist/development/core/money/format.mjs +6 -3
- package/dist/development/core/money/format.mjs.map +1 -1
- package/dist/development/core/observable.mjs +0 -3
- package/dist/development/core/observable.mjs.map +1 -1
- package/dist/development/core/predictive-search/form.d.mts +1 -0
- package/dist/development/core/predictive-search/form.mjs +1 -0
- package/dist/development/core/predictive-search/form.mjs.map +1 -1
- package/dist/development/core/predictive-search/index.d.mts +1 -1
- package/dist/development/core/predictive-search/queries.d.mts +38 -2
- package/dist/development/core/predictive-search/queries.mjs +7 -1
- package/dist/development/core/predictive-search/queries.mjs.map +1 -1
- package/dist/development/core/predictive-search/search.d.mts +43 -10
- package/dist/development/core/predictive-search/search.mjs +34 -0
- package/dist/development/core/predictive-search/search.mjs.map +1 -1
- package/dist/development/core/predictive-search/server-handlers.d.mts +31 -5
- package/dist/development/core/predictive-search/server-handlers.mjs +5 -3
- package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
- package/dist/development/core/predictive-search/store.d.mts +3 -1
- package/dist/development/core/predictive-search/store.mjs.map +1 -1
- package/dist/development/core/predictive-search/url.d.mts +50 -8
- package/dist/development/core/predictive-search/url.mjs +9 -0
- package/dist/development/core/predictive-search/url.mjs.map +1 -1
- package/dist/development/core/product/form.d.mts +21 -2
- package/dist/development/core/product/form.mjs +13 -0
- package/dist/development/core/product/form.mjs.map +1 -1
- package/dist/development/core/product/index.d.mts +1 -1
- package/dist/development/core/product/options.d.mts +2 -2
- package/dist/development/core/product/options.mjs +2 -2
- package/dist/development/core/product/options.mjs.map +1 -1
- package/dist/development/core/product/product-form.d.mts +33 -1
- package/dist/development/core/product/product-form.mjs +30 -0
- package/dist/development/core/product/product-form.mjs.map +1 -1
- package/dist/development/core/product/state.d.mts +41 -0
- package/dist/development/core/product/url.d.mts +6 -0
- package/dist/development/core/product/url.mjs.map +1 -1
- package/dist/development/core/request-context.d.mts +8 -5
- package/dist/development/core/request-context.mjs +17 -39
- package/dist/development/core/request-context.mjs.map +1 -1
- package/dist/development/core/request-routing/handle-shopify-routes.mjs +4 -1
- package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/ajax-api.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/api-proxy.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/checkout.mjs +22 -6
- package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/proxy.mjs +36 -10
- package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs +35 -0
- package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
- package/dist/development/core/shopify-scripts/analytics.mjs +2 -2
- package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/constants.mjs +4 -2
- package/dist/development/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/global.mjs +9 -4
- package/dist/development/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/index.d.mts +1 -0
- package/dist/development/core/shopify-scripts/index.mjs +14 -12
- package/dist/development/core/shopify-scripts/index.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/initialize.d.mts +1 -0
- package/dist/development/core/shopify-scripts/initialize.mjs +10 -3
- package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/types.d.mts +6 -0
- package/dist/development/core/url.mjs +21 -2
- package/dist/development/core/url.mjs.map +1 -1
- package/dist/development/customer-account/session.d.mts +69 -13
- package/dist/development/customer-account/session.mjs +4 -0
- package/dist/development/customer-account/session.mjs.map +1 -1
- package/dist/development/globals.d.mts +6 -5
- package/dist/development/graphql/generated/graphql-env.d.mts +459 -16
- package/dist/development/graphql/generated/storefront-api-types.d.mts +1 -1
- package/dist/development/graphql/graphql.d.mts +33 -0
- package/dist/development/graphql/graphql.mjs +30 -0
- package/dist/development/graphql/graphql.mjs.map +1 -1
- package/dist/development/graphql/type-resolver.d.mts +14 -0
- package/dist/development/react/cart.d.mts +85 -14
- package/dist/development/react/cart.mjs +123 -3
- package/dist/development/react/cart.mjs.map +1 -1
- package/dist/development/react/collection.d.mts +2 -4
- package/dist/development/react/collection.mjs.map +1 -1
- package/dist/development/react/index.d.mts +8 -6
- package/dist/development/react/index.mjs +2 -2
- package/dist/development/react/predictive-search.d.mts +68 -7
- package/dist/development/react/predictive-search.mjs +54 -12
- package/dist/development/react/predictive-search.mjs.map +1 -1
- package/dist/development/react/product.d.mts +1 -0
- package/dist/development/react/product.mjs +5 -2
- package/dist/development/react/product.mjs.map +1 -1
- package/dist/development/react/shopify-scripts.mjs +1 -0
- package/dist/development/react/shopify-scripts.mjs.map +1 -1
- package/dist/development/vue/cart.d.mts +85 -6
- package/dist/development/vue/cart.mjs +95 -0
- package/dist/development/vue/cart.mjs.map +1 -1
- package/dist/development/vue/collection.d.mts +83 -5
- package/dist/development/vue/collection.mjs +52 -0
- package/dist/development/vue/collection.mjs.map +1 -1
- package/dist/development/vue/index.d.mts +6 -4
- package/dist/development/vue/predictive-search.d.mts +53 -6
- package/dist/development/vue/predictive-search.mjs +33 -0
- package/dist/development/vue/predictive-search.mjs.map +1 -1
- package/dist/development/vue/product.d.mts +6 -2
- package/dist/development/vue/product.mjs.map +1 -1
- package/dist/development/vue/shopify-scripts.d.mts +30 -3
- package/dist/development/vue/shopify-scripts.mjs +6 -0
- package/dist/development/vue/shopify-scripts.mjs.map +1 -1
- package/dist/globals.d.mts +6 -5
- package/dist/graphql/generated/customer-account-graphql-env.d.mts +1717 -1090
- package/dist/graphql/generated/graphql-env.d.mts +459 -16
- package/dist/graphql/generated/storefront-api-types.d.mts +1 -1
- package/dist/graphql/graphql.d.mts +33 -0
- package/dist/graphql/graphql.mjs +30 -0
- package/dist/graphql/graphql.mjs.map +1 -1
- package/dist/graphql/type-resolver.d.mts +14 -0
- package/dist/react/cart.d.mts +85 -14
- package/dist/react/cart.mjs +123 -3
- package/dist/react/cart.mjs.map +1 -1
- package/dist/react/collection.d.mts +2 -4
- package/dist/react/collection.mjs.map +1 -1
- package/dist/react/index.d.mts +8 -6
- package/dist/react/index.mjs +2 -2
- package/dist/react/predictive-search.d.mts +68 -7
- package/dist/react/predictive-search.mjs +54 -12
- package/dist/react/predictive-search.mjs.map +1 -1
- package/dist/react/product.d.mts +1 -0
- package/dist/react/product.mjs +5 -2
- package/dist/react/product.mjs.map +1 -1
- package/dist/react/shopify-scripts.mjs +1 -0
- package/dist/react/shopify-scripts.mjs.map +1 -1
- package/dist/storefront-api-types.d.ts +165 -20
- package/dist/storefront.schema.json +782 -57
- package/dist/vite/customer-account.mjs +191 -0
- package/dist/vite/customer-account.mjs.map +1 -0
- package/dist/vite/local-https.mjs +13 -29
- package/dist/vite/local-https.mjs.map +1 -1
- package/dist/vite/mkcert.mjs +1 -1
- package/dist/vue/cart.d.mts +85 -6
- package/dist/vue/cart.mjs +95 -0
- package/dist/vue/cart.mjs.map +1 -1
- package/dist/vue/collection.d.mts +83 -5
- package/dist/vue/collection.mjs +52 -0
- package/dist/vue/collection.mjs.map +1 -1
- package/dist/vue/index.d.mts +6 -4
- package/dist/vue/predictive-search.d.mts +53 -6
- package/dist/vue/predictive-search.mjs +33 -0
- package/dist/vue/predictive-search.mjs.map +1 -1
- package/dist/vue/product.d.mts +6 -2
- package/dist/vue/product.mjs.map +1 -1
- package/dist/vue/shopify-scripts.d.mts +31 -4
- package/dist/vue/shopify-scripts.mjs +6 -0
- package/dist/vue/shopify-scripts.mjs.map +1 -1
- package/package.json +5 -2
- package/skills/hydrogen-analytics/SKILL.md +6 -5
- package/skills/hydrogen-analytics/references/custom-consent.md +52 -0
- package/skills/hydrogen-analytics/references/react.md +1 -1
- package/skills/hydrogen-cart-metafields/SKILL.md +133 -0
- package/skills/hydrogen-cart-ui/SKILL.md +2 -1
- package/skills/hydrogen-customer-account/SKILL.md +3 -3
- package/skills/hydrogen-local-https/SKILL.md +22 -7
- package/skills/hydrogen-request-handlers/SKILL.md +5 -5
- package/skills/hydrogen-request-handlers/references/nuxt.md +0 -6
- package/skills/hydrogen-setup/references/analytics.md +24 -23
- package/skills/hydrogen-setup/steps/1-inspect-app.md +1 -1
- package/skills/hydrogen-setup/steps/11-verify.md +1 -0
- package/skills/hydrogen-setup/steps/2-scaffold.md +22 -1
- package/skills/hydrogen-smoke-test/SKILL.md +2 -2
- package/skills/hydrogen-storefront-client/SKILL.md +4 -2
- package/skills/hydrogen-variant-form/SKILL.md +10 -4
- package/ts-plugin/package.json +5 -0
- package/dist/core/shopify-scripts/consent.mjs +0 -17
- package/dist/core/shopify-scripts/consent.mjs.map +0 -1
- package/dist/core/shopify-scripts/deprecated-cookies.mjs +0 -97
- package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/tracking-values.mjs +0 -65
- package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/uuid.mjs +0 -17
- package/dist/core/shopify-scripts/utils/uuid.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/consent.mjs +0 -17
- package/dist/development/core/shopify-scripts/consent.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +0 -97
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +0 -65
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/uuid.mjs +0 -17
- package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +0 -1
package/dist/vue/cart.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart.mjs","names":[],"sources":["../../src/vue/cart.ts"],"sourcesContent":["import {\n computed,\n defineComponent,\n h,\n inject,\n onMounted,\n onScopeDispose,\n onUnmounted,\n provide,\n shallowRef,\n type ComputedRef,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport { trackCartAnalytics } from \"../core/analytics/cart-tracker\";\nimport {\n configureCartEndpoint as configureCoreCartEndpoint,\n createCartStore,\n type CreateCartStoreOptions,\n type CartStore,\n} from \"../core/cart/cart\";\nimport { createCartFormRegister, type CartFormRegister } from \"../core/cart/form\";\nimport type { CartDataFromHandlers } from \"../core/cart/server-handlers\";\nimport type { CartData, CartState } from \"../core/cart/state\";\n\nconst DEFAULT_CART_ENDPOINT = \"/api/cart\";\n\nlet cartEndpoint = DEFAULT_CART_ENDPOINT;\n\nconst CartStoreKey: InjectionKey<CartStore> = Symbol(\"CartStore\");\n\nexport function configureCartEndpoint(endpoint: string): void {\n cartEndpoint = endpoint;\n configureCoreCartEndpoint(endpoint);\n}\n\nexport function getCartEndpoint(): string {\n return cartEndpoint;\n}\n\ntype TypedUseCart<TData extends CartData> = {\n (): Readonly<ShallowRef<CartState<TData>>>;\n <S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n ): Readonly<ShallowRef<S>>;\n};\n\ntype TypedUseOptionalCart<TData extends CartData> = <S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n) => Readonly<ShallowRef<S | undefined>>;\n\ntype CartInitialData<TData extends CartData = CartData> =\n CreateCartStoreOptions<TData>[\"initialData\"];\n\ntype TypedCartProvider<TData extends CartData> = {\n new (): { $props: { initialData?: CartInitialData<TData> } };\n};\n\n/** Actions for reconciling cart state after updates outside Standard Actions. */\nexport type CartActions = Pick<CartStore, \"refresh\">;\n\ntype TypedCartComponents<TData extends CartData> = {\n CartProvider: TypedCartProvider<TData>;\n useCart: TypedUseCart<TData>;\n useOptionalCart: TypedUseOptionalCart<TData>;\n useCartActions: typeof useCartActions;\n useCartForm: typeof useCartForm;\n};\n\nfunction createTypedCartProvider<TData extends CartData>(): TypedCartProvider<TData> {\n const TypedCartProvider = defineComponent(\n (props: { initialData?: CartInitialData<TData> }, { slots }) => {\n return () =>\n h(\n CartProvider,\n { initialData: props.initialData as CartInitialData | undefined },\n slots.default,\n );\n },\n { name: \"CartProvider\", props: [\"initialData\"] },\n );\n\n return TypedCartProvider as unknown as TypedCartProvider<TData>;\n}\n\nexport function useCartStore(composableName = \"useCartStore\"): CartStore {\n const store = inject(CartStoreKey, null);\n if (!store) {\n throw new Error(`${composableName} must be used inside a <CartProvider>.`);\n }\n return store;\n}\n\nfunction useOptionalCartStore(): CartStore | null {\n return inject(CartStoreKey, null);\n}\n\nexport const CartProvider = defineComponent({\n name: \"CartProvider\",\n props: {\n initialData: {\n type: Object as PropType<CartInitialData>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n const store = createCartStore({ initialData: props.initialData });\n provide(CartStoreKey, store);\n\n onMounted(() => {\n configureCoreCartEndpoint(cartEndpoint);\n store.connect();\n });\n\n onUnmounted(() => {\n store.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n\nexport function useCart(): Readonly<ShallowRef<CartState>>;\nexport function useCart<TData extends CartData = CartData, S = unknown>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>>;\nexport function useCart<TData extends CartData = CartData, S = unknown>(\n selector?: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S | CartState>> {\n const store = useCartStore(\"useCart\");\n const resolve = selector ?? ((state: CartState<TData>) => state as unknown as S);\n return useCartSelector(store, resolve, isEqual) as Readonly<ShallowRef<S>>;\n}\n\nexport function useCartActions(): CartActions {\n const store = useCartStore(\"useCartActions\");\n return { refresh: store.refresh };\n}\n\nexport function useCartAnalytics(): void {\n const store = useCartStore(\"useCartAnalytics\");\n let stopTracking: (() => void) | undefined;\n\n onMounted(() => {\n stopTracking = trackCartAnalytics(store);\n });\n\n onScopeDispose(() => stopTracking?.());\n}\n\n/**\n * Like `useCart`, but returns `undefined` when rendered outside a `<CartProvider>`.\n * @internal\n */\nexport function useOptionalCart<TData extends CartData = CartData, S = unknown>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S | undefined>> {\n const store = useOptionalCartStore();\n if (!store) return shallowRef<S | undefined>(undefined);\n return useCartSelector(store, selector, isEqual);\n}\n\nfunction useCartSelector<TData extends CartData = CartData, S = unknown>(\n store: CartStore,\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>> {\n const selected = shallowRef<S>(selector(store.getState() as CartState<TData>));\n\n const unsubscribe = store.subscribe(() => {\n const next = selector(store.getState() as CartState<TData>);\n if (isEqual?.(selected.value, next)) return;\n selected.value = next;\n });\n\n onScopeDispose(unsubscribe);\n\n return selected as Readonly<ShallowRef<S>>;\n}\n\nexport function useCartForm(): {\n formProps: (opts?: {\n beforeSubmit?: (e: Event) => void;\n afterSubmit?: (e: Event) => void;\n }) => Record<string, unknown>;\n register: CartFormRegister;\n isPending: {\n initial: ComputedRef<boolean>;\n lines: (lineId?: string) => boolean;\n };\n} {\n const store = useCartStore(\"useCartForm\");\n const loading = useCart((s) => s.loading);\n const pendingLines = useCart((s) => s.pending.lines);\n const register = createCartFormRegister();\n\n const formProps = (opts?: {\n beforeSubmit?: (e: Event) => void;\n afterSubmit?: (e: Event) => void;\n }): Record<string, unknown> => ({\n onSubmit: (e: Event) => {\n opts?.beforeSubmit?.(e);\n if (e.defaultPrevented) return;\n e.preventDefault();\n store.handleFormSubmit(e as SubmitEvent).catch(() => {});\n opts?.afterSubmit?.(e);\n },\n method: \"post\",\n action: cartEndpoint,\n });\n\n const isPending = {\n initial: computed(() => loading.value),\n lines: (lineId?: string): boolean =>\n lineId ? pendingLines.value.has(lineId) : pendingLines.value.size > 0,\n };\n\n return { formProps, register, isPending };\n}\n\nexport function createCartComponents<THandlers>(): TypedCartComponents<\n CartDataFromHandlers<THandlers>\n> {\n type TData = CartDataFromHandlers<THandlers>;\n const TypedCartProvider = createTypedCartProvider<TData>();\n\n const useTypedCart = ((\n selector?: (state: CartState<TData>) => unknown,\n isEqual?: (a: unknown, b: unknown) => boolean,\n ) => {\n if (!selector) return useCart() as Readonly<ShallowRef<CartState<TData>>>;\n return useCart<TData, unknown>(selector, isEqual);\n }) as TypedUseCart<TData>;\n\n const useTypedOptionalCart = (<S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n ) => useOptionalCart<TData, S>(selector, isEqual)) as TypedUseOptionalCart<TData>;\n\n return {\n CartProvider: TypedCartProvider,\n useCart: useTypedCart,\n useOptionalCart: useTypedOptionalCart,\n useCartActions,\n useCartForm,\n };\n}\n"],"mappings":";;;;;;AA6BA,IAAI,eAAe;AAEnB,MAAM,eAAwC,OAAO,YAAY;AAOjE,SAAgB,kBAA0B;AACxC,QAAO;;AAkCT,SAAS,0BAA4E;AAanF,QAZ0B,iBACvB,OAAiD,EAAE,YAAY;AAC9D,eACE,EACE,cACA,EAAE,aAAa,MAAM,aAA4C,EACjE,MAAM,QACP;IAEL;EAAE,MAAM;EAAgB,OAAO,CAAC,cAAc;EAAE,CAG1B;;AAG1B,SAAgB,aAAa,iBAAiB,gBAA2B;CACvE,MAAM,QAAQ,OAAO,cAAc,KAAK;AACxC,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,GAAG,eAAe,wCAAwC;AAE5E,QAAO;;AAGT,SAAS,uBAAyC;AAChD,QAAO,OAAO,cAAc,KAAK;;AAGnC,MAAa,eAAe,gBAAgB;CAC1C,MAAM;CACN,OAAO,EACL,aAAa;EACX,MAAM;EACN,SAAS;EACV,EACF;CACD,MAAM,OAAO,EAAE,SAAS;EACtB,MAAM,QAAQ,gBAAgB,EAAE,aAAa,MAAM,aAAa,CAAC;AACjE,UAAQ,cAAc,MAAM;AAE5B,kBAAgB;AACd,yBAA0B,aAAa;AACvC,SAAM,SAAS;IACf;AAEF,oBAAkB;AAChB,SAAM,SAAS;IACf;AAEF,eAAa,MAAM,WAAW;;CAEjC,CAAC;AAOF,SAAgB,QACd,UACA,SACqC;AAGrC,QAAO,gBAFO,aAAa,UAEC,EADZ,cAAc,UAA4B,QACnB,QAAQ;;AAGjD,SAAgB,iBAA8B;AAE5C,QAAO,EAAE,SADK,aAAa,iBACJ,CAAC,SAAS;;AAGnC,SAAgB,mBAAyB;CACvC,MAAM,QAAQ,aAAa,mBAAmB;CAC9C,IAAI;AAEJ,iBAAgB;AACd,iBAAe,mBAAmB,MAAM;GACxC;AAEF,sBAAqB,gBAAgB,CAAC;;;;;;AAOxC,SAAgB,gBACd,UACA,SACqC;CACrC,MAAM,QAAQ,sBAAsB;AACpC,KAAI,CAAC,MAAO,QAAO,WAA0B,OAAU;AACvD,QAAO,gBAAgB,OAAO,UAAU,QAAQ;;AAGlD,SAAS,gBACP,OACA,UACA,SACyB;CACzB,MAAM,WAAW,WAAc,SAAS,MAAM,UAAU,CAAqB,CAAC;AAQ9E,gBANoB,MAAM,gBAAgB;EACxC,MAAM,OAAO,SAAS,MAAM,UAAU,CAAqB;AAC3D,MAAI,UAAU,SAAS,OAAO,KAAK,CAAE;AACrC,WAAS,QAAQ;GAGO,CAAC;AAE3B,QAAO;;AAGT,SAAgB,cAUd;CACA,MAAM,QAAQ,aAAa,cAAc;CACzC,MAAM,UAAU,SAAS,MAAM,EAAE,QAAQ;CACzC,MAAM,eAAe,SAAS,MAAM,EAAE,QAAQ,MAAM;CACpD,MAAM,WAAW,wBAAwB;CAEzC,MAAM,aAAa,UAGa;EAC9B,WAAW,MAAa;AACtB,SAAM,eAAe,EAAE;AACvB,OAAI,EAAE,iBAAkB;AACxB,KAAE,gBAAgB;AAClB,SAAM,iBAAiB,EAAiB,CAAC,YAAY,GAAG;AACxD,SAAM,cAAc,EAAE;;EAExB,QAAQ;EACR,QAAQ;EACT;AAQD,QAAO;EAAE;EAAW;EAAU;GAL5B,SAAS,eAAe,QAAQ,MAAM;GACtC,QAAQ,WACN,SAAS,aAAa,MAAM,IAAI,OAAO,GAAG,aAAa,MAAM,OAAO;GAGjC;EAAE;;AAG3C,SAAgB,uBAEd;CAEA,MAAM,oBAAoB,yBAAgC;CAE1D,MAAM,iBACJ,UACA,YACG;AACH,MAAI,CAAC,SAAU,QAAO,SAAS;AAC/B,SAAO,QAAwB,UAAU,QAAQ;;CAGnD,MAAM,yBACJ,UACA,YACG,gBAA0B,UAAU,QAAQ;AAEjD,QAAO;EACL,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB;EACA;EACD"}
|
|
1
|
+
{"version":3,"file":"cart.mjs","names":[],"sources":["../../src/vue/cart.ts"],"sourcesContent":["import {\n computed,\n defineComponent,\n h,\n inject,\n onMounted,\n onScopeDispose,\n onUnmounted,\n provide,\n shallowRef,\n type ComputedRef,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport { trackCartAnalytics } from \"../core/analytics/cart-tracker\";\nimport {\n configureCartEndpoint as configureCoreCartEndpoint,\n createCartStore,\n type CreateCartStoreOptions,\n type CartActions,\n type CartStore,\n} from \"../core/cart/cart\";\nimport { createCartFormRegister, type CartFormRegister } from \"../core/cart/form\";\nimport type { CartDataFromHandlers } from \"../core/cart/server-handlers\";\nimport type { CartData, CartState } from \"../core/cart/state\";\n\nconst DEFAULT_CART_ENDPOINT = \"/api/cart\";\n\nlet cartEndpoint = DEFAULT_CART_ENDPOINT;\n\nconst CartStoreKey: InjectionKey<CartStore> = Symbol(\"CartStore\");\n\nexport function configureCartEndpoint(endpoint: string): void {\n cartEndpoint = endpoint;\n configureCoreCartEndpoint(endpoint);\n}\n\nexport function getCartEndpoint(): string {\n return cartEndpoint;\n}\n\ntype TypedUseCart<TData extends CartData> = {\n (): Readonly<ShallowRef<CartState<TData>>>;\n <S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n ): Readonly<ShallowRef<S>>;\n};\n\ntype TypedUseOptionalCart<TData extends CartData> = <S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n) => Readonly<ShallowRef<S | undefined>>;\n\ntype CartInitialData<TData extends CartData = CartData> =\n CreateCartStoreOptions<TData>[\"initialData\"];\n\ntype TypedCartProvider<TData extends CartData> = {\n new (): { $props: { initialData?: CartInitialData<TData> } };\n};\n\nexport type { CartActions };\n\ntype TypedCartComponents<TData extends CartData> = {\n CartProvider: TypedCartProvider<TData>;\n useCart: TypedUseCart<TData>;\n useOptionalCart: TypedUseOptionalCart<TData>;\n useCartActions: typeof useCartActions;\n useCartForm: typeof useCartForm;\n};\n\nfunction createTypedCartProvider<TData extends CartData>(): TypedCartProvider<TData> {\n const TypedCartProvider = defineComponent(\n (props: { initialData?: CartInitialData<TData> }, { slots }) => {\n return () =>\n h(\n CartProvider,\n { initialData: props.initialData as CartInitialData | undefined },\n slots.default,\n );\n },\n { name: \"CartProvider\", props: [\"initialData\"] },\n );\n\n return TypedCartProvider as unknown as TypedCartProvider<TData>;\n}\n\nexport function useCartStore(composableName = \"useCartStore\"): CartStore {\n const store = inject(CartStoreKey, null);\n if (!store) {\n throw new Error(`${composableName} must be used inside a <CartProvider>.`);\n }\n return store;\n}\n\nfunction useOptionalCartStore(): CartStore | null {\n return inject(CartStoreKey, null);\n}\n\n/**\n * Vue component that creates and manages a {@link CartStore} instance.\n *\n * Calls {@link CartStore.connect} on mount and {@link CartStore.destroy} on unmount.\n * All cart composables (`useCart`, `useCartForm`, `useCartActions`) must be\n * descendants of this component.\n *\n * @example\n * ```vue\n * <CartProvider :initialData=\"{ cart: loaderData.cart }\">\n * <App />\n * </CartProvider>\n * ```\n */\nexport const CartProvider = defineComponent({\n name: \"CartProvider\",\n props: {\n initialData: {\n type: Object as PropType<CartInitialData>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n const store = createCartStore({ initialData: props.initialData });\n provide(CartStoreKey, store);\n\n onMounted(() => {\n configureCoreCartEndpoint(cartEndpoint);\n store.connect();\n });\n\n onUnmounted(() => {\n store.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n\n/**\n * Subscribes to {@link CartState} as a Vue `ShallowRef`.\n *\n * Without a selector, returns the full `CartState`. With a selector, returns\n * a `ShallowRef` of the selected slice — the ref updates only when the\n * selected value changes (by reference, or by custom `isEqual`).\n *\n * @example\n * ```vue\n * <script setup>\n * // Full state\n * const state = useCart();\n *\n * // Selected slice — re-renders only when lines change\n * const lines = useCart((s) => s.data.lines.nodes);\n *\n * // Check if a specific line is pending\n * const isPending = useCart((s) => s.pending.lines.has(lineId));\n * </script>\n * ```\n */\nexport function useCart(): Readonly<ShallowRef<CartState>>;\nexport function useCart<TData extends CartData = CartData, S = unknown>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>>;\nexport function useCart<TData extends CartData = CartData, S = unknown>(\n selector?: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S | CartState>> {\n const store = useCartStore(\"useCart\");\n const resolve = selector ?? ((state: CartState<TData>) => state as unknown as S);\n return useCartSelector(store, resolve, isEqual) as Readonly<ShallowRef<S>>;\n}\n\n/**\n * Returns cart actions for reconciling state after out-of-band mutations.\n *\n * Currently exposes {@link CartStore.refresh} — call it after server-side cart\n * mutations that bypass the form system.\n *\n * @example\n * ```vue\n * <script setup>\n * const { refresh } = useCartActions();\n *\n * async function handleServerAction() {\n * await createCartOnServer();\n * refresh();\n * }\n * </script>\n * ```\n */\nexport function useCartActions(): CartActions {\n const store = useCartStore(\"useCartActions\");\n return { refresh: store.refresh };\n}\n\n/**\n * Subscribes the {@link CartStore} to the analytics event dispatcher.\n *\n * Call once near the root of your app. Starts tracking on mount via `onMounted`\n * and cleans up via `onScopeDispose`.\n *\n * @example\n * ```vue\n * <script setup>\n * useCartAnalytics();\n * </script>\n * ```\n */\nexport function useCartAnalytics(): void {\n const store = useCartStore(\"useCartAnalytics\");\n let stopTracking: (() => void) | undefined;\n\n onMounted(() => {\n stopTracking = trackCartAnalytics(store);\n });\n\n onScopeDispose(() => stopTracking?.());\n}\n\n/**\n * Like `useCart`, but returns `undefined` when rendered outside a `<CartProvider>`.\n * @internal\n */\nexport function useOptionalCart<TData extends CartData = CartData, S = unknown>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S | undefined>> {\n const store = useOptionalCartStore();\n if (!store) return shallowRef<S | undefined>(undefined);\n return useCartSelector(store, selector, isEqual);\n}\n\nfunction useCartSelector<TData extends CartData = CartData, S = unknown>(\n store: CartStore,\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>> {\n const selected = shallowRef<S>(selector(store.getState() as CartState<TData>));\n\n const unsubscribe = store.subscribe(() => {\n const next = selector(store.getState() as CartState<TData>);\n if (isEqual?.(selected.value, next)) return;\n selected.value = next;\n });\n\n onScopeDispose(unsubscribe);\n\n return selected as Readonly<ShallowRef<S>>;\n}\n\n/**\n * Returns form props, a field register function, and reactive pending state\n * for building cart forms in Vue.\n *\n * Unlike the React hook, the Vue variant includes `isPending` — a reactive\n * object with `initial` (`ComputedRef<boolean>`) for the initial cart load\n * and `lines(lineId?)` for checking per-line or any-line pending state.\n *\n * Note: `interactive: true` returns numeric input attributes but does **not**\n * auto-submit on change — that behavior requires `attachQuantityInput`, which\n * is only wired by the React adapter.\n *\n * @example\n * ```vue\n * <script setup>\n * const { formProps, register, isPending } = useCartForm();\n * </script>\n *\n * <template>\n * <form v-bind=\"formProps()\">\n * <input v-bind=\"register('lineId', { value: line.id })\" />\n * <input v-bind=\"register('quantity', { value: line.quantity })\" />\n * <button v-bind=\"register('set')\" />\n * <button v-bind=\"register('increase')\">+</button>\n * <button v-bind=\"register('decrease')\">−</button>\n * <span v-if=\"isPending.lines(line.id)\">Updating…</span>\n * </form>\n * </template>\n * ```\n */\nexport function useCartForm(): {\n formProps: (opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }) => Record<string, unknown>;\n register: CartFormRegister;\n isPending: {\n initial: ComputedRef<boolean>;\n lines: (lineId?: string) => boolean;\n };\n} {\n const store = useCartStore(\"useCartForm\");\n const loading = useCart((s) => s.loading);\n const pendingLines = useCart((s) => s.pending.lines);\n const register = createCartFormRegister();\n\n const formProps = (opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }): Record<string, unknown> => ({\n onSubmit: (e: SubmitEvent) => {\n opts?.beforeSubmit?.(e);\n if (e.defaultPrevented) return;\n e.preventDefault();\n store.handleFormSubmit(e).catch(() => {});\n opts?.afterSubmit?.(e);\n },\n method: \"post\",\n action: cartEndpoint,\n });\n\n const isPending = {\n initial: computed(() => loading.value),\n lines: (lineId?: string): boolean =>\n lineId ? pendingLines.value.has(lineId) : pendingLines.value.size > 0,\n };\n\n return { formProps, register, isPending };\n}\n\n/**\n * Factory that returns typed cart components and composables matched to your\n * server handler's cart query shape.\n *\n * The generic `THandlers` parameter is inferred from your `createCartServerHandlers`\n * call, so every composable's {@link CartState} carries your custom cart fields.\n *\n * @example\n * ```ts\n * import type { cartServerHandlers } from \"./server/cart.server\";\n *\n * const {\n * CartProvider,\n * useCart,\n * useOptionalCart,\n * useCartActions,\n * useCartForm,\n * } = createCartComponents<typeof cartServerHandlers>();\n * ```\n */\nexport function createCartComponents<THandlers>(): TypedCartComponents<\n CartDataFromHandlers<THandlers>\n> {\n type TData = CartDataFromHandlers<THandlers>;\n const TypedCartProvider = createTypedCartProvider<TData>();\n\n const useTypedCart = ((\n selector?: (state: CartState<TData>) => unknown,\n isEqual?: (a: unknown, b: unknown) => boolean,\n ) => {\n if (!selector) return useCart() as Readonly<ShallowRef<CartState<TData>>>;\n return useCart<TData, unknown>(selector, isEqual);\n }) as TypedUseCart<TData>;\n\n const useTypedOptionalCart = (<S>(\n selector: (state: CartState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n ) => useOptionalCart<TData, S>(selector, isEqual)) as TypedUseOptionalCart<TData>;\n\n return {\n CartProvider: TypedCartProvider,\n useCart: useTypedCart,\n useOptionalCart: useTypedOptionalCart,\n useCartActions,\n useCartForm,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
import { CollectionState } from "../core/collection/state.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { CollectionActions, CollectionData } from "../core/collection/collection.mjs";
|
|
3
3
|
import * as _$vue from "vue";
|
|
4
4
|
import { PropType, ShallowRef } from "vue";
|
|
5
5
|
|
|
6
6
|
//#region src/vue/collection.d.ts
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Manages the lifecycle of a {@link CollectionStore}: creates on mount and syncs
|
|
9
|
+
* with URL changes. Recreates the store when `data.handle` changes
|
|
10
|
+
* (navigating to a different collection).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```vue
|
|
14
|
+
* <script setup lang="ts">
|
|
15
|
+
* import { CollectionProvider, type CollectionData } from '@shopify/hydrogen/vue';
|
|
16
|
+
* import { useRoute, useRouter } from 'vue-router';
|
|
17
|
+
*
|
|
18
|
+
* const props = defineProps<{ data: CollectionData; urlSearch: string }>();
|
|
19
|
+
* const route = useRoute();
|
|
20
|
+
* const router = useRouter();
|
|
21
|
+
*
|
|
22
|
+
* // `search` includes the leading `?`, so append it to the path as-is.
|
|
23
|
+
* const onChange = (search: string) => router.replace(`${route.path}${search}`);
|
|
24
|
+
* </script>
|
|
25
|
+
*
|
|
26
|
+
* <template>
|
|
27
|
+
* <CollectionProvider
|
|
28
|
+
* :data="props.data"
|
|
29
|
+
* :url-search="props.urlSearch"
|
|
30
|
+
* @change="onChange"
|
|
31
|
+
* >
|
|
32
|
+
* <slot />
|
|
33
|
+
* </CollectionProvider>
|
|
34
|
+
* </template>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
8
37
|
declare const CollectionProvider: _$vue.DefineComponent<_$vue.ExtractPropTypes<{
|
|
9
38
|
data: {
|
|
10
39
|
type: PropType<CollectionData>;
|
|
@@ -32,15 +61,64 @@ declare const CollectionProvider: _$vue.DefineComponent<_$vue.ExtractPropTypes<{
|
|
|
32
61
|
}>, {
|
|
33
62
|
urlSearch: string;
|
|
34
63
|
}, {}, {}, {}, string, _$vue.ComponentProvideOptions, true, {}, any>;
|
|
64
|
+
/**
|
|
65
|
+
* Subscribes to the collection store and returns a reactive ref of the full
|
|
66
|
+
* state snapshot.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```vue
|
|
70
|
+
* <script setup lang="ts">
|
|
71
|
+
* const state = useCollection();
|
|
72
|
+
* </script>
|
|
73
|
+
*
|
|
74
|
+
* <template>
|
|
75
|
+
* <p>{{ state.status }}</p>
|
|
76
|
+
* </template>
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
35
79
|
declare function useCollection(): Readonly<ShallowRef<CollectionState>>;
|
|
80
|
+
/**
|
|
81
|
+
* Subscribes to the collection store and returns a reactive ref of a derived
|
|
82
|
+
* value via `selector`. Optionally accepts an `isEqual` comparator to skip
|
|
83
|
+
* updates when the derived value is structurally unchanged.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```vue
|
|
87
|
+
* <script setup lang="ts">
|
|
88
|
+
* const status = useCollection(s => s.status);
|
|
89
|
+
* </script>
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
36
92
|
declare function useCollection<S>(selector: (state: CollectionState) => S, isEqual?: (a: S, b: S) => boolean): Readonly<ShallowRef<S>>;
|
|
93
|
+
/**
|
|
94
|
+
* Returns methods that change filters and sort. The store's `onBrowseChange`
|
|
95
|
+
* callback (set by {@link CollectionProvider}) handles emitting `change` with a
|
|
96
|
+
* serialized search string.
|
|
97
|
+
*/
|
|
37
98
|
declare function useCollectionActions(): CollectionActions;
|
|
99
|
+
/**
|
|
100
|
+
* Returns form props for progressive-enhancement of collection filter forms.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```vue
|
|
104
|
+
* <script setup lang="ts">
|
|
105
|
+
* const { formProps } = useCollectionForm();
|
|
106
|
+
* </script>
|
|
107
|
+
*
|
|
108
|
+
* <template>
|
|
109
|
+
* <form v-bind="formProps()" action="/collections/shoes">
|
|
110
|
+
* <input type="checkbox" name="filter.p.tag" value="sale" />
|
|
111
|
+
* <button type="submit">Apply</button>
|
|
112
|
+
* </form>
|
|
113
|
+
* </template>
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
38
116
|
declare function useCollectionForm(): {
|
|
39
117
|
formProps: (opts?: {
|
|
40
|
-
beforeSubmit?: (e:
|
|
41
|
-
afterSubmit?: (e:
|
|
118
|
+
beforeSubmit?: (e: SubmitEvent) => void;
|
|
119
|
+
afterSubmit?: (e: SubmitEvent) => void;
|
|
42
120
|
}) => Record<string, unknown>;
|
|
43
121
|
};
|
|
44
122
|
//#endregion
|
|
45
|
-
export {
|
|
123
|
+
export { CollectionProvider, useCollection, useCollectionActions, useCollectionForm };
|
|
46
124
|
//# sourceMappingURL=collection.d.mts.map
|
package/dist/vue/collection.mjs
CHANGED
|
@@ -4,6 +4,36 @@ import { defineComponent, inject, onUnmounted, provide, shallowRef, toValue, wat
|
|
|
4
4
|
|
|
5
5
|
//#region src/vue/collection.ts
|
|
6
6
|
const CollectionStoreKey = Symbol("CollectionStore");
|
|
7
|
+
/**
|
|
8
|
+
* Manages the lifecycle of a {@link CollectionStore}: creates on mount and syncs
|
|
9
|
+
* with URL changes. Recreates the store when `data.handle` changes
|
|
10
|
+
* (navigating to a different collection).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```vue
|
|
14
|
+
* <script setup lang="ts">
|
|
15
|
+
* import { CollectionProvider, type CollectionData } from '@shopify/hydrogen/vue';
|
|
16
|
+
* import { useRoute, useRouter } from 'vue-router';
|
|
17
|
+
*
|
|
18
|
+
* const props = defineProps<{ data: CollectionData; urlSearch: string }>();
|
|
19
|
+
* const route = useRoute();
|
|
20
|
+
* const router = useRouter();
|
|
21
|
+
*
|
|
22
|
+
* // `search` includes the leading `?`, so append it to the path as-is.
|
|
23
|
+
* const onChange = (search: string) => router.replace(`${route.path}${search}`);
|
|
24
|
+
* <\/script>
|
|
25
|
+
*
|
|
26
|
+
* <template>
|
|
27
|
+
* <CollectionProvider
|
|
28
|
+
* :data="props.data"
|
|
29
|
+
* :url-search="props.urlSearch"
|
|
30
|
+
* @change="onChange"
|
|
31
|
+
* >
|
|
32
|
+
* <slot />
|
|
33
|
+
* </CollectionProvider>
|
|
34
|
+
* </template>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
7
37
|
const CollectionProvider = defineComponent({
|
|
8
38
|
name: "CollectionProvider",
|
|
9
39
|
props: {
|
|
@@ -79,6 +109,11 @@ function useCollection(selector, isEqual) {
|
|
|
79
109
|
}, { immediate: true });
|
|
80
110
|
return selected;
|
|
81
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Returns methods that change filters and sort. The store's `onBrowseChange`
|
|
114
|
+
* callback (set by {@link CollectionProvider}) handles emitting `change` with a
|
|
115
|
+
* serialized search string.
|
|
116
|
+
*/
|
|
82
117
|
function useCollectionActions() {
|
|
83
118
|
const storeRef = useRequiredStoreRef("useCollectionActions");
|
|
84
119
|
return {
|
|
@@ -91,6 +126,23 @@ function useCollectionActions() {
|
|
|
91
126
|
handleFormSubmit: (...args) => storeRef.value.handleFormSubmit(...args)
|
|
92
127
|
};
|
|
93
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns form props for progressive-enhancement of collection filter forms.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```vue
|
|
134
|
+
* <script setup lang="ts">
|
|
135
|
+
* const { formProps } = useCollectionForm();
|
|
136
|
+
* <\/script>
|
|
137
|
+
*
|
|
138
|
+
* <template>
|
|
139
|
+
* <form v-bind="formProps()" action="/collections/shoes">
|
|
140
|
+
* <input type="checkbox" name="filter.p.tag" value="sale" />
|
|
141
|
+
* <button type="submit">Apply</button>
|
|
142
|
+
* </form>
|
|
143
|
+
* </template>
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
94
146
|
function useCollectionForm() {
|
|
95
147
|
const actions = useCollectionActions();
|
|
96
148
|
const formProps = (opts) => ({ onSubmit: (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.mjs","names":[],"sources":["../../src/vue/collection.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onUnmounted,\n provide,\n shallowRef,\n toValue,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport {\n createCollectionStore,\n createCollectionReconciler,\n type CollectionData,\n type CollectionReconciler,\n type CollectionStore,\n} from \"../core/collection\";\nimport type { CollectionState } from \"../core/collection\";\n\nexport type { CollectionData };\n\nconst CollectionStoreKey: InjectionKey<ShallowRef<CollectionStore>> = Symbol(\"CollectionStore\");\n\
|
|
1
|
+
{"version":3,"file":"collection.mjs","names":[],"sources":["../../src/vue/collection.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onUnmounted,\n provide,\n shallowRef,\n toValue,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport {\n createCollectionStore,\n createCollectionReconciler,\n type CollectionActions,\n type CollectionData,\n type CollectionReconciler,\n type CollectionStore,\n} from \"../core/collection\";\nimport type { CollectionState } from \"../core/collection\";\n\nexport type { CollectionActions, CollectionData };\n\nconst CollectionStoreKey: InjectionKey<ShallowRef<CollectionStore>> = Symbol(\"CollectionStore\");\n\n/**\n * Manages the lifecycle of a {@link CollectionStore}: creates on mount and syncs\n * with URL changes. Recreates the store when `data.handle` changes\n * (navigating to a different collection).\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * import { CollectionProvider, type CollectionData } from '@shopify/hydrogen/vue';\n * import { useRoute, useRouter } from 'vue-router';\n *\n * const props = defineProps<{ data: CollectionData; urlSearch: string }>();\n * const route = useRoute();\n * const router = useRouter();\n *\n * // `search` includes the leading `?`, so append it to the path as-is.\n * const onChange = (search: string) => router.replace(`${route.path}${search}`);\n * </script>\n *\n * <template>\n * <CollectionProvider\n * :data=\"props.data\"\n * :url-search=\"props.urlSearch\"\n * @change=\"onChange\"\n * >\n * <slot />\n * </CollectionProvider>\n * </template>\n * ```\n */\nexport const CollectionProvider = defineComponent({\n name: \"CollectionProvider\",\n props: {\n data: {\n type: Object as PropType<CollectionData>,\n required: true,\n },\n urlSearch: {\n type: String,\n default: \"\",\n },\n },\n emits: {\n change: (searchString: string) => typeof searchString === \"string\",\n },\n setup(props, { slots, emit }) {\n const readUrlSearch = () => toValue(props.urlSearch);\n\n const initialStore = createCollectionStore({\n data: props.data,\n urlSearch: readUrlSearch(),\n });\n const storeRef = shallowRef<CollectionStore>(initialStore);\n provide(CollectionStoreKey, storeRef);\n\n let reconciler: CollectionReconciler = createCollectionReconciler(\n {\n getStore: () => storeRef.value,\n readUrlSearch,\n emitChange: (s) => emit(\"change\", s),\n },\n readUrlSearch(),\n );\n initialStore.setOnBrowseChange(() => reconciler.handleBrowseChange());\n\n function resetStore() {\n storeRef.value.setOnBrowseChange(null);\n const store = createCollectionStore({\n data: props.data,\n urlSearch: readUrlSearch(),\n });\n storeRef.value = store;\n reconciler.reset(readUrlSearch());\n store.setOnBrowseChange(() => reconciler.handleBrowseChange());\n }\n\n watch(\n () => props.data.handle,\n (newHandle, oldHandle) => {\n if (newHandle === oldHandle) return;\n resetStore();\n },\n );\n\n watch(\n () => [readUrlSearch(), props.data] as const,\n () => {\n reconciler.reconcile(readUrlSearch(), props.data.dataSearch);\n },\n { flush: \"sync\", immediate: true, deep: true },\n );\n\n onUnmounted(() => {\n storeRef.value.setOnBrowseChange(null);\n });\n\n return () => slots.default?.();\n },\n});\n\nfunction useRequiredStoreRef(composableName: string): ShallowRef<CollectionStore> {\n const storeRef = inject(CollectionStoreKey, null);\n if (!storeRef) {\n throw new Error(`${composableName} must be used inside a <CollectionProvider>.`);\n }\n return storeRef;\n}\n\n/**\n * Subscribes to the collection store and returns a reactive ref of the full\n * state snapshot.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const state = useCollection();\n * </script>\n *\n * <template>\n * <p>{{ state.status }}</p>\n * </template>\n * ```\n */\nexport function useCollection(): Readonly<ShallowRef<CollectionState>>;\n/**\n * Subscribes to the collection store and returns a reactive ref of a derived\n * value via `selector`. Optionally accepts an `isEqual` comparator to skip\n * updates when the derived value is structurally unchanged.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const status = useCollection(s => s.status);\n * </script>\n * ```\n */\nexport function useCollection<S>(\n selector: (state: CollectionState) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>>;\nexport function useCollection<S>(\n selector?: (state: CollectionState) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<CollectionState | S>> {\n const storeRef = useRequiredStoreRef(\"useCollection\");\n const resolve = selector ?? ((state: CollectionState) => state as unknown as S);\n const selected = shallowRef<CollectionState | S>(resolve(storeRef.value.getState()));\n\n watch(\n () => storeRef.value,\n (store, _, onCleanup) => {\n selected.value = resolve(store.getState());\n\n const unsubscribe = store.subscribe(() => {\n const next = resolve(store.getState());\n if (isEqual && selector) {\n if (isEqual(selected.value as S, next)) return;\n }\n selected.value = next;\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return selected as Readonly<ShallowRef<CollectionState | S>>;\n}\n\n/**\n * Returns methods that change filters and sort. The store's `onBrowseChange`\n * callback (set by {@link CollectionProvider}) handles emitting `change` with a\n * serialized search string.\n */\nexport function useCollectionActions(): CollectionActions {\n const storeRef = useRequiredStoreRef(\"useCollectionActions\");\n\n return {\n setFilters: (...args) => storeRef.value.setFilters(...args),\n toggleFilter: (...args) => storeRef.value.toggleFilter(...args),\n toggleFilterInput: (...args) => storeRef.value.toggleFilterInput(...args),\n setSortKey: (...args) => storeRef.value.setSortKey(...args),\n setSortByValue: (...args) => storeRef.value.setSortByValue(...args),\n reset: (...args) => storeRef.value.reset(...args),\n handleFormSubmit: (...args) => storeRef.value.handleFormSubmit(...args),\n };\n}\n\n/**\n * Returns form props for progressive-enhancement of collection filter forms.\n *\n * @example\n * ```vue\n * <script setup lang=\"ts\">\n * const { formProps } = useCollectionForm();\n * </script>\n *\n * <template>\n * <form v-bind=\"formProps()\" action=\"/collections/shoes\">\n * <input type=\"checkbox\" name=\"filter.p.tag\" value=\"sale\" />\n * <button type=\"submit\">Apply</button>\n * </form>\n * </template>\n * ```\n */\nexport function useCollectionForm(): {\n formProps: (opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }) => Record<string, unknown>;\n} {\n const actions = useCollectionActions();\n\n const formProps = (opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }): Record<string, unknown> => ({\n onSubmit: (e: SubmitEvent) => {\n opts?.beforeSubmit?.(e);\n if (e.defaultPrevented) return;\n e.preventDefault();\n actions.handleFormSubmit(e);\n opts?.afterSubmit?.(e);\n },\n });\n\n return { formProps };\n}\n"],"mappings":"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"}
|
package/dist/vue/index.d.mts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { CartActions } from "../core/cart/cart.mjs";
|
|
1
2
|
import { ShopifyGlobal } from "../globals.mjs";
|
|
2
|
-
import { CollectionData } from "../core/collection/collection.mjs";
|
|
3
|
+
import { CollectionActions, CollectionData } from "../core/collection/collection.mjs";
|
|
3
4
|
import { ValidProductSelectionResult } from "../core/product/product-form.mjs";
|
|
4
5
|
import { ProductAddToCartProps, ProductFormRegister, ProductMerchandiseIdProps, ProductOptionValueProps, ProductQuantityDefaultProps, ProductQuantityProps } from "../core/product/form.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { PredictiveSearchActions } from "../core/predictive-search/store.mjs";
|
|
7
|
+
import { createCartComponents, useCartActions, useCartAnalytics } from "./cart.mjs";
|
|
8
|
+
import { CollectionProvider, useCollection, useCollectionActions, useCollectionForm } from "./collection.mjs";
|
|
9
|
+
import { PredictiveSearchFormPropsOptions, PredictiveSearchFormResult, PredictiveSearchProvider, PredictiveSearchQueryInputPropsOptions, usePredictiveSearch, usePredictiveSearchActions, usePredictiveSearchForm } from "./predictive-search.mjs";
|
|
8
10
|
import { UseProductFormOptions, UseProductFormResult, UseProductResult, createProductComponents, useProductForm } from "./product.mjs";
|
|
9
11
|
import { ShopPayButton, ShopPayButtonProps } from "./shop-pay.mjs";
|
|
10
12
|
import { ShopifyScripts, ShopifyScriptsProps } from "./shopify-scripts.mjs";
|
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
import { PredictiveSearchLimitScope, PredictiveSearchType, SearchUnavailableProductsType, SearchableField } from "../graphql/generated/storefront-api-types.mjs";
|
|
2
2
|
import { PredictiveSearchData } from "../core/predictive-search/search.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { PredictiveSearchActions, PredictiveSearchState } from "../core/predictive-search/store.mjs";
|
|
4
4
|
import * as _$vue from "vue";
|
|
5
5
|
import { PropType, ShallowRef } from "vue";
|
|
6
6
|
|
|
7
7
|
//#region src/vue/predictive-search.d.ts
|
|
8
|
-
|
|
8
|
+
/** Options for the form props builder returned by {@link usePredictiveSearchForm}. */
|
|
9
9
|
type PredictiveSearchFormPropsOptions = {
|
|
10
|
-
preventDefault?: boolean;
|
|
10
|
+
/** When `true`, prevents the native form submission and triggers a client-side search instead. */preventDefault?: boolean; /** Called on submit with the submit event and the extracted search term. Calling `event.preventDefault()` cancels both the native submission and Hydrogen's client-side search. */
|
|
11
11
|
onSubmit?: (event: SubmitEvent, term: string) => void;
|
|
12
12
|
[key: string]: unknown;
|
|
13
13
|
};
|
|
14
|
+
/** Options for the query input props builder returned by {@link usePredictiveSearchForm}'s `register` method. */
|
|
14
15
|
type PredictiveSearchQueryInputPropsOptions = {
|
|
15
|
-
onInput?: (event: Event, term: string) => void;
|
|
16
|
+
/** Called on input with the input event and the current input value. Call `event.preventDefault()` to skip the automatic search trigger. */onInput?: (event: Event, term: string) => void;
|
|
16
17
|
[key: string]: unknown;
|
|
17
18
|
};
|
|
19
|
+
/** Return type of {@link usePredictiveSearchForm}, providing methods to build a progressively-enhanced search form. */
|
|
18
20
|
type PredictiveSearchFormResult = {
|
|
19
|
-
formProps(options?: PredictiveSearchFormPropsOptions): Record<string, unknown>;
|
|
21
|
+
/** Generates form element attributes including the search action and submit handler. */formProps(options?: PredictiveSearchFormPropsOptions): Record<string, unknown>; /** Generates input element attributes for a named form field and wires up the search trigger. */
|
|
20
22
|
register: (field: "query", options?: PredictiveSearchQueryInputPropsOptions) => Record<string, unknown>;
|
|
21
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Creates and manages a predictive search store, providing it to descendant
|
|
26
|
+
* composables via Vue's provide/inject.
|
|
27
|
+
*
|
|
28
|
+
* Recreates the store when configuration props change. Connects the store
|
|
29
|
+
* on mount and destroys it on unmount.
|
|
30
|
+
*/
|
|
22
31
|
declare const PredictiveSearchProvider: _$vue.DefineComponent<_$vue.ExtractPropTypes<{
|
|
23
32
|
predictiveSearchEndpoint: {
|
|
24
33
|
type: StringConstructor;
|
|
@@ -115,10 +124,48 @@ declare const PredictiveSearchProvider: _$vue.DefineComponent<_$vue.ExtractPropT
|
|
|
115
124
|
searchableFields: SearchableField[];
|
|
116
125
|
unavailableProducts: SearchUnavailableProductsType;
|
|
117
126
|
}, {}, {}, {}, string, _$vue.ComponentProvideOptions, true, {}, any>;
|
|
127
|
+
/**
|
|
128
|
+
* Subscribes to the predictive search store's state as a reactive ref.
|
|
129
|
+
*
|
|
130
|
+
* Without arguments, returns a `ShallowRef` of the full
|
|
131
|
+
* {@link PredictiveSearchState}. With a `selector`, returns a ref of the
|
|
132
|
+
* derived value that only updates when the selected value changes
|
|
133
|
+
* (reference equality by default, or a custom `isEqual`).
|
|
134
|
+
*
|
|
135
|
+
* Must be used inside a {@link PredictiveSearchProvider}.
|
|
136
|
+
*
|
|
137
|
+
* @throws {Error} When called outside a PredictiveSearchProvider.
|
|
138
|
+
*/
|
|
118
139
|
declare function usePredictiveSearch<TData extends PredictiveSearchData = PredictiveSearchData>(): Readonly<ShallowRef<PredictiveSearchState<TData>>>;
|
|
119
140
|
declare function usePredictiveSearch<TData extends PredictiveSearchData = PredictiveSearchData, S = PredictiveSearchState<TData>>(selector: (state: PredictiveSearchState<TData>) => S, isEqual?: (a: S, b: S) => boolean): Readonly<ShallowRef<S>>;
|
|
141
|
+
/**
|
|
142
|
+
* Returns `search` and `clear` methods that delegate to the current store.
|
|
143
|
+
*
|
|
144
|
+
* These are thin wrappers that read from the reactive store ref on each call,
|
|
145
|
+
* so they always target the active store even after a provider prop change
|
|
146
|
+
* triggers store recreation.
|
|
147
|
+
*
|
|
148
|
+
* Must be used inside a {@link PredictiveSearchProvider}.
|
|
149
|
+
*
|
|
150
|
+
* @throws {Error} When called outside a PredictiveSearchProvider.
|
|
151
|
+
*/
|
|
120
152
|
declare function usePredictiveSearchActions(): PredictiveSearchActions;
|
|
153
|
+
/**
|
|
154
|
+
* Returns `formProps` and `register` for building a progressively-enhanced
|
|
155
|
+
* search form.
|
|
156
|
+
*
|
|
157
|
+
* `formProps()` generates form element attributes including the search
|
|
158
|
+
* action URL. `register("query")` generates input attributes and calls the
|
|
159
|
+
* store's search action on every `input` event. The store debounces requests
|
|
160
|
+
* and resets state for terms shorter than `minTermLength`.
|
|
161
|
+
* Both support an optional callback that receives the event and extracted
|
|
162
|
+
* term, and respect `event.preventDefault()` to cancel the automatic behavior.
|
|
163
|
+
*
|
|
164
|
+
* Must be used inside a {@link PredictiveSearchProvider}.
|
|
165
|
+
*
|
|
166
|
+
* @throws {Error} When called outside a PredictiveSearchProvider.
|
|
167
|
+
*/
|
|
121
168
|
declare function usePredictiveSearchForm(): PredictiveSearchFormResult;
|
|
122
169
|
//#endregion
|
|
123
|
-
export {
|
|
170
|
+
export { PredictiveSearchFormPropsOptions, PredictiveSearchFormResult, PredictiveSearchProvider, PredictiveSearchQueryInputPropsOptions, usePredictiveSearch, usePredictiveSearchActions, usePredictiveSearchForm };
|
|
124
171
|
//# sourceMappingURL=predictive-search.d.mts.map
|
|
@@ -5,6 +5,13 @@ import { defineComponent, inject, onMounted, onUnmounted, provide, shallowRef, w
|
|
|
5
5
|
//#region src/vue/predictive-search.ts
|
|
6
6
|
const CONFIG_ARRAY_SEPARATOR = "\0";
|
|
7
7
|
const PredictiveSearchKey = Symbol("PredictiveSearch");
|
|
8
|
+
/**
|
|
9
|
+
* Creates and manages a predictive search store, providing it to descendant
|
|
10
|
+
* composables via Vue's provide/inject.
|
|
11
|
+
*
|
|
12
|
+
* Recreates the store when configuration props change. Connects the store
|
|
13
|
+
* on mount and destroys it on unmount.
|
|
14
|
+
*/
|
|
8
15
|
const PredictiveSearchProvider = defineComponent({
|
|
9
16
|
name: "PredictiveSearchProvider",
|
|
10
17
|
props: {
|
|
@@ -121,6 +128,17 @@ function usePredictiveSearch(selector, isEqual) {
|
|
|
121
128
|
}, { immediate: true });
|
|
122
129
|
return selected;
|
|
123
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Returns `search` and `clear` methods that delegate to the current store.
|
|
133
|
+
*
|
|
134
|
+
* These are thin wrappers that read from the reactive store ref on each call,
|
|
135
|
+
* so they always target the active store even after a provider prop change
|
|
136
|
+
* triggers store recreation.
|
|
137
|
+
*
|
|
138
|
+
* Must be used inside a {@link PredictiveSearchProvider}.
|
|
139
|
+
*
|
|
140
|
+
* @throws {Error} When called outside a PredictiveSearchProvider.
|
|
141
|
+
*/
|
|
124
142
|
function usePredictiveSearchActions() {
|
|
125
143
|
const { storeRef } = useRequiredContext("usePredictiveSearchActions");
|
|
126
144
|
return {
|
|
@@ -128,6 +146,21 @@ function usePredictiveSearchActions() {
|
|
|
128
146
|
clear: () => storeRef.value.clear()
|
|
129
147
|
};
|
|
130
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Returns `formProps` and `register` for building a progressively-enhanced
|
|
151
|
+
* search form.
|
|
152
|
+
*
|
|
153
|
+
* `formProps()` generates form element attributes including the search
|
|
154
|
+
* action URL. `register("query")` generates input attributes and calls the
|
|
155
|
+
* store's search action on every `input` event. The store debounces requests
|
|
156
|
+
* and resets state for terms shorter than `minTermLength`.
|
|
157
|
+
* Both support an optional callback that receives the event and extracted
|
|
158
|
+
* term, and respect `event.preventDefault()` to cancel the automatic behavior.
|
|
159
|
+
*
|
|
160
|
+
* Must be used inside a {@link PredictiveSearchProvider}.
|
|
161
|
+
*
|
|
162
|
+
* @throws {Error} When called outside a PredictiveSearchProvider.
|
|
163
|
+
*/
|
|
131
164
|
function usePredictiveSearchForm() {
|
|
132
165
|
const { storeRef, searchActionRef } = useRequiredContext("usePredictiveSearchForm");
|
|
133
166
|
const coreRegister = createPredictiveSearchFormRegister();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"predictive-search.mjs","names":[],"sources":["../../src/vue/predictive-search.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n provide,\n shallowRef,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport {\n createPredictiveSearchFormRegister,\n createPredictiveSearchStore,\n getPredictiveSearchFormAttributes,\n readPredictiveSearchFormTerm,\n type CreatePredictiveSearchStoreOptions,\n type PredictiveSearchData,\n type PredictiveSearchState,\n type PredictiveSearchStore,\n} from \"../core/predictive-search\";\nimport type {\n PredictiveSearchLimitScope,\n PredictiveSearchType,\n SearchableField,\n SearchUnavailableProductsType,\n} from \"../graphql/generated/storefront-api-types\";\n\nconst CONFIG_ARRAY_SEPARATOR = \"\\0\";\n\ntype PredictiveSearchContextValue = {\n storeRef: ShallowRef<PredictiveSearchStore>;\n searchActionRef: ShallowRef<string | undefined>;\n};\n\nconst PredictiveSearchKey: InjectionKey<PredictiveSearchContextValue> = Symbol(\"PredictiveSearch\");\n\nexport type PredictiveSearchActions = Pick<PredictiveSearchStore, \"search\" | \"clear\">;\n\nexport type PredictiveSearchFormPropsOptions = {\n preventDefault?: boolean;\n onSubmit?: (event: SubmitEvent, term: string) => void;\n [key: string]: unknown;\n};\n\nexport type PredictiveSearchQueryInputPropsOptions = {\n onInput?: (event: Event, term: string) => void;\n [key: string]: unknown;\n};\n\nexport type PredictiveSearchFormResult = {\n formProps(options?: PredictiveSearchFormPropsOptions): Record<string, unknown>;\n register: (\n field: \"query\",\n options?: PredictiveSearchQueryInputPropsOptions,\n ) => Record<string, unknown>;\n};\n\nexport const PredictiveSearchProvider = defineComponent({\n name: \"PredictiveSearchProvider\",\n props: {\n predictiveSearchEndpoint: { type: String, default: undefined },\n searchAction: { type: String, default: undefined },\n debounceInMs: { type: Number, default: undefined },\n minTermLength: { type: Number, default: undefined },\n fetch: { type: Function as PropType<typeof globalThis.fetch>, default: undefined },\n limit: { type: Number, default: undefined },\n limitScope: { type: String as PropType<PredictiveSearchLimitScope>, default: undefined },\n types: { type: Array as PropType<PredictiveSearchType[]>, default: undefined },\n searchableFields: { type: Array as PropType<SearchableField[]>, default: undefined },\n unavailableProducts: {\n type: String as PropType<SearchUnavailableProductsType>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n function buildStoreOptions(): CreatePredictiveSearchStoreOptions {\n return {\n predictiveSearchEndpoint: props.predictiveSearchEndpoint,\n debounceInMs: props.debounceInMs,\n minTermLength: props.minTermLength,\n fetch: props.fetch as typeof globalThis.fetch | undefined,\n limit: props.limit,\n limitScope: props.limitScope,\n types: props.types,\n searchableFields: props.searchableFields,\n unavailableProducts: props.unavailableProducts,\n };\n }\n\n const storeRef = shallowRef<PredictiveSearchStore>(\n createPredictiveSearchStore(buildStoreOptions()),\n );\n const searchActionRef = shallowRef(props.searchAction);\n\n provide(PredictiveSearchKey, { storeRef, searchActionRef });\n\n watch(\n () => props.searchAction,\n (next) => {\n searchActionRef.value = next;\n },\n );\n\n watch(\n () => [\n props.predictiveSearchEndpoint,\n props.debounceInMs,\n props.minTermLength,\n props.fetch,\n props.limit,\n props.limitScope,\n getArrayKey(props.types),\n getArrayKey(props.searchableFields),\n props.unavailableProducts,\n ],\n () => {\n storeRef.value.destroy();\n storeRef.value = createPredictiveSearchStore(buildStoreOptions());\n storeRef.value.connect();\n },\n );\n\n onMounted(() => {\n storeRef.value.connect();\n });\n\n onUnmounted(() => {\n storeRef.value.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n\nfunction getArrayKey(values: readonly string[] | undefined): string {\n return values?.join(CONFIG_ARRAY_SEPARATOR) ?? \"\";\n}\n\nfunction useRequiredContext(composableName: string): PredictiveSearchContextValue {\n const context = inject(PredictiveSearchKey, null);\n if (!context) {\n throw new Error(`${composableName} must be used inside a <PredictiveSearchProvider>.`);\n }\n return context;\n}\n\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n>(): Readonly<ShallowRef<PredictiveSearchState<TData>>>;\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n S = PredictiveSearchState<TData>,\n>(\n selector: (state: PredictiveSearchState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>>;\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n S = PredictiveSearchState<TData>,\n>(\n selector?: (state: PredictiveSearchState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<PredictiveSearchState<TData> | S>> {\n const { storeRef } = useRequiredContext(\"usePredictiveSearch\");\n const resolve = selector ?? ((state: PredictiveSearchState<TData>) => state as unknown as S);\n const selected = shallowRef<PredictiveSearchState<TData> | S>(\n resolve((storeRef.value as PredictiveSearchStore<TData>).getState()),\n );\n\n watch(\n () => storeRef.value,\n (store, _, onCleanup) => {\n const typedStore = store as PredictiveSearchStore<TData>;\n selected.value = resolve(typedStore.getState());\n\n const unsubscribe = typedStore.subscribe(() => {\n const next = resolve(typedStore.getState());\n if (isEqual && selector) {\n if (isEqual(selected.value as S, next)) return;\n }\n selected.value = next;\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return selected as Readonly<ShallowRef<PredictiveSearchState<TData> | S>>;\n}\n\nexport function usePredictiveSearchActions(): PredictiveSearchActions {\n const { storeRef } = useRequiredContext(\"usePredictiveSearchActions\");\n\n return {\n search: (term) => storeRef.value.search(term),\n clear: () => storeRef.value.clear(),\n };\n}\n\nexport function usePredictiveSearchForm(): PredictiveSearchFormResult {\n const { storeRef, searchActionRef } = useRequiredContext(\"usePredictiveSearchForm\");\n const coreRegister = createPredictiveSearchFormRegister();\n\n function register(\n field: \"query\",\n options: PredictiveSearchQueryInputPropsOptions = {},\n ): Record<string, unknown> {\n const { onInput, ...attributes } = options;\n const coreAttributes = coreRegister(field);\n\n return {\n ...attributes,\n ...coreAttributes,\n onInput: (event: Event) => {\n const term = (event.target as HTMLInputElement).value;\n onInput?.(event, term);\n if (event.defaultPrevented) return;\n void storeRef.value.search(term);\n },\n };\n }\n\n function formProps(options: PredictiveSearchFormPropsOptions = {}): Record<string, unknown> {\n const { onSubmit, preventDefault, ...attributes } = options;\n\n return {\n ...getPredictiveSearchFormAttributes(searchActionRef.value),\n ...attributes,\n onSubmit: (event: SubmitEvent) => {\n const term = readPredictiveSearchFormTerm(\n new FormData(event.currentTarget as HTMLFormElement),\n );\n onSubmit?.(event, term);\n if (event.defaultPrevented) return;\n if (!preventDefault) return;\n event.preventDefault();\n void storeRef.value.search(term);\n },\n };\n }\n\n return { formProps, register };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"predictive-search.mjs","names":[],"sources":["../../src/vue/predictive-search.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n provide,\n shallowRef,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport {\n createPredictiveSearchFormRegister,\n createPredictiveSearchStore,\n getPredictiveSearchFormAttributes,\n readPredictiveSearchFormTerm,\n type CreatePredictiveSearchStoreOptions,\n type PredictiveSearchActions,\n type PredictiveSearchData,\n type PredictiveSearchState,\n type PredictiveSearchStore,\n} from \"../core/predictive-search\";\nimport type {\n PredictiveSearchLimitScope,\n PredictiveSearchType,\n SearchableField,\n SearchUnavailableProductsType,\n} from \"../graphql/generated/storefront-api-types\";\n\nconst CONFIG_ARRAY_SEPARATOR = \"\\0\";\n\ntype PredictiveSearchContextValue = {\n storeRef: ShallowRef<PredictiveSearchStore>;\n searchActionRef: ShallowRef<string | undefined>;\n};\n\nconst PredictiveSearchKey: InjectionKey<PredictiveSearchContextValue> = Symbol(\"PredictiveSearch\");\n\nexport type { PredictiveSearchActions };\n\n/** Options for the form props builder returned by {@link usePredictiveSearchForm}. */\nexport type PredictiveSearchFormPropsOptions = {\n /** When `true`, prevents the native form submission and triggers a client-side search instead. */\n preventDefault?: boolean;\n /** Called on submit with the submit event and the extracted search term. Calling `event.preventDefault()` cancels both the native submission and Hydrogen's client-side search. */\n onSubmit?: (event: SubmitEvent, term: string) => void;\n [key: string]: unknown;\n};\n\n/** Options for the query input props builder returned by {@link usePredictiveSearchForm}'s `register` method. */\nexport type PredictiveSearchQueryInputPropsOptions = {\n /** Called on input with the input event and the current input value. Call `event.preventDefault()` to skip the automatic search trigger. */\n onInput?: (event: Event, term: string) => void;\n [key: string]: unknown;\n};\n\n/** Return type of {@link usePredictiveSearchForm}, providing methods to build a progressively-enhanced search form. */\nexport type PredictiveSearchFormResult = {\n /** Generates form element attributes including the search action and submit handler. */\n formProps(options?: PredictiveSearchFormPropsOptions): Record<string, unknown>;\n /** Generates input element attributes for a named form field and wires up the search trigger. */\n register: (\n field: \"query\",\n options?: PredictiveSearchQueryInputPropsOptions,\n ) => Record<string, unknown>;\n};\n\n/**\n * Creates and manages a predictive search store, providing it to descendant\n * composables via Vue's provide/inject.\n *\n * Recreates the store when configuration props change. Connects the store\n * on mount and destroys it on unmount.\n */\nexport const PredictiveSearchProvider = defineComponent({\n name: \"PredictiveSearchProvider\",\n props: {\n predictiveSearchEndpoint: { type: String, default: undefined },\n searchAction: { type: String, default: undefined },\n debounceInMs: { type: Number, default: undefined },\n minTermLength: { type: Number, default: undefined },\n fetch: { type: Function as PropType<typeof globalThis.fetch>, default: undefined },\n limit: { type: Number, default: undefined },\n limitScope: { type: String as PropType<PredictiveSearchLimitScope>, default: undefined },\n types: { type: Array as PropType<PredictiveSearchType[]>, default: undefined },\n searchableFields: { type: Array as PropType<SearchableField[]>, default: undefined },\n unavailableProducts: {\n type: String as PropType<SearchUnavailableProductsType>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n function buildStoreOptions(): CreatePredictiveSearchStoreOptions {\n return {\n predictiveSearchEndpoint: props.predictiveSearchEndpoint,\n debounceInMs: props.debounceInMs,\n minTermLength: props.minTermLength,\n fetch: props.fetch as typeof globalThis.fetch | undefined,\n limit: props.limit,\n limitScope: props.limitScope,\n types: props.types,\n searchableFields: props.searchableFields,\n unavailableProducts: props.unavailableProducts,\n };\n }\n\n const storeRef = shallowRef<PredictiveSearchStore>(\n createPredictiveSearchStore(buildStoreOptions()),\n );\n const searchActionRef = shallowRef(props.searchAction);\n\n provide(PredictiveSearchKey, { storeRef, searchActionRef });\n\n watch(\n () => props.searchAction,\n (next) => {\n searchActionRef.value = next;\n },\n );\n\n watch(\n () => [\n props.predictiveSearchEndpoint,\n props.debounceInMs,\n props.minTermLength,\n props.fetch,\n props.limit,\n props.limitScope,\n getArrayKey(props.types),\n getArrayKey(props.searchableFields),\n props.unavailableProducts,\n ],\n () => {\n storeRef.value.destroy();\n storeRef.value = createPredictiveSearchStore(buildStoreOptions());\n storeRef.value.connect();\n },\n );\n\n onMounted(() => {\n storeRef.value.connect();\n });\n\n onUnmounted(() => {\n storeRef.value.destroy();\n });\n\n return () => slots.default?.();\n },\n});\n\nfunction getArrayKey(values: readonly string[] | undefined): string {\n return values?.join(CONFIG_ARRAY_SEPARATOR) ?? \"\";\n}\n\nfunction useRequiredContext(composableName: string): PredictiveSearchContextValue {\n const context = inject(PredictiveSearchKey, null);\n if (!context) {\n throw new Error(`${composableName} must be used inside a <PredictiveSearchProvider>.`);\n }\n return context;\n}\n\n/**\n * Subscribes to the predictive search store's state as a reactive ref.\n *\n * Without arguments, returns a `ShallowRef` of the full\n * {@link PredictiveSearchState}. With a `selector`, returns a ref of the\n * derived value that only updates when the selected value changes\n * (reference equality by default, or a custom `isEqual`).\n *\n * Must be used inside a {@link PredictiveSearchProvider}.\n *\n * @throws {Error} When called outside a PredictiveSearchProvider.\n */\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n>(): Readonly<ShallowRef<PredictiveSearchState<TData>>>;\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n S = PredictiveSearchState<TData>,\n>(\n selector: (state: PredictiveSearchState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<S>>;\nexport function usePredictiveSearch<\n TData extends PredictiveSearchData = PredictiveSearchData,\n S = PredictiveSearchState<TData>,\n>(\n selector?: (state: PredictiveSearchState<TData>) => S,\n isEqual?: (a: S, b: S) => boolean,\n): Readonly<ShallowRef<PredictiveSearchState<TData> | S>> {\n const { storeRef } = useRequiredContext(\"usePredictiveSearch\");\n const resolve = selector ?? ((state: PredictiveSearchState<TData>) => state as unknown as S);\n const selected = shallowRef<PredictiveSearchState<TData> | S>(\n resolve((storeRef.value as PredictiveSearchStore<TData>).getState()),\n );\n\n watch(\n () => storeRef.value,\n (store, _, onCleanup) => {\n const typedStore = store as PredictiveSearchStore<TData>;\n selected.value = resolve(typedStore.getState());\n\n const unsubscribe = typedStore.subscribe(() => {\n const next = resolve(typedStore.getState());\n if (isEqual && selector) {\n if (isEqual(selected.value as S, next)) return;\n }\n selected.value = next;\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return selected as Readonly<ShallowRef<PredictiveSearchState<TData> | S>>;\n}\n\n/**\n * Returns `search` and `clear` methods that delegate to the current store.\n *\n * These are thin wrappers that read from the reactive store ref on each call,\n * so they always target the active store even after a provider prop change\n * triggers store recreation.\n *\n * Must be used inside a {@link PredictiveSearchProvider}.\n *\n * @throws {Error} When called outside a PredictiveSearchProvider.\n */\nexport function usePredictiveSearchActions(): PredictiveSearchActions {\n const { storeRef } = useRequiredContext(\"usePredictiveSearchActions\");\n\n return {\n search: (term) => storeRef.value.search(term),\n clear: () => storeRef.value.clear(),\n };\n}\n\n/**\n * Returns `formProps` and `register` for building a progressively-enhanced\n * search form.\n *\n * `formProps()` generates form element attributes including the search\n * action URL. `register(\"query\")` generates input attributes and calls the\n * store's search action on every `input` event. The store debounces requests\n * and resets state for terms shorter than `minTermLength`.\n * Both support an optional callback that receives the event and extracted\n * term, and respect `event.preventDefault()` to cancel the automatic behavior.\n *\n * Must be used inside a {@link PredictiveSearchProvider}.\n *\n * @throws {Error} When called outside a PredictiveSearchProvider.\n */\nexport function usePredictiveSearchForm(): PredictiveSearchFormResult {\n const { storeRef, searchActionRef } = useRequiredContext(\"usePredictiveSearchForm\");\n const coreRegister = createPredictiveSearchFormRegister();\n\n function register(\n field: \"query\",\n options: PredictiveSearchQueryInputPropsOptions = {},\n ): Record<string, unknown> {\n const { onInput, ...attributes } = options;\n const coreAttributes = coreRegister(field);\n\n return {\n ...attributes,\n ...coreAttributes,\n onInput: (event: Event) => {\n const term = (event.target as HTMLInputElement).value;\n onInput?.(event, term);\n if (event.defaultPrevented) return;\n void storeRef.value.search(term);\n },\n };\n }\n\n function formProps(options: PredictiveSearchFormPropsOptions = {}): Record<string, unknown> {\n const { onSubmit, preventDefault, ...attributes } = options;\n\n return {\n ...getPredictiveSearchFormAttributes(searchActionRef.value),\n ...attributes,\n onSubmit: (event: SubmitEvent) => {\n const term = readPredictiveSearchFormTerm(\n new FormData(event.currentTarget as HTMLFormElement),\n );\n onSubmit?.(event, term);\n if (event.defaultPrevented) return;\n if (!preventDefault) return;\n event.preventDefault();\n void storeRef.value.search(term);\n },\n };\n }\n\n return { formProps, register };\n}\n"],"mappings":"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"}
|
package/dist/vue/product.d.mts
CHANGED
|
@@ -5,22 +5,26 @@ import { ProductFormRegister } from "../core/product/form.mjs";
|
|
|
5
5
|
import { ShallowRef, defineComponent } from "vue";
|
|
6
6
|
|
|
7
7
|
//#region src/vue/product.d.ts
|
|
8
|
+
/** Options for {@link useProductForm}. */
|
|
8
9
|
interface UseProductFormOptions<TProduct extends ProductInput> {
|
|
9
10
|
onSelect?: (result: ValidProductSelectionResult<TProduct>) => void;
|
|
10
11
|
}
|
|
12
|
+
/** Return value of {@link useProductForm}. */
|
|
11
13
|
interface UseProductFormResult<TProduct extends ProductInput> {
|
|
12
14
|
options: ProductFormOptions<TProduct>;
|
|
13
15
|
selectedVariant: ProductVariantFrom<TProduct> | null;
|
|
14
16
|
register: ProductFormRegister;
|
|
15
17
|
formProps: (opts?: {
|
|
16
|
-
beforeSubmit?: (e:
|
|
17
|
-
afterSubmit?: (e:
|
|
18
|
+
beforeSubmit?: (e: SubmitEvent) => void;
|
|
19
|
+
afterSubmit?: (e: SubmitEvent) => void;
|
|
18
20
|
}) => Record<string, unknown>;
|
|
19
21
|
errors: ProductFormErrors;
|
|
20
22
|
matchedLineItem: CartLine | null;
|
|
23
|
+
/** Reactive ref that is `true` while a form submission is in flight. */
|
|
21
24
|
pending: ShallowRef<boolean>;
|
|
22
25
|
selectOption: (name: string, value: string) => VariantSelectionResult<ProductVariantFrom<TProduct>>;
|
|
23
26
|
}
|
|
27
|
+
/** Return value of the `useProduct` composable from {@link createProductComponents}. */
|
|
24
28
|
interface UseProductResult<TProduct extends ProductInput> {
|
|
25
29
|
options: ProductFormOptions<TProduct>;
|
|
26
30
|
selectedVariant: ProductVariantFrom<TProduct> | null;
|
package/dist/vue/product.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product.mjs","names":[],"sources":["../../src/vue/product.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onScopeDispose,\n onUnmounted,\n provide,\n shallowRef,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport type { CartLine } from \"../core/cart/state\";\nimport { getLogger } from \"../core/logging\";\nimport {\n createProductFormRegister,\n createProductFormStore,\n type ProductFormErrors,\n type ProductFormOptions,\n type ProductFormRegister,\n type ProductFormStore,\n type ProductInput,\n type ProductVariantFrom,\n type ValidProductSelectionResult,\n type VariantSelectionResult,\n} from \"../core/product\";\nimport { getCartEndpoint, useCartStore } from \"./cart\";\n\nconst log = getLogger(\"product\");\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport type { ValidProductSelectionResult } from \"../core/product\";\n\nexport interface UseProductFormOptions<TProduct extends ProductInput> {\n onSelect?: (result: ValidProductSelectionResult<TProduct>) => void;\n}\n\nexport interface UseProductFormResult<TProduct extends ProductInput> {\n options: ProductFormOptions<TProduct>;\n selectedVariant: ProductVariantFrom<TProduct> | null;\n register: ProductFormRegister;\n formProps: (opts?: {\n beforeSubmit?: (e: Event) => void;\n afterSubmit?: (e: Event) => void;\n }) => Record<string, unknown>;\n errors: ProductFormErrors;\n matchedLineItem: CartLine | null;\n pending: ShallowRef<boolean>;\n selectOption: (\n name: string,\n value: string,\n ) => VariantSelectionResult<ProductVariantFrom<TProduct>>;\n}\n\nexport interface UseProductResult<TProduct extends ProductInput> {\n options: ProductFormOptions<TProduct>;\n selectedVariant: ProductVariantFrom<TProduct> | null;\n selectOption: (\n name: string,\n value: string,\n ) => VariantSelectionResult<ProductVariantFrom<TProduct>>;\n errors: ProductFormErrors;\n matchedLineItem: CartLine | null;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ninterface ProductContextValue<TProduct extends ProductInput> {\n store: ProductFormStore<TProduct>;\n getOnSelect: () => ((result: ValidProductSelectionResult<TProduct>) => void) | undefined;\n}\n\n/**\n * Shared implementation backing both the standalone composable and the factory\n * composable. Accepts a `getOnSelect` getter so the factory version can always\n * read the latest provider prop, while the standalone version captures the\n * caller's callback at setup time.\n */\nfunction useProductFormImpl<TProduct extends ProductInput>(\n store: ProductFormStore<TProduct>,\n getOnSelect: () => ((result: ValidProductSelectionResult<TProduct>) => void) | undefined,\n): UseProductFormResult<TProduct> {\n const state = shallowRef(store.getState());\n const pending = shallowRef(false);\n\n const unsubscribe = store.subscribe(() => {\n state.value = store.getState();\n });\n onScopeDispose(unsubscribe);\n\n function selectOption(\n name: string,\n value: string,\n ): VariantSelectionResult<ProductVariantFrom<TProduct>> {\n const result = store.selectOption(name, value);\n if (result.status !== \"invalid\") {\n getOnSelect()?.(result);\n }\n return result;\n }\n\n function formProps(opts?: {\n beforeSubmit?: (e: Event) => void;\n afterSubmit?: (e: Event) => void;\n }): Record<string, unknown> {\n return {\n onSubmit: (e: Event) => {\n opts?.beforeSubmit?.(e);\n if (e.defaultPrevented) return;\n e.preventDefault();\n pending.value = true;\n store\n .handleFormSubmit(e as SubmitEvent)\n .then(\n () => opts?.afterSubmit?.(e),\n (error: unknown) => {\n log.error(\"form submission error\", { error });\n },\n )\n .finally(() => {\n pending.value = false;\n });\n },\n method: \"post\",\n action: getCartEndpoint(),\n };\n }\n\n return {\n get options() {\n return state.value.options;\n },\n get selectedVariant() {\n return state.value.selectedVariant;\n },\n get register() {\n return createProductFormRegister(state.value.selectedVariant, selectOption);\n },\n formProps,\n get errors() {\n return state.value.errors;\n },\n get matchedLineItem() {\n return state.value.matchedLineItem;\n },\n pending,\n selectOption,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Standalone composable\n// ---------------------------------------------------------------------------\n\n/**\n * Subscribes to a {@link ProductFormStore} and returns form-ready state.\n *\n * This is a pure subscription composable — it does **not** manage store\n * lifecycle. Create the store with `createProductFormStore` and manage its\n * lifecycle (hydration, destruction) yourself, or use\n * `createProductComponents` for a provider-based approach.\n */\nexport function useProductForm<TProduct extends ProductInput>(\n store: ProductFormStore<TProduct>,\n options?: UseProductFormOptions<TProduct>,\n): UseProductFormResult<TProduct> {\n const onSelect = options?.onSelect;\n return useProductFormImpl(store, () => onSelect);\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a typed set of product components bound to a specific product type.\n *\n * Returns `{ ProductProvider, useProduct, useProductForm }` where:\n * - `ProductProvider` manages store lifecycle (creation, hydration, cleanup)\n * - `useProduct` provides read-only state and variant selection\n * - `useProductForm` provides form-binding utilities (register, formProps, pending)\n *\n * Requires a `<CartProvider>` ancestor.\n */\nexport function createProductComponents<TProduct extends ProductInput>(): {\n ProductProvider: ReturnType<typeof defineComponent>;\n useProduct: () => UseProductResult<TProduct>;\n useProductForm: () => UseProductFormResult<TProduct>;\n} {\n const ProductStoreKey: InjectionKey<ProductContextValue<TProduct>> = Symbol(\"ProductFormStore\");\n\n function useProductContext(composableName: string): ProductContextValue<TProduct> {\n const ctx = inject(ProductStoreKey);\n if (!ctx) {\n throw new Error(\n `${composableName} must be used inside a <ProductProvider>. ` +\n \"Wrap your component tree with the ProductProvider from createProductComponents(), \" +\n \"or use the standalone useProductForm(store) composable instead.\",\n );\n }\n return ctx;\n }\n\n const ProductProvider = defineComponent({\n name: \"ProductProvider\",\n props: {\n product: {\n type: Object as PropType<TProduct>,\n required: true,\n },\n onSelect: {\n type: Function as PropType<(result: ValidProductSelectionResult<TProduct>) => void>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n const product = props.product as TProduct;\n const cartStore = useCartStore();\n const store = createProductFormStore<TProduct>(product, cartStore);\n\n provide(ProductStoreKey, {\n store,\n getOnSelect: () =>\n props.onSelect as ((result: ValidProductSelectionResult<TProduct>) => void) | undefined,\n });\n\n let mounted = false;\n watch(\n () => {\n const p = props.product as TProduct;\n return `${p.id}:${p.selectedOrFirstAvailableVariant?.id ?? \"\"}`;\n },\n () => {\n if (!mounted) {\n mounted = true;\n return;\n }\n store.hydrate(props.product as TProduct);\n },\n { immediate: true },\n );\n\n onUnmounted(() => store.destroy());\n\n return () => slots.default?.();\n },\n });\n\n function useProduct(): UseProductResult<TProduct> {\n const ctx = useProductContext(\"useProduct\");\n const state = shallowRef(ctx.store.getState());\n\n const unsubscribe = ctx.store.subscribe(() => {\n state.value = ctx.store.getState();\n });\n onScopeDispose(unsubscribe);\n\n function selectOption(\n name: string,\n value: string,\n ): VariantSelectionResult<ProductVariantFrom<TProduct>> {\n const result = ctx.store.selectOption(name, value);\n if (result.status !== \"invalid\") {\n ctx.getOnSelect()?.(result);\n }\n return result;\n }\n\n return {\n get options() {\n return state.value.options;\n },\n get selectedVariant() {\n return state.value.selectedVariant;\n },\n selectOption,\n get errors() {\n return state.value.errors;\n },\n get matchedLineItem() {\n return state.value.matchedLineItem;\n },\n };\n }\n\n function useProductFormHook(): UseProductFormResult<TProduct> {\n const ctx = useProductContext(\"useProductForm\");\n return useProductFormImpl(ctx.store, ctx.getOnSelect);\n }\n\n return {\n ProductProvider,\n useProduct,\n useProductForm: useProductFormHook,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"product.mjs","names":[],"sources":["../../src/vue/product.ts"],"sourcesContent":["import {\n defineComponent,\n inject,\n onScopeDispose,\n onUnmounted,\n provide,\n shallowRef,\n watch,\n type InjectionKey,\n type PropType,\n type ShallowRef,\n} from \"vue\";\n\nimport type { CartLine } from \"../core/cart/state\";\nimport { getLogger } from \"../core/logging\";\nimport {\n createProductFormRegister,\n createProductFormStore,\n type ProductFormErrors,\n type ProductFormOptions,\n type ProductFormRegister,\n type ProductFormStore,\n type ProductInput,\n type ProductVariantFrom,\n type ValidProductSelectionResult,\n type VariantSelectionResult,\n} from \"../core/product\";\nimport { getCartEndpoint, useCartStore } from \"./cart\";\n\nconst log = getLogger(\"product\");\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport type { ValidProductSelectionResult } from \"../core/product\";\n\n/** Options for {@link useProductForm}. */\nexport interface UseProductFormOptions<TProduct extends ProductInput> {\n onSelect?: (result: ValidProductSelectionResult<TProduct>) => void;\n}\n\n/** Return value of {@link useProductForm}. */\nexport interface UseProductFormResult<TProduct extends ProductInput> {\n options: ProductFormOptions<TProduct>;\n selectedVariant: ProductVariantFrom<TProduct> | null;\n register: ProductFormRegister;\n formProps: (opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }) => Record<string, unknown>;\n errors: ProductFormErrors;\n matchedLineItem: CartLine | null;\n /** Reactive ref that is `true` while a form submission is in flight. */\n pending: ShallowRef<boolean>;\n selectOption: (\n name: string,\n value: string,\n ) => VariantSelectionResult<ProductVariantFrom<TProduct>>;\n}\n\n/** Return value of the `useProduct` composable from {@link createProductComponents}. */\nexport interface UseProductResult<TProduct extends ProductInput> {\n options: ProductFormOptions<TProduct>;\n selectedVariant: ProductVariantFrom<TProduct> | null;\n selectOption: (\n name: string,\n value: string,\n ) => VariantSelectionResult<ProductVariantFrom<TProduct>>;\n errors: ProductFormErrors;\n matchedLineItem: CartLine | null;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ninterface ProductContextValue<TProduct extends ProductInput> {\n store: ProductFormStore<TProduct>;\n getOnSelect: () => ((result: ValidProductSelectionResult<TProduct>) => void) | undefined;\n}\n\n/**\n * Shared implementation backing both the standalone composable and the factory\n * composable. Accepts a `getOnSelect` getter so the factory version can always\n * read the latest provider prop, while the standalone version captures the\n * caller's callback at setup time.\n */\nfunction useProductFormImpl<TProduct extends ProductInput>(\n store: ProductFormStore<TProduct>,\n getOnSelect: () => ((result: ValidProductSelectionResult<TProduct>) => void) | undefined,\n): UseProductFormResult<TProduct> {\n const state = shallowRef(store.getState());\n const pending = shallowRef(false);\n\n const unsubscribe = store.subscribe(() => {\n state.value = store.getState();\n });\n onScopeDispose(unsubscribe);\n\n function selectOption(\n name: string,\n value: string,\n ): VariantSelectionResult<ProductVariantFrom<TProduct>> {\n const result = store.selectOption(name, value);\n if (result.status !== \"invalid\") {\n getOnSelect()?.(result);\n }\n return result;\n }\n\n function formProps(opts?: {\n beforeSubmit?: (e: SubmitEvent) => void;\n afterSubmit?: (e: SubmitEvent) => void;\n }): Record<string, unknown> {\n return {\n onSubmit: (e: SubmitEvent) => {\n opts?.beforeSubmit?.(e);\n if (e.defaultPrevented) return;\n e.preventDefault();\n pending.value = true;\n store\n .handleFormSubmit(e)\n .then(\n () => opts?.afterSubmit?.(e),\n (error: unknown) => {\n log.error(\"form submission error\", { error });\n },\n )\n .finally(() => {\n pending.value = false;\n });\n },\n method: \"post\",\n action: getCartEndpoint(),\n };\n }\n\n return {\n get options() {\n return state.value.options;\n },\n get selectedVariant() {\n return state.value.selectedVariant;\n },\n get register() {\n return createProductFormRegister(state.value.selectedVariant, selectOption);\n },\n formProps,\n get errors() {\n return state.value.errors;\n },\n get matchedLineItem() {\n return state.value.matchedLineItem;\n },\n pending,\n selectOption,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Standalone composable\n// ---------------------------------------------------------------------------\n\n/**\n * Subscribes to a {@link ProductFormStore} and returns form-ready state.\n *\n * This is a pure subscription composable — it does **not** manage store\n * lifecycle. Create the store with `createProductFormStore` and manage its\n * lifecycle (hydration, destruction) yourself, or use\n * `createProductComponents` for a provider-based approach.\n */\nexport function useProductForm<TProduct extends ProductInput>(\n store: ProductFormStore<TProduct>,\n options?: UseProductFormOptions<TProduct>,\n): UseProductFormResult<TProduct> {\n const onSelect = options?.onSelect;\n return useProductFormImpl(store, () => onSelect);\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a typed set of product components bound to a specific product type.\n *\n * Returns `{ ProductProvider, useProduct, useProductForm }` where:\n * - `ProductProvider` manages store lifecycle (creation, hydration, cleanup)\n * - `useProduct` provides read-only state and variant selection\n * - `useProductForm` provides form-binding utilities (register, formProps, pending)\n *\n * Requires a `<CartProvider>` ancestor.\n */\nexport function createProductComponents<TProduct extends ProductInput>(): {\n ProductProvider: ReturnType<typeof defineComponent>;\n useProduct: () => UseProductResult<TProduct>;\n useProductForm: () => UseProductFormResult<TProduct>;\n} {\n const ProductStoreKey: InjectionKey<ProductContextValue<TProduct>> = Symbol(\"ProductFormStore\");\n\n function useProductContext(composableName: string): ProductContextValue<TProduct> {\n const ctx = inject(ProductStoreKey);\n if (!ctx) {\n throw new Error(\n `${composableName} must be used inside a <ProductProvider>. ` +\n \"Wrap your component tree with the ProductProvider from createProductComponents(), \" +\n \"or use the standalone useProductForm(store) composable instead.\",\n );\n }\n return ctx;\n }\n\n const ProductProvider = defineComponent({\n name: \"ProductProvider\",\n props: {\n product: {\n type: Object as PropType<TProduct>,\n required: true,\n },\n onSelect: {\n type: Function as PropType<(result: ValidProductSelectionResult<TProduct>) => void>,\n default: undefined,\n },\n },\n setup(props, { slots }) {\n const product = props.product as TProduct;\n const cartStore = useCartStore();\n const store = createProductFormStore<TProduct>(product, cartStore);\n\n provide(ProductStoreKey, {\n store,\n getOnSelect: () =>\n props.onSelect as ((result: ValidProductSelectionResult<TProduct>) => void) | undefined,\n });\n\n let mounted = false;\n watch(\n () => {\n const p = props.product as TProduct;\n return `${p.id}:${p.selectedOrFirstAvailableVariant?.id ?? \"\"}`;\n },\n () => {\n if (!mounted) {\n mounted = true;\n return;\n }\n store.hydrate(props.product as TProduct);\n },\n { immediate: true },\n );\n\n onUnmounted(() => store.destroy());\n\n return () => slots.default?.();\n },\n });\n\n function useProduct(): UseProductResult<TProduct> {\n const ctx = useProductContext(\"useProduct\");\n const state = shallowRef(ctx.store.getState());\n\n const unsubscribe = ctx.store.subscribe(() => {\n state.value = ctx.store.getState();\n });\n onScopeDispose(unsubscribe);\n\n function selectOption(\n name: string,\n value: string,\n ): VariantSelectionResult<ProductVariantFrom<TProduct>> {\n const result = ctx.store.selectOption(name, value);\n if (result.status !== \"invalid\") {\n ctx.getOnSelect()?.(result);\n }\n return result;\n }\n\n return {\n get options() {\n return state.value.options;\n },\n get selectedVariant() {\n return state.value.selectedVariant;\n },\n selectOption,\n get errors() {\n return state.value.errors;\n },\n get matchedLineItem() {\n return state.value.matchedLineItem;\n },\n };\n }\n\n function useProductFormHook(): UseProductFormResult<TProduct> {\n const ctx = useProductContext(\"useProductForm\");\n return useProductFormImpl(ctx.store, ctx.getOnSelect);\n }\n\n return {\n ProductProvider,\n useProduct,\n useProductForm: useProductFormHook,\n };\n}\n"],"mappings":"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"}
|