@jay-framework/wix-stores 0.19.6 → 0.19.7

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.
@@ -25,19 +25,33 @@ items:
25
25
  Script key: p
26
26
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
27
27
 
28
- - id: wix-stores:related-products
29
- title: Related products
28
+ - id: wix-stores:category-products
29
+ title: Category products
30
30
  category: Store
31
31
  subCategory: Components
32
32
  pluginName: wix-stores
33
33
  packageName: "@jay-framework/wix-stores"
34
- thumbnail: thumbnails/wix-stores/related-products.png
34
+ thumbnail: thumbnails/wix-stores/category-products.png
35
35
  prompt: |
36
- Use headless component @jay-framework/wix-stores / contract related-products.
37
- Read agent-kit/materialized-contracts/wix-stores/related-products.jay-contract.
36
+ Use headless component @jay-framework/wix-stores / contract category-products.
37
+ Read agent-kit/materialized-contracts/wix-stores/category-products.jay-contract.
38
38
  Script key: r
39
39
  Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
40
- Use alongside product-page; pass productId and categorySlug as instance props.
40
+ Pass categorySlug to show products from a category. Pass productId to exclude a product (e.g. on a product page).
41
+
42
+ - id: wix-stores:product-spotlight
43
+ title: Product spotlight
44
+ category: Store
45
+ subCategory: Components
46
+ pluginName: wix-stores
47
+ packageName: "@jay-framework/wix-stores"
48
+ thumbnail: thumbnails/wix-stores/product-spotlight.png
49
+ prompt: |
50
+ Use headless component @jay-framework/wix-stores / contract product-spotlight.
51
+ Read agent-kit/materialized-contracts/wix-stores/product-spotlight.jay-contract.
52
+ Script key: spotlight
53
+ Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md.
54
+ Pass slug as a prop to specify which product to display.
41
55
 
42
56
  - id: wix-stores:category-list
43
57
  title: Category list
@@ -0,0 +1,31 @@
1
+ name: category-products
2
+ description: Products from a specific category. Use for category product showcases, or as related products on a product page (pass productId to exclude the current product).
3
+ props:
4
+ - name: productId
5
+ type: string
6
+ description: Product ID to exclude from results (optional, use for related products)
7
+ - name: categorySlug
8
+ type: string
9
+ description: Category slug to filter products by
10
+ - name: limit
11
+ type: number
12
+ description: Maximum number of products to show (default 4)
13
+ tags:
14
+ - tag: products
15
+ type: sub-contract
16
+ repeated: true
17
+ trackBy: _id
18
+ phase: fast+interactive
19
+ description: Product cards from the category
20
+ link: ./product-card
21
+
22
+ - tag: hasProducts
23
+ type: variant
24
+ dataType: boolean
25
+ phase: fast+interactive
26
+ description: Whether there are products to show
27
+
28
+ - tag: categoryName
29
+ type: data
30
+ dataType: string
31
+ description: Name of the category these products belong to
@@ -0,0 +1,36 @@
1
+ import {JayContract} from "@jay-framework/runtime";
2
+ import {ProductCardViewState, ProductCardRefs, ProductCardRepeatedRefs} from "./product-card.jay-contract";
3
+
4
+ export interface CategoryProductsViewState {
5
+ products: Array<ProductCardViewState>,
6
+ hasProducts: boolean,
7
+ categoryName: string
8
+ }
9
+
10
+ export type CategoryProductsSlowViewState = Pick<CategoryProductsViewState, 'categoryName'>;
11
+
12
+ export type CategoryProductsFastViewState = Pick<CategoryProductsViewState, 'hasProducts'> & {
13
+ products: Array<CategoryProductsViewState['products'][number]>;
14
+ };
15
+
16
+ export type CategoryProductsInteractiveViewState = Pick<CategoryProductsViewState, 'hasProducts'> & {
17
+ products: Array<CategoryProductsViewState['products'][number]>;
18
+ };
19
+
20
+
21
+ export interface CategoryProductsRefs {
22
+ products: ProductCardRepeatedRefs
23
+ }
24
+
25
+
26
+ export interface CategoryProductsRepeatedRefs {
27
+ products: ProductCardRepeatedRefs
28
+ }
29
+
30
+ export interface CategoryProductsProps {
31
+ productId?: string;
32
+ categorySlug?: string;
33
+ limit?: number;
34
+ }
35
+
36
+ export type CategoryProductsContract = JayContract<CategoryProductsViewState, CategoryProductsRefs, CategoryProductsSlowViewState, CategoryProductsFastViewState, CategoryProductsInteractiveViewState, CategoryProductsProps>
@@ -0,0 +1,16 @@
1
+ name: product-spotlight
2
+ description: A single product card by slug. Use to feature a specific product on any page (homepage, content pages, etc.).
3
+ props:
4
+ - name: slug
5
+ type: string
6
+ description: Product slug to display
7
+ tags:
8
+ - tag: product
9
+ type: sub-contract
10
+ description: The product card
11
+ link: ./product-card
12
+
13
+ - tag: hasProduct
14
+ type: variant
15
+ dataType: boolean
16
+ description: Whether the product was found
@@ -0,0 +1,61 @@
1
+ import {JayContract} from "@jay-framework/runtime";
2
+ import {ProductCardViewState, ProductCardRefs, ProductCardRepeatedRefs} from "./product-card.jay-contract";
3
+
4
+ export interface ProductSpotlightViewState {
5
+ product: ProductCardViewState,
6
+ hasProduct: boolean
7
+ }
8
+
9
+ export type ProductSpotlightSlowViewState = Pick<ProductSpotlightViewState, 'hasProduct'> & {
10
+ product: Pick<ProductSpotlightViewState['product'], '_id' | 'name' | 'slug' | 'productUrl' | 'categoryPrefix' | 'hasDiscount' | 'hasRibbon' | 'productType' | 'quickAddType'> & {
11
+ mainMedia: ProductSpotlightViewState['product']['mainMedia'];
12
+ thumbnail: ProductSpotlightViewState['product']['thumbnail'];
13
+ inventory: ProductSpotlightViewState['product']['inventory'];
14
+ ribbon: ProductSpotlightViewState['product']['ribbon'];
15
+ brand: ProductSpotlightViewState['product']['brand'];
16
+ quickOption: Pick<ProductSpotlightViewState['product']['quickOption'], '_id' | 'name' | 'optionRenderType'> & {
17
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'name' | 'choiceType' | 'colorCode'>>;
18
+ };
19
+ secondQuickOption: Pick<ProductSpotlightViewState['product']['secondQuickOption'], '_id' | 'name' | 'optionRenderType'> & {
20
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'name' | 'choiceType' | 'colorCode'>>;
21
+ };
22
+ };
23
+ };
24
+
25
+ export type ProductSpotlightFastViewState = {
26
+ product: Pick<ProductSpotlightViewState['product'], 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
27
+ quickOption: {
28
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
29
+ };
30
+ secondQuickOption: {
31
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
32
+ };
33
+ };
34
+ };
35
+
36
+ export type ProductSpotlightInteractiveViewState = {
37
+ product: Pick<ProductSpotlightViewState['product'], 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
38
+ quickOption: {
39
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
40
+ };
41
+ secondQuickOption: {
42
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
43
+ };
44
+ };
45
+ };
46
+
47
+
48
+ export interface ProductSpotlightRefs {
49
+ product: ProductCardRefs
50
+ }
51
+
52
+
53
+ export interface ProductSpotlightRepeatedRefs {
54
+ product: ProductCardRepeatedRefs
55
+ }
56
+
57
+ export interface ProductSpotlightProps {
58
+ slug?: string;
59
+ }
60
+
61
+ export type ProductSpotlightContract = JayContract<ProductSpotlightViewState, ProductSpotlightRefs, ProductSpotlightSlowViewState, ProductSpotlightFastViewState, ProductSpotlightInteractiveViewState, ProductSpotlightProps>
@@ -886,7 +886,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
886
886
  };
887
887
  }
888
888
  const productSearch = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(ProductSearchInteractive);
889
- function RelatedProductsInteractive(_props, refs, viewStateSignals, _fastCarryForward, storesContext) {
889
+ function CategoryProductsInteractive(_props, refs, viewStateSignals, _fastCarryForward, storesContext) {
890
890
  const { products: [products, setProducts], hasProducts: [hasProducts] } = viewStateSignals;
891
891
  setupCardInteractions(refs.products, { get: products, set: setProducts }, storesContext);
892
892
  return {
@@ -896,7 +896,34 @@ function RelatedProductsInteractive(_props, refs, viewStateSignals, _fastCarryFo
896
896
  })
897
897
  };
898
898
  }
899
- const relatedProducts = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(RelatedProductsInteractive);
899
+ const categoryProducts = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(CategoryProductsInteractive);
900
+ function ProductSpotlightInteractive(_props, refs, viewStateSignals, fastCarryForward, storesContext) {
901
+ const { product: [product, setProduct] } = viewStateSignals;
902
+ const fullProduct = fastCarryForward.product;
903
+ refs.product.addToCartButton.onclick(async () => {
904
+ if (!fullProduct._id || fullProduct.quickAddType !== QuickAddType.SIMPLE)
905
+ return;
906
+ setProduct({ ...product(), isAddingToCart: true });
907
+ try {
908
+ await storesContext.addToCart(fullProduct._id, 1);
909
+ } catch (error) {
910
+ console.error("Failed to add to cart:", error);
911
+ } finally {
912
+ setProduct({ ...product(), isAddingToCart: false });
913
+ }
914
+ });
915
+ refs.product.viewOptionsButton.onclick(() => {
916
+ if (fullProduct.productUrl) {
917
+ window.location.href = fullProduct.productUrl;
918
+ }
919
+ });
920
+ return {
921
+ render: () => ({
922
+ product: product()
923
+ })
924
+ };
925
+ }
926
+ const productSpotlight = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(ProductSpotlightInteractive);
900
927
  const categoryList = makeJayStackComponent().withProps();
901
928
  const init = makeJayInit().withClient(async (data) => {
902
929
  console.log("[wix-stores] Initializing client-side stores context...");
@@ -909,9 +936,10 @@ export {
909
936
  cartIndicator,
910
937
  cartPage,
911
938
  categoryList,
939
+ categoryProducts,
912
940
  init,
913
941
  productPage,
914
942
  productSearch,
915
- provideWixStoresContext,
916
- relatedProducts
943
+ productSpotlight,
944
+ provideWixStoresContext
917
945
  };
package/dist/index.d.ts CHANGED
@@ -41,6 +41,13 @@ interface ProductOptionsViewState {
41
41
  }
42
42
 
43
43
 
44
+ interface ProductOptionsRefs {
45
+ choices: {
46
+ choiceButton: HTMLElementCollectionProxy<ChoiceOfProductOptionsViewState, HTMLButtonElement>
47
+ }
48
+ }
49
+
50
+
44
51
  interface ProductOptionsRepeatedRefs {
45
52
  choices: {
46
53
  choiceButton: HTMLElementCollectionProxy<ChoiceOfProductOptionsViewState, HTMLButtonElement>
@@ -127,6 +134,16 @@ interface ProductCardViewState {
127
134
  }
128
135
 
129
136
 
137
+ interface ProductCardRefs {
138
+ productLink: HTMLElementProxy<ProductCardViewState, HTMLAnchorElement>,
139
+ addToCartButton: HTMLElementProxy<ProductCardViewState, HTMLButtonElement>,
140
+ cardContainer: HTMLElementProxy<ProductCardViewState, HTMLElement>,
141
+ viewOptionsButton: HTMLElementProxy<ProductCardViewState, HTMLButtonElement>,
142
+ quickOption: ProductOptionsRefs,
143
+ secondQuickOption: ProductOptionsRefs
144
+ }
145
+
146
+
130
147
  interface ProductCardRepeatedRefs {
131
148
  productLink: HTMLElementCollectionProxy<ProductCardViewState, HTMLAnchorElement>,
132
149
  addToCartButton: HTMLElementCollectionProxy<ProductCardViewState, HTMLButtonElement>,
@@ -865,36 +882,92 @@ interface ProductFastCarryForward {
865
882
  */
866
883
  declare const productPage: _jay_framework_fullstack_component.JayStackComponentDefinition<ProductPageRefs, ProductPageSlowViewState, ProductPageFastViewState, ProductPageInteractiveViewState, [ProductSlowCarryForward, WixStoresService], [Signals<ProductPageFastViewState>, ProductFastCarryForward, WixStoresContext], PageProps & ProductPageParams, ProductPageParams, _jay_framework_component.JayComponentCore<PageProps & ProductPageParams, ProductPageInteractiveViewState>>;
867
884
 
868
- interface RelatedProductsViewState {
885
+ interface CategoryProductsViewState {
869
886
  products: Array<ProductCardViewState>,
870
887
  hasProducts: boolean,
871
888
  categoryName: string
872
889
  }
873
890
 
874
- type RelatedProductsSlowViewState = Pick<RelatedProductsViewState, 'categoryName'>;
891
+ type CategoryProductsSlowViewState = Pick<CategoryProductsViewState, 'categoryName'>;
875
892
 
876
- type RelatedProductsFastViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
877
- products: Array<RelatedProductsViewState['products'][number]>;
893
+ type CategoryProductsFastViewState = Pick<CategoryProductsViewState, 'hasProducts'> & {
894
+ products: Array<CategoryProductsViewState['products'][number]>;
878
895
  };
879
896
 
880
- type RelatedProductsInteractiveViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
881
- products: Array<RelatedProductsViewState['products'][number]>;
897
+ type CategoryProductsInteractiveViewState = Pick<CategoryProductsViewState, 'hasProducts'> & {
898
+ products: Array<CategoryProductsViewState['products'][number]>;
882
899
  };
883
900
 
884
901
 
885
- interface RelatedProductsRefs {
902
+ interface CategoryProductsRefs {
886
903
  products: ProductCardRepeatedRefs
887
904
  }
888
905
 
889
- interface RelatedProductsProps {
890
- productId: string;
906
+ interface CategoryProductsProps {
907
+ productId?: string;
891
908
  categorySlug?: string;
892
909
  limit?: number;
893
910
  }
894
- interface RelatedSlowCarryForward {
911
+ interface SlowCarryForward {
895
912
  products: ProductCardViewState[];
896
913
  }
897
- declare const relatedProducts: _jay_framework_fullstack_component.JayStackComponentDefinition<RelatedProductsRefs, RelatedProductsSlowViewState, RelatedProductsFastViewState, RelatedProductsInteractiveViewState, [RelatedSlowCarryForward, WixStoresService], [Signals<RelatedProductsFastViewState>, Record<string, never>, WixStoresContext], PageProps & RelatedProductsProps, {}, _jay_framework_component.JayComponentCore<PageProps & RelatedProductsProps, RelatedProductsInteractiveViewState>>;
914
+ declare const categoryProducts: _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryProductsRefs, CategoryProductsSlowViewState, CategoryProductsFastViewState, CategoryProductsInteractiveViewState, [SlowCarryForward, WixStoresService], [Signals<CategoryProductsFastViewState>, Record<string, never>, WixStoresContext], PageProps & CategoryProductsProps, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryProductsProps, CategoryProductsInteractiveViewState>>;
915
+
916
+ interface ProductSpotlightViewState {
917
+ product: ProductCardViewState,
918
+ hasProduct: boolean
919
+ }
920
+
921
+ type ProductSpotlightSlowViewState = Pick<ProductSpotlightViewState, 'hasProduct'> & {
922
+ product: Pick<ProductSpotlightViewState['product'], '_id' | 'name' | 'slug' | 'productUrl' | 'categoryPrefix' | 'hasDiscount' | 'hasRibbon' | 'productType' | 'quickAddType'> & {
923
+ mainMedia: ProductSpotlightViewState['product']['mainMedia'];
924
+ thumbnail: ProductSpotlightViewState['product']['thumbnail'];
925
+ inventory: ProductSpotlightViewState['product']['inventory'];
926
+ ribbon: ProductSpotlightViewState['product']['ribbon'];
927
+ brand: ProductSpotlightViewState['product']['brand'];
928
+ quickOption: Pick<ProductSpotlightViewState['product']['quickOption'], '_id' | 'name' | 'optionRenderType'> & {
929
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'name' | 'choiceType' | 'colorCode'>>;
930
+ };
931
+ secondQuickOption: Pick<ProductSpotlightViewState['product']['secondQuickOption'], '_id' | 'name' | 'optionRenderType'> & {
932
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'name' | 'choiceType' | 'colorCode'>>;
933
+ };
934
+ };
935
+ };
936
+
937
+ type ProductSpotlightFastViewState = {
938
+ product: Pick<ProductSpotlightViewState['product'], 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
939
+ quickOption: {
940
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
941
+ };
942
+ secondQuickOption: {
943
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
944
+ };
945
+ };
946
+ };
947
+
948
+ type ProductSpotlightInteractiveViewState = {
949
+ product: Pick<ProductSpotlightViewState['product'], 'price' | 'strikethroughPrice' | 'isAddingToCart'> & {
950
+ quickOption: {
951
+ choices: Array<Pick<ProductSpotlightViewState['product']['quickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
952
+ };
953
+ secondQuickOption: {
954
+ choices: Array<Pick<ProductSpotlightViewState['product']['secondQuickOption']['choices'][number], 'choiceId' | 'inStock' | 'isSelected'>>;
955
+ };
956
+ };
957
+ };
958
+
959
+
960
+ interface ProductSpotlightRefs {
961
+ product: ProductCardRefs
962
+ }
963
+
964
+ interface ProductSpotlightProps {
965
+ slug: string;
966
+ }
967
+ interface SpotlightCarryForward {
968
+ product: ProductCardViewState;
969
+ }
970
+ declare const productSpotlight: _jay_framework_fullstack_component.JayStackComponentDefinition<ProductSpotlightRefs, ProductSpotlightSlowViewState, ProductSpotlightFastViewState, ProductSpotlightInteractiveViewState, [SpotlightCarryForward, WixStoresService], [Signals<ProductSpotlightFastViewState>, SpotlightCarryForward, WixStoresContext], PageProps & ProductSpotlightProps, {}, _jay_framework_component.JayComponentCore<PageProps & ProductSpotlightProps, ProductSpotlightInteractiveViewState>>;
898
971
 
899
972
  interface CategoryOfCategoryListViewState {
900
973
  _id: string,
@@ -1065,4 +1138,4 @@ declare function generateWixStoresReferences(ctx: PluginReferencesContext): Prom
1065
1138
  */
1066
1139
  declare const generator: _jay_framework_fullstack_component.DynamicContractGenerator<[WixStoresService]>;
1067
1140
 
1068
- export { type CategoryListParams, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, type RelatedProductsProps, WIX_STORES_CONTEXT, WIX_STORES_SERVICE_MARKER, type WixStoresContext, type WixStoresInitData, type WixStoresService, type WixStoresServiceOptions, buildCategoryUrl, buildProductUrl, categoryList, findCategoryImage, findRootCategoryId, findRootCategorySlug, generateWixStoresReferences, getCategories, getProductBySlug, getVariantStock, init, productPage, generator as productPageContractGenerator, productSearch, provideWixStoresService, relatedProducts, searchProducts, setupWixStores };
1141
+ export { type CategoryListParams, type CategoryProductsProps, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, type ProductSpotlightProps, WIX_STORES_CONTEXT, WIX_STORES_SERVICE_MARKER, type WixStoresContext, type WixStoresInitData, type WixStoresService, type WixStoresServiceOptions, buildCategoryUrl, buildProductUrl, categoryList, categoryProducts, findCategoryImage, findRootCategoryId, findRootCategorySlug, generateWixStoresReferences, getCategories, getProductBySlug, getVariantStock, init, productPage, generator as productPageContractGenerator, productSearch, productSpotlight, provideWixStoresService, searchProducts, setupWixStores };
package/dist/index.js CHANGED
@@ -716,6 +716,7 @@ const getProductBySlug = makeJayQuery("wixStores.getProductBySlug").withServices
716
716
  const fields = [
717
717
  "MEDIA_ITEMS_INFO",
718
718
  "VARIANT_OPTION_CHOICE_NAMES",
719
+ "CURRENCY",
719
720
  ...needsCategoryInfo(wixStores) ? ["ALL_CATEGORIES_INFO"] : []
720
721
  ];
721
722
  const result = await wixStores.products.getProductBySlug(slug, {
@@ -955,7 +956,7 @@ async function buildCategoryHeader(wixStoreService, category, categoryUrlTemplat
955
956
  }
956
957
  return header;
957
958
  }
958
- async function renderSlowlyChanging$3(props, wixStores) {
959
+ async function renderSlowlyChanging$4(props, wixStores) {
959
960
  const Pipeline = RenderPipeline.for();
960
961
  const categorySlug = props.category ?? null;
961
962
  const prefixSlug = props.prefix ?? null;
@@ -1028,7 +1029,7 @@ async function renderSlowlyChanging$3(props, wixStores) {
1028
1029
  };
1029
1030
  });
1030
1031
  }
1031
- async function renderFastChanging$2(props, slowCarryForward, _wixStores) {
1032
+ async function renderFastChanging$3(props, slowCarryForward, _wixStores) {
1032
1033
  const Pipeline = RenderPipeline.for();
1033
1034
  const urlFilters = parseUrlFilters(props.url);
1034
1035
  const initialSort = parseSortParam(urlFilters.sort);
@@ -1215,7 +1216,7 @@ async function* loadSearchParams([wixStores]) {
1215
1216
  yield [];
1216
1217
  }
1217
1218
  }
1218
- const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadSearchParams).withSlowlyRender(renderSlowlyChanging$3).withFastRender(renderFastChanging$2);
1219
+ const productSearch = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadSearchParams).withSlowlyRender(renderSlowlyChanging$4).withFastRender(renderFastChanging$3);
1219
1220
  var ProductType = /* @__PURE__ */ ((ProductType2) => {
1220
1221
  ProductType2[ProductType2["PHYSICAL"] = 0] = "PHYSICAL";
1221
1222
  ProductType2[ProductType2["DIGITAL"] = 1] = "DIGITAL";
@@ -1449,7 +1450,7 @@ function mapVariants(variantsInfo) {
1449
1450
  strikethroughPrice: variant.price.compareAtPrice?.formattedAmount || ""
1450
1451
  })) || [];
1451
1452
  }
1452
- async function renderSlowlyChanging$2(props, wixStores) {
1453
+ async function renderSlowlyChanging$3(props, wixStores) {
1453
1454
  const Pipeline = RenderPipeline.for();
1454
1455
  const template = wixStores.urls.product;
1455
1456
  const needsCategories = template.includes("{category}") || template.includes("{prefix}");
@@ -1505,7 +1506,7 @@ async function renderSlowlyChanging$2(props, wixStores) {
1505
1506
  };
1506
1507
  });
1507
1508
  }
1508
- async function renderFastChanging$1(props, slowCarryForward, wixStores) {
1509
+ async function renderFastChanging$2(props, slowCarryForward, wixStores) {
1509
1510
  const Pipeline = RenderPipeline.for();
1510
1511
  const { variants } = slowCarryForward;
1511
1512
  const defaultVariant = variants.find((v) => v.inventoryStatus === StockStatus.IN_STOCK) || variants[0];
@@ -1555,9 +1556,9 @@ async function renderFastChanging$1(props, slowCarryForward, wixStores) {
1555
1556
  }
1556
1557
  }));
1557
1558
  }
1558
- const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$2).withFastRender(renderFastChanging$1);
1559
+ const productPage = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withLoadParams(loadProductParams).withSlowlyRender(renderSlowlyChanging$3).withFastRender(renderFastChanging$2);
1559
1560
  const DEFAULT_LIMIT = 4;
1560
- async function renderSlowlyChanging$1(props, wixStores) {
1561
+ async function renderSlowlyChanging$2(props, wixStores) {
1561
1562
  const Pipeline = RenderPipeline.for();
1562
1563
  const limit = props.limit ?? DEFAULT_LIMIT;
1563
1564
  const categorySlug = props.categorySlug;
@@ -1601,7 +1602,7 @@ async function renderSlowlyChanging$1(props, wixStores) {
1601
1602
  carryForward: { products }
1602
1603
  }));
1603
1604
  }
1604
- async function renderFastChanging(_props, slowCarryForward, _wixStores) {
1605
+ async function renderFastChanging$1(_props, slowCarryForward, _wixStores) {
1605
1606
  const Pipeline = RenderPipeline.for();
1606
1607
  const { products } = slowCarryForward;
1607
1608
  return Pipeline.ok({
@@ -1609,7 +1610,95 @@ async function renderFastChanging(_props, slowCarryForward, _wixStores) {
1609
1610
  hasProducts: products.length > 0
1610
1611
  }).toPhaseOutput((viewState) => ({ viewState, carryForward: {} }));
1611
1612
  }
1612
- const relatedProducts = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
1613
+ const categoryProducts = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$2).withFastRender(renderFastChanging$1);
1614
+ async function renderSlowlyChanging$1(props, _wixStores) {
1615
+ const Pipeline = RenderPipeline.for();
1616
+ return Pipeline.try(async () => {
1617
+ if (!props.slug) {
1618
+ throw new Error("No product slug provided");
1619
+ }
1620
+ const card = await getProductBySlug({ slug: props.slug });
1621
+ if (!card) {
1622
+ throw new Error(`Product not found: ${props.slug}`);
1623
+ }
1624
+ return card;
1625
+ }).recover((error) => {
1626
+ return handleError(error);
1627
+ }).toPhaseOutput((product) => {
1628
+ return {
1629
+ viewState: {
1630
+ hasProduct: true,
1631
+ product: {
1632
+ _id: product._id,
1633
+ name: product.name,
1634
+ slug: product.slug,
1635
+ productUrl: product.productUrl,
1636
+ categoryPrefix: product.categoryPrefix,
1637
+ mainMedia: product.mainMedia,
1638
+ thumbnail: product.thumbnail,
1639
+ hasDiscount: product.hasDiscount,
1640
+ inventory: product.inventory,
1641
+ ribbon: product.ribbon,
1642
+ hasRibbon: product.hasRibbon,
1643
+ brand: product.brand,
1644
+ productType: product.productType,
1645
+ quickAddType: product.quickAddType,
1646
+ quickOption: {
1647
+ _id: product.quickOption?._id,
1648
+ name: product.quickOption?.name,
1649
+ optionRenderType: product.quickOption?.optionRenderType,
1650
+ choices: (product.quickOption?.choices ?? []).map((c) => ({
1651
+ choiceId: c.choiceId,
1652
+ name: c.name,
1653
+ choiceType: c.choiceType,
1654
+ colorCode: c.colorCode
1655
+ }))
1656
+ },
1657
+ secondQuickOption: {
1658
+ _id: product.secondQuickOption?._id,
1659
+ name: product.secondQuickOption?.name,
1660
+ optionRenderType: product.secondQuickOption?.optionRenderType,
1661
+ choices: (product.secondQuickOption?.choices ?? []).map((c) => ({
1662
+ choiceId: c.choiceId,
1663
+ name: c.name,
1664
+ choiceType: c.choiceType,
1665
+ colorCode: c.colorCode
1666
+ }))
1667
+ }
1668
+ }
1669
+ },
1670
+ carryForward: { product }
1671
+ };
1672
+ });
1673
+ }
1674
+ async function renderFastChanging(_props, carryForward, _wixStores) {
1675
+ const Pipeline = RenderPipeline.for();
1676
+ const { product } = carryForward;
1677
+ return Pipeline.ok({
1678
+ product: {
1679
+ price: product.price,
1680
+ strikethroughPrice: product.strikethroughPrice,
1681
+ isAddingToCart: false,
1682
+ quickOption: {
1683
+ choices: (product.quickOption?.choices ?? []).map((c) => ({
1684
+ choiceId: c.choiceId,
1685
+ inStock: c.inStock,
1686
+ isSelected: c.isSelected
1687
+ }))
1688
+ },
1689
+ secondQuickOption: {
1690
+ choices: (product.secondQuickOption?.choices ?? []).map((c) => ({
1691
+ choiceId: c.choiceId,
1692
+ inStock: c.inStock,
1693
+ isSelected: c.isSelected
1694
+ }))
1695
+ }
1696
+ }
1697
+ }).toPhaseOutput((viewState) => {
1698
+ return { viewState, carryForward: { product } };
1699
+ });
1700
+ }
1701
+ const productSpotlight = makeJayStackComponent().withProps().withServices(WIX_STORES_SERVICE_MARKER).withSlowlyRender(renderSlowlyChanging$1).withFastRender(renderFastChanging);
1613
1702
  async function findCategoryBySlug(categoriesClient, slug) {
1614
1703
  const result = await categoriesClient.queryCategories({ treeReference: { appNamespace: "@wix/stores" } }).eq("slug", slug).eq("visible", true).limit(1).find();
1615
1704
  return result.items?.[0] ?? null;
@@ -1807,12 +1896,12 @@ function buildCategoryPrompt(config, entry) {
1807
1896
  );
1808
1897
  }
1809
1898
  lines.push(
1810
- ` related-products — pass categorySlug="${node.slug}" alongside a productId when showing related items in this category`,
1899
+ ` category-products — pass categorySlug="${node.slug}" to show products from this category; optionally pass productId to exclude a product`,
1811
1900
  "",
1812
1901
  "Contracts:",
1813
1902
  " agent-kit/materialized-contracts/wix-stores/product-search.jay-contract",
1814
1903
  " agent-kit/materialized-contracts/wix-stores/category-list.jay-contract",
1815
- " agent-kit/materialized-contracts/wix-stores/related-products.jay-contract",
1904
+ " agent-kit/materialized-contracts/wix-stores/category-products.jay-contract",
1816
1905
  "",
1817
1906
  "Bind ViewState and refs per agent-kit/designer/INSTRUCTIONS.md."
1818
1907
  );
@@ -2276,6 +2365,7 @@ export {
2276
2365
  cartIndicator,
2277
2366
  cartPage,
2278
2367
  categoryList,
2368
+ categoryProducts,
2279
2369
  findCategoryImage,
2280
2370
  findRootCategoryId,
2281
2371
  findRootCategorySlug,
@@ -2287,10 +2377,10 @@ export {
2287
2377
  productPage,
2288
2378
  generator as productPageContractGenerator,
2289
2379
  productSearch,
2380
+ productSpotlight,
2290
2381
  provideWixCartContext,
2291
2382
  provideWixCartService,
2292
2383
  provideWixStoresService,
2293
- relatedProducts,
2294
2384
  searchProducts,
2295
2385
  setupWixStores
2296
2386
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/wix-stores",
3
- "version": "0.19.6",
3
+ "version": "0.19.7",
4
4
  "type": "module",
5
5
  "description": "Wix Stores API client for Jay Framework",
6
6
  "license": "Apache-2.0",
@@ -17,7 +17,8 @@
17
17
  "./media.jay-contract": "./dist/contracts/media.jay-contract",
18
18
  "./media-gallery.jay-contract": "./dist/contracts/media-gallery.jay-contract",
19
19
  "./product-search.jay-contract": "./dist/contracts/product-search.jay-contract",
20
- "./related-products.jay-contract": "./dist/contracts/related-products.jay-contract",
20
+ "./category-products.jay-contract": "./dist/contracts/category-products.jay-contract",
21
+ "./product-spotlight.jay-contract": "./dist/contracts/product-spotlight.jay-contract",
21
22
  "./category-list.jay-contract": "./dist/contracts/category-list.jay-contract",
22
23
  "./search-products.jay-action": "./dist/actions/search-products.jay-action",
23
24
  "./get-product-by-slug.jay-action": "./dist/actions/get-product-by-slug.jay-action",
@@ -38,16 +39,16 @@
38
39
  "test": "vitest run"
39
40
  },
40
41
  "dependencies": {
41
- "@jay-framework/component": "^0.19.6",
42
- "@jay-framework/fullstack-component": "^0.19.6",
43
- "@jay-framework/reactive": "^0.19.6",
44
- "@jay-framework/runtime": "^0.19.6",
45
- "@jay-framework/secure": "^0.19.6",
46
- "@jay-framework/stack-client-runtime": "^0.19.6",
47
- "@jay-framework/stack-server-runtime": "^0.19.6",
48
- "@jay-framework/wix-cart": "^0.19.6",
49
- "@jay-framework/wix-server-client": "^0.19.6",
50
- "@jay-framework/wix-utils": "^0.19.6",
42
+ "@jay-framework/component": "^0.19.7",
43
+ "@jay-framework/fullstack-component": "^0.19.7",
44
+ "@jay-framework/reactive": "^0.19.7",
45
+ "@jay-framework/runtime": "^0.19.7",
46
+ "@jay-framework/secure": "^0.19.7",
47
+ "@jay-framework/stack-client-runtime": "^0.19.7",
48
+ "@jay-framework/stack-server-runtime": "^0.19.7",
49
+ "@jay-framework/wix-cart": "^0.19.7",
50
+ "@jay-framework/wix-server-client": "^0.19.7",
51
+ "@jay-framework/wix-utils": "^0.19.7",
51
52
  "@wix/categories": "^1.0.185",
52
53
  "@wix/data-extension-schema": "^1.0.221",
53
54
  "@wix/sdk": "^1.21.5",
@@ -59,10 +60,10 @@
59
60
  "@babel/core": "^7.23.7",
60
61
  "@babel/preset-env": "^7.23.8",
61
62
  "@babel/preset-typescript": "^7.23.3",
62
- "@jay-framework/compiler-jay-stack": "^0.19.6",
63
- "@jay-framework/jay-cli": "^0.19.6",
64
- "@jay-framework/jay-stack-cli": "^0.19.6",
65
- "@jay-framework/vite-plugin": "^0.19.6",
63
+ "@jay-framework/compiler-jay-stack": "^0.19.7",
64
+ "@jay-framework/jay-cli": "^0.19.7",
65
+ "@jay-framework/jay-stack-cli": "^0.19.7",
66
+ "@jay-framework/vite-plugin": "^0.19.7",
66
67
  "nodemon": "^3.0.3",
67
68
  "rimraf": "^5.0.5",
68
69
  "tslib": "^2.6.2",
package/plugin.yaml CHANGED
@@ -7,10 +7,14 @@ contracts:
7
7
  component: productSearch
8
8
  description: Headless product search page
9
9
  # category-page removed — use product-search with prefix/category params instead
10
- - name: related-products
11
- contract: related-products.jay-contract
12
- component: relatedProducts
13
- description: Related products from the same category
10
+ - name: category-products
11
+ contract: category-products.jay-contract
12
+ component: categoryProducts
13
+ description: Products from a category — use for showcases or as related products (exclude current product via productId)
14
+ - name: product-spotlight
15
+ contract: product-spotlight.jay-contract
16
+ component: productSpotlight
17
+ description: A single product card by product ID — use to feature a product on any page
14
18
  - name: category-list
15
19
  contract: category-list.jay-contract
16
20
  component: categoryList
@@ -1,31 +0,0 @@
1
- name: related-products
2
- description: Related products grid showing products from the same category. Use on product pages alongside the product-page component.
3
- props:
4
- - name: productId
5
- type: string
6
- description: Product ID to exclude from results
7
- - name: categorySlug
8
- type: string
9
- description: Category slug to filter related products by
10
- - name: limit
11
- type: number
12
- description: Maximum number of related products to show (default 4)
13
- tags:
14
- - tag: products
15
- type: sub-contract
16
- repeated: true
17
- trackBy: _id
18
- phase: fast+interactive
19
- description: Related product cards
20
- link: ./product-card
21
-
22
- - tag: hasProducts
23
- type: variant
24
- dataType: boolean
25
- phase: fast+interactive
26
- description: Whether there are related products to show
27
-
28
- - tag: categoryName
29
- type: data
30
- dataType: string
31
- description: Name of the category these products belong to
@@ -1,36 +0,0 @@
1
- import {JayContract} from "@jay-framework/runtime";
2
- import {ProductCardViewState, ProductCardRefs, ProductCardRepeatedRefs} from "./product-card.jay-contract";
3
-
4
- export interface RelatedProductsViewState {
5
- products: Array<ProductCardViewState>,
6
- hasProducts: boolean,
7
- categoryName: string
8
- }
9
-
10
- export type RelatedProductsSlowViewState = Pick<RelatedProductsViewState, 'categoryName'>;
11
-
12
- export type RelatedProductsFastViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
13
- products: Array<RelatedProductsViewState['products'][number]>;
14
- };
15
-
16
- export type RelatedProductsInteractiveViewState = Pick<RelatedProductsViewState, 'hasProducts'> & {
17
- products: Array<RelatedProductsViewState['products'][number]>;
18
- };
19
-
20
-
21
- export interface RelatedProductsRefs {
22
- products: ProductCardRepeatedRefs
23
- }
24
-
25
-
26
- export interface RelatedProductsRepeatedRefs {
27
- products: ProductCardRepeatedRefs
28
- }
29
-
30
- export interface RelatedProductsProps {
31
- productId?: string;
32
- categorySlug?: string;
33
- limit?: number;
34
- }
35
-
36
- export type RelatedProductsContract = JayContract<RelatedProductsViewState, RelatedProductsRefs, RelatedProductsSlowViewState, RelatedProductsFastViewState, RelatedProductsInteractiveViewState, RelatedProductsProps>