@jay-framework/wix-stores 0.15.4 → 0.15.6

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.
@@ -301,6 +301,7 @@ function ProductPageInteractive(props, refs, viewStateSignals, fastCarryForward,
301
301
  quantity: quantity()
302
302
  },
303
303
  actionsEnabled: computedActionsEnabled,
304
+ isAddingToCart,
304
305
  options,
305
306
  modifiers,
306
307
  mediaGallery: interactiveMedia,
@@ -313,6 +314,11 @@ function ProductPageInteractive(props, refs, viewStateSignals, fastCarryForward,
313
314
  };
314
315
  }
315
316
  const productPage = makeJayStackComponent().withProps().withContexts(WIX_STORES_CONTEXT).withInteractive(ProductPageInteractive);
317
+ var OptionRenderType = /* @__PURE__ */ ((OptionRenderType2) => {
318
+ OptionRenderType2[OptionRenderType2["TEXT_CHOICES"] = 0] = "TEXT_CHOICES";
319
+ OptionRenderType2[OptionRenderType2["SWATCH_CHOICES"] = 1] = "SWATCH_CHOICES";
320
+ return OptionRenderType2;
321
+ })(OptionRenderType || {});
316
322
  var CurrentSort = /* @__PURE__ */ ((CurrentSort2) => {
317
323
  CurrentSort2[CurrentSort2["relevance"] = 0] = "relevance";
318
324
  CurrentSort2[CurrentSort2["priceAsc"] = 1] = "priceAsc";
@@ -369,6 +375,15 @@ function updateUrlFilters(searchTerm, filters, sort, categories) {
369
375
  }
370
376
  if (filters.inStockOnly)
371
377
  params.set("inStock", "1");
378
+ const optSegments = [];
379
+ for (const opt of filters.optionFilters || []) {
380
+ const selected = opt.choices.filter((c) => c.isSelected).map((c) => encodeURIComponent(c.choiceName));
381
+ if (selected.length > 0) {
382
+ optSegments.push(`${encodeURIComponent(opt.optionName)}:${selected.join(",")}`);
383
+ }
384
+ }
385
+ if (optSegments.length > 0)
386
+ params.set("opt", optSegments.join(";"));
372
387
  if (sort !== CurrentSort.relevance) {
373
388
  const sortNames = {
374
389
  [CurrentSort.priceAsc]: "priceAsc",
@@ -384,6 +399,30 @@ function updateUrlFilters(searchTerm, filters, sort, categories) {
384
399
  const query = params.toString();
385
400
  window.history.replaceState(null, "", query ? `?${query}` : window.location.pathname);
386
401
  }
402
+ function buildOptionFiltersViewState(baseOptionFilters, filteredResult, optionSelections) {
403
+ const filteredChoiceCounts = /* @__PURE__ */ new Map();
404
+ for (const opt of filteredResult.optionFilters || []) {
405
+ for (const ch of opt.choices) {
406
+ filteredChoiceCounts.set(ch.choiceName.toLowerCase(), ch.productCount);
407
+ }
408
+ }
409
+ return baseOptionFilters.map((opt) => ({
410
+ optionId: opt.optionId,
411
+ optionName: opt.optionName,
412
+ optionRenderType: opt.optionRenderType === "SWATCH_CHOICES" ? OptionRenderType.SWATCH_CHOICES : OptionRenderType.TEXT_CHOICES,
413
+ choices: opt.choices.map((ch) => {
414
+ const count = filteredChoiceCounts.get(ch.choiceName.toLowerCase()) ?? 0;
415
+ return {
416
+ choiceId: ch.choiceId,
417
+ choiceName: ch.choiceName,
418
+ colorCode: ch.colorCode,
419
+ productCount: count,
420
+ isSelected: optionSelections.get(opt.optionName)?.has(ch.choiceName) ?? false,
421
+ isDisabled: count === 0
422
+ };
423
+ })
424
+ }));
425
+ }
387
426
  function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForward, storesContext) {
388
427
  const baseCategoryId = fastCarryForward.baseCategoryId;
389
428
  const variantStockCache = {};
@@ -394,19 +433,41 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
394
433
  let debounceTimeout = null;
395
434
  let searchVersion = 0;
396
435
  const DEBOUNCE_MS = 300;
436
+ const [latestSearchResult, setLatestSearchResult] = createSignal(null);
437
+ const mergedFilters = createMemo(() => {
438
+ const f = filters();
439
+ const result = latestSearchResult();
440
+ if (!result)
441
+ return f;
442
+ const selections = /* @__PURE__ */ new Map();
443
+ for (const opt of f.optionFilters || []) {
444
+ const selected = opt.choices.filter((c) => c.isSelected).map((c) => c.choiceName);
445
+ if (selected.length > 0)
446
+ selections.set(opt.optionName, new Set(selected));
447
+ }
448
+ return {
449
+ ...f,
450
+ optionFilters: buildOptionFiltersViewState(fastCarryForward.baseOptionFilters, result, selections)
451
+ };
452
+ });
397
453
  const performSearch = async (version, searchTerm, currentFilters, currentSort) => {
398
454
  setIsSearching(true);
399
455
  setHasSearched(true);
400
456
  try {
401
457
  const userSelectedCategoryIds = currentFilters.categoryFilter.categories.filter((c) => c.isSelected).map((c) => c.categoryId);
402
458
  const categoryIds = baseCategoryId ? [baseCategoryId, ...userSelectedCategoryIds] : userSelectedCategoryIds;
459
+ const activeOptionFilters = (currentFilters.optionFilters || []).map((opt) => ({
460
+ optionName: opt.optionName,
461
+ choiceNames: opt.choices.filter((c) => c.isSelected).map((c) => c.choiceName)
462
+ })).filter((o) => o.choiceNames.length > 0);
403
463
  const result = await searchProducts({
404
464
  query: searchTerm || "",
405
465
  filters: {
406
466
  minPrice: currentFilters.priceRange.minPrice || void 0,
407
467
  maxPrice: currentFilters.priceRange.maxPrice || void 0,
408
468
  categoryIds,
409
- inStockOnly: currentFilters.inStockOnly
469
+ inStockOnly: currentFilters.inStockOnly,
470
+ optionFilters: activeOptionFilters.length > 0 ? activeOptionFilters : void 0
410
471
  },
411
472
  sortBy: mapSortToAction(currentSort),
412
473
  // No cursor = start from beginning
@@ -421,6 +482,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
421
482
  setLoadedCount(result.products.length);
422
483
  setHasMore(result.hasMore);
423
484
  setHasResults(result.products.length > 0);
485
+ setLatestSearchResult(result);
424
486
  currentCursor = result.nextCursor;
425
487
  updateUrlFilters(searchTerm, currentFilters, currentSort, fastCarryForward.categories);
426
488
  } catch (error) {
@@ -443,13 +505,18 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
443
505
  const searchTerm = submittedSearchTerm();
444
506
  const userSelectedCategoryIds = currentFilters.categoryFilter.categories.filter((c) => c.isSelected).map((c) => c.categoryId);
445
507
  const categoryIds = baseCategoryId ? [baseCategoryId, ...userSelectedCategoryIds] : userSelectedCategoryIds;
508
+ const activeOptionFilters = (currentFilters.optionFilters || []).map((opt) => ({
509
+ optionName: opt.optionName,
510
+ choiceNames: opt.choices.filter((c) => c.isSelected).map((c) => c.choiceName)
511
+ })).filter((o) => o.choiceNames.length > 0);
446
512
  const result = await searchProducts({
447
513
  query: searchTerm || "",
448
514
  filters: {
449
515
  minPrice: currentFilters.priceRange.minPrice || void 0,
450
516
  maxPrice: currentFilters.priceRange.maxPrice || void 0,
451
517
  categoryIds,
452
- inStockOnly: currentFilters.inStockOnly
518
+ inStockOnly: currentFilters.inStockOnly,
519
+ optionFilters: activeOptionFilters.length > 0 ? activeOptionFilters : void 0
453
520
  },
454
521
  sortBy: mapSortToAction(currentSort),
455
522
  cursor: currentCursor,
@@ -564,6 +631,24 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
564
631
  const isChecked = event.target.checked;
565
632
  setFilters(patch(filters(), [{ op: REPLACE, path: ["inStockOnly"], value: isChecked }]));
566
633
  });
634
+ refs.filters.optionFilters.choices.isSelected.oninput(({ event, coordinate }) => {
635
+ const [optionId, choiceId] = coordinate;
636
+ const currentFilters = filters();
637
+ const optionIndex = currentFilters.optionFilters.findIndex((o) => o.optionId === optionId);
638
+ if (optionIndex === -1)
639
+ return;
640
+ const choiceIndex = currentFilters.optionFilters[optionIndex].choices.findIndex((c) => c.choiceId === choiceId);
641
+ if (choiceIndex === -1)
642
+ return;
643
+ const isChecked = event.target.checked;
644
+ setFilters(patch(currentFilters, [
645
+ {
646
+ op: REPLACE,
647
+ path: ["optionFilters", optionIndex, "choices", choiceIndex, "isSelected"],
648
+ value: isChecked
649
+ }
650
+ ]));
651
+ });
567
652
  refs.filters.clearFilters.onclick(() => {
568
653
  const currentFilters = filters();
569
654
  const clearedCategories = currentFilters.categoryFilter.categories.map((cat) => ({
@@ -575,6 +660,10 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
575
660
  isSelected: i === 0
576
661
  // First one is "Show all"
577
662
  }));
663
+ const clearedOptionFilters = (currentFilters.optionFilters || []).map((opt) => ({
664
+ ...opt,
665
+ choices: opt.choices.map((ch) => ({ ...ch, isSelected: false }))
666
+ }));
578
667
  setFilters({
579
668
  priceRange: {
580
669
  minPrice: 0,
@@ -584,7 +673,8 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
584
673
  ranges: clearedRanges
585
674
  },
586
675
  categoryFilter: { categories: clearedCategories },
587
- inStockOnly: false
676
+ inStockOnly: false,
677
+ optionFilters: clearedOptionFilters
588
678
  });
589
679
  });
590
680
  refs.loadMoreButton.onclick(() => {
@@ -617,48 +707,48 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
617
707
  ]));
618
708
  }
619
709
  });
710
+ const variantStockLoading = /* @__PURE__ */ new Set();
620
711
  const loadVariantStock = async (productId) => {
621
- if (variantStockCache[productId])
622
- return;
623
- const stockMap = await getVariantStock({ productId });
624
- variantStockCache[productId] = stockMap;
625
- const currentResults = searchResults();
626
- const productIndex = currentResults.findIndex((p) => p._id === productId);
627
- if (productIndex === -1)
628
- return;
629
- const product = currentResults[productIndex];
630
- if (product.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS)
712
+ if (variantStockCache[productId] || variantStockLoading.has(productId))
631
713
  return;
632
- const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
633
- const textChoices = product.secondQuickOption?.choices;
634
- if (!selectedColor || !textChoices)
635
- return;
636
- const colorStock = stockMap[selectedColor.choiceId];
637
- const updatedTextChoices = textChoices.map((c) => ({
638
- ...c,
639
- inStock: colorStock?.[c.choiceId] ?? false
640
- }));
641
- setSearchResults(patch(searchResults(), [
642
- {
643
- op: REPLACE,
644
- path: [productIndex, "secondQuickOption", "choices"],
645
- value: updatedTextChoices
646
- }
647
- ]));
714
+ variantStockLoading.add(productId);
715
+ try {
716
+ const currentResults = searchResults();
717
+ const productIndex = currentResults.findIndex((p) => p._id === productId);
718
+ if (productIndex === -1)
719
+ return;
720
+ const product = currentResults[productIndex];
721
+ if (product?.quickAddType !== QuickAddType.COLOR_AND_TEXT_OPTIONS)
722
+ return;
723
+ const stockMap = await getVariantStock({ productId });
724
+ variantStockCache[productId] = stockMap;
725
+ const selectedColor = product.quickOption?.choices?.find((c) => c.isSelected);
726
+ const textChoices = product.secondQuickOption?.choices;
727
+ if (!selectedColor || !textChoices)
728
+ return;
729
+ const colorStock = stockMap[selectedColor.choiceId];
730
+ const updatedTextChoices = textChoices.map((c) => ({
731
+ ...c,
732
+ inStock: colorStock?.[c.choiceId] ?? false
733
+ }));
734
+ setSearchResults(patch(searchResults(), [
735
+ {
736
+ op: REPLACE,
737
+ path: [productIndex, "secondQuickOption", "choices"],
738
+ value: updatedTextChoices
739
+ }
740
+ ]));
741
+ } finally {
742
+ variantStockLoading.delete(productId);
743
+ }
648
744
  };
649
745
  refs.searchResults.productLink.onmouseenter(({ coordinate }) => {
650
746
  const [productId] = coordinate;
651
- const product = searchResults().find((p) => p._id === productId);
652
- if (product?.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
653
- loadVariantStock(productId);
654
- }
747
+ loadVariantStock(productId);
655
748
  });
656
749
  refs.searchResults.quickOption.choices.choiceButton.onmouseenter(({ coordinate }) => {
657
750
  const [productId] = coordinate;
658
- const product = searchResults().find((p) => p._id === productId);
659
- if (product?.quickAddType === QuickAddType.COLOR_AND_TEXT_OPTIONS) {
660
- loadVariantStock(productId);
661
- }
751
+ loadVariantStock(productId);
662
752
  });
663
753
  refs.searchResults.quickOption.choices.choiceButton.onclick(async ({ coordinate }) => {
664
754
  const [productId, choiceId] = coordinate;
@@ -763,6 +853,10 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
763
853
  ]));
764
854
  }
765
855
  });
856
+ refs.searchResults.secondQuickOption.choices.choiceButton.onmouseenter(({ coordinate }) => {
857
+ const [productId] = coordinate;
858
+ loadVariantStock(productId);
859
+ });
766
860
  refs.searchResults.viewOptionsButton.onclick(({ coordinate }) => {
767
861
  const [productId] = coordinate;
768
862
  const product = searchResults().find((p) => p._id === productId);
@@ -780,7 +874,7 @@ function ProductSearchInteractive(props, refs, viewStateSignals, fastCarryForwar
780
874
  hasResults: hasResults(),
781
875
  hasSuggestions: hasSuggestions(),
782
876
  suggestions: suggestions(),
783
- filters: filters(),
877
+ filters: mergedFilters(),
784
878
  sortBy: sortBy(),
785
879
  hasMore: hasMore(),
786
880
  loadedCount: loadedCount(),
package/dist/index.d.ts CHANGED
@@ -7,14 +7,14 @@ import * as _jay_framework_runtime from '@jay-framework/runtime';
7
7
  import { HTMLElementCollectionProxy, HTMLElementProxy } from '@jay-framework/runtime';
8
8
  import { WixClient } from '@wix/sdk';
9
9
  import { BuildDescriptors } from '@wix/sdk-types';
10
- import { productsV3, inventoryItemsV3 } from '@wix/stores';
10
+ import { productsV3, inventoryItemsV3, customizationsV3 } from '@wix/stores';
11
11
  import { categories } from '@wix/categories';
12
- import { currentCart } from '@wix/ecom';
12
+ import { Customization } from '@wix/auto_sdk_stores_customizations-v-3';
13
13
  import { Getter } from '@jay-framework/reactive';
14
14
  import { OptionChoice } from '@wix/auto_sdk_stores_products-v-3';
15
15
  import { PluginSetupContext, PluginSetupResult, PluginReferencesContext, PluginReferencesResult } from '@jay-framework/stack-server-runtime';
16
16
 
17
- declare enum OptionRenderType$1 {
17
+ declare enum OptionRenderType$2 {
18
18
  TEXT_CHOICES,
19
19
  COLOR_SWATCH_CHOICES
20
20
  }
@@ -36,7 +36,7 @@ interface ChoiceOfProductOptionsViewState {
36
36
  interface ProductOptionsViewState {
37
37
  _id: string,
38
38
  name: string,
39
- optionRenderType: OptionRenderType$1,
39
+ optionRenderType: OptionRenderType$2,
40
40
  choices: Array<ChoiceOfProductOptionsViewState>
41
41
  }
42
42
 
@@ -164,10 +164,32 @@ interface CategoryFilterOfFilterOfProductSearchViewState {
164
164
  categories: Array<CategoryOfCategoryFilterOfFilterOfProductSearchViewState>
165
165
  }
166
166
 
167
+ declare enum OptionRenderType$1 {
168
+ TEXT_CHOICES,
169
+ SWATCH_CHOICES
170
+ }
171
+
172
+ interface ChoiceOfOptionFilterOfFilterOfProductSearchViewState {
173
+ choiceId: string,
174
+ choiceName: string,
175
+ colorCode: string,
176
+ productCount: number,
177
+ isSelected: boolean,
178
+ isDisabled: boolean
179
+ }
180
+
181
+ interface OptionFilterOfFilterOfProductSearchViewState {
182
+ optionId: string,
183
+ optionName: string,
184
+ optionRenderType: OptionRenderType$1,
185
+ choices: Array<ChoiceOfOptionFilterOfFilterOfProductSearchViewState>
186
+ }
187
+
167
188
  interface FilterOfProductSearchViewState {
168
189
  priceRange: PriceRangeOfFilterOfProductSearchViewState,
169
190
  categoryFilter: CategoryFilterOfFilterOfProductSearchViewState,
170
- inStockOnly: boolean
191
+ inStockOnly: boolean,
192
+ optionFilters: Array<OptionFilterOfFilterOfProductSearchViewState>
171
193
  }
172
194
 
173
195
  declare enum CurrentSort {
@@ -275,6 +297,7 @@ type ProductSearchFastViewState = Pick<ProductSearchViewState, 'searchExpression
275
297
  categoryFilter: {
276
298
  categories: Array<Pick<ProductSearchViewState['filters']['categoryFilter']['categories'][number], 'categoryId' | 'isSelected'>>;
277
299
  };
300
+ optionFilters: Array<ProductSearchViewState['filters']['optionFilters'][number]>;
278
301
  };
279
302
  sortBy: ProductSearchViewState['sortBy'];
280
303
  suggestions: Array<ProductSearchViewState['suggestions'][number]>;
@@ -287,6 +310,7 @@ type ProductSearchInteractiveViewState = Pick<ProductSearchViewState, 'searchExp
287
310
  categoryFilter: {
288
311
  categories: Array<Pick<ProductSearchViewState['filters']['categoryFilter']['categories'][number], 'categoryId' | 'isSelected'>>;
289
312
  };
313
+ optionFilters: Array<ProductSearchViewState['filters']['optionFilters'][number]>;
290
314
  };
291
315
  sortBy: ProductSearchViewState['sortBy'];
292
316
  suggestions: Array<ProductSearchViewState['suggestions'][number]>;
@@ -313,6 +337,11 @@ interface ProductSearchRefs {
313
337
  categories: {
314
338
  isSelected: HTMLElementCollectionProxy<CategoryOfCategoryFilterOfFilterOfProductSearchViewState, HTMLInputElement>
315
339
  }
340
+ },
341
+ optionFilters: {
342
+ choices: {
343
+ isSelected: HTMLElementCollectionProxy<ChoiceOfOptionFilterOfFilterOfProductSearchViewState, HTMLInputElement>
344
+ }
316
345
  }
317
346
  },
318
347
  sortBy: {
@@ -390,14 +419,15 @@ interface WixStoresService {
390
419
  products: BuildDescriptors<typeof productsV3, {}>;
391
420
  categories: BuildDescriptors<typeof categories, {}>;
392
421
  inventory: BuildDescriptors<typeof inventoryItemsV3, {}>;
393
- /** @deprecated Use WIX_CART_SERVICE from @jay-framework/wix-cart instead */
394
- cart: BuildDescriptors<typeof currentCart, {}>;
422
+ customizations: BuildDescriptors<typeof customizationsV3, {}>;
395
423
  /** URL templates for building canonical links */
396
424
  urls: UrlTemplates;
397
425
  /** Slug of the fallback category for pages without category context */
398
426
  defaultCategory: string | null;
399
427
  /** Get the cached category tree. Lazily built on first call. */
400
428
  getCategoryTree(): Promise<CategoryTree>;
429
+ /** Get cached product customizations (options with choices). Lazily loaded. */
430
+ getCustomizations(): Promise<Customization[]>;
401
431
  }
402
432
  /**
403
433
  * Server service marker for Wix Stores.
@@ -473,6 +503,53 @@ interface WixStoresContext {
473
503
  */
474
504
  declare const WIX_STORES_CONTEXT: _jay_framework_runtime.ContextMarker<WixStoresContext>;
475
505
 
506
+ interface SearchProductsInput {
507
+ query: string;
508
+ filters?: {
509
+ inStockOnly?: boolean;
510
+ minPrice?: number;
511
+ maxPrice?: number;
512
+ categoryIds?: Array<string>;
513
+ optionFilters?: Array<{
514
+ optionName: string;
515
+ choiceNames: Array<string>;
516
+ }>;
517
+ };
518
+ sortBy?: 'relevance' | 'price_asc' | 'price_desc' | 'name_asc' | 'name_desc' | 'newest';
519
+ cursor?: string;
520
+ pageSize?: number;
521
+ }
522
+
523
+ interface SearchProductsOutput {
524
+ products: Array<ProductCardViewState>;
525
+ totalCount: number;
526
+ nextCursor?: string;
527
+ hasMore: boolean;
528
+ priceAggregation?: {
529
+ minBound: number;
530
+ maxBound: number;
531
+ ranges: Array<{
532
+ rangeId: string;
533
+ label: string;
534
+ minValue?: number;
535
+ maxValue?: number;
536
+ productCount: number;
537
+ isSelected: boolean;
538
+ }>;
539
+ };
540
+ optionFilters?: Array<{
541
+ optionId: string;
542
+ optionName: string;
543
+ optionRenderType: 'TEXT_CHOICES' | 'SWATCH_CHOICES';
544
+ choices: Array<{
545
+ choiceId: string;
546
+ choiceName: string;
547
+ colorCode: string;
548
+ productCount: number;
549
+ }>;
550
+ }>;
551
+ }
552
+
476
553
  /**
477
554
  * URL parameters for product search routes.
478
555
  * Supports: category (prefix slug), subcategory (sub-category slug).
@@ -483,10 +560,6 @@ interface ProductSearchParams extends UrlParams {
483
560
  /** Sub-category slug (e.g., 'shirts'). Further scopes within the category. */
484
561
  subcategory?: string;
485
562
  }
486
- /**
487
- * Search sort options
488
- */
489
- type SearchSortOption = 'relevance' | 'priceAsc' | 'priceDesc' | 'newest' | 'nameAsc' | 'nameDesc';
490
563
  /**
491
564
  * Category info carried forward from slow to fast phase
492
565
  */
@@ -500,6 +573,10 @@ interface SearchSlowCarryForward {
500
573
  categories: CategoryInfos;
501
574
  /** Root category ID when scoped to a category prefix (always applied, hidden from UI) */
502
575
  baseCategoryId: string | null;
576
+ /** Pre-loaded product results from slow phase (used when no query params) */
577
+ preloadedResult: SearchProductsOutput | null;
578
+ /** Base option filters from unfiltered search (static list, counts updated per search) */
579
+ baseOptionFilters: SearchProductsOutput['optionFilters'];
503
580
  }
504
581
  /**
505
582
  * Data carried forward from fast rendering to interactive phase
@@ -510,6 +587,8 @@ interface SearchFastCarryForward {
510
587
  categories: CategoryInfos;
511
588
  /** Root category ID when scoped to a category prefix (always applied, hidden from UI) */
512
589
  baseCategoryId: string | null;
590
+ /** Base option filters from unfiltered search (static list structure) */
591
+ baseOptionFilters: SearchProductsOutput['optionFilters'];
513
592
  }
514
593
  declare const productSearch: _jay_framework_fullstack_component.JayStackComponentDefinition<ProductSearchRefs, ProductSearchSlowViewState, ProductSearchFastViewState, ProductSearchInteractiveViewState, [SearchSlowCarryForward, WixStoresService], [Signals<ProductSearchFastViewState>, SearchFastCarryForward, WixStoresContext], PageProps & ProductSearchParams, ProductSearchParams, _jay_framework_component.JayComponentCore<PageProps & ProductSearchParams, ProductSearchInteractiveViewState>>;
515
594
 
@@ -627,40 +706,6 @@ interface ModifierOfProductPageViewState {
627
706
  choices: Array<ChoiceOfModifierOfProductPageViewState>
628
707
  }
629
708
 
630
- interface PropOfTagOfSeoDatumOfProductPageViewState {
631
- key: string,
632
- value: string
633
- }
634
-
635
- interface MetaOfTagOfSeoDatumOfProductPageViewState {
636
- key: string,
637
- value: string
638
- }
639
-
640
- interface TagOfSeoDatumOfProductPageViewState {
641
- position: string,
642
- type: string,
643
- props: Array<PropOfTagOfSeoDatumOfProductPageViewState>,
644
- meta: Array<MetaOfTagOfSeoDatumOfProductPageViewState>,
645
- children: string
646
- }
647
-
648
- interface KeywordOfSettingOfSeoDatumOfProductPageViewState {
649
- term: string,
650
- isMain: boolean,
651
- origin: string
652
- }
653
-
654
- interface SettingOfSeoDatumOfProductPageViewState {
655
- preventAutoRedirect: boolean,
656
- keywords: Array<KeywordOfSettingOfSeoDatumOfProductPageViewState>
657
- }
658
-
659
- interface SeoDatumOfProductPageViewState {
660
- tags: Array<TagOfSeoDatumOfProductPageViewState>,
661
- settings: SettingOfSeoDatumOfProductPageViewState
662
- }
663
-
664
709
  interface ProductPageViewState {
665
710
  _id: string,
666
711
  productName: string,
@@ -676,10 +721,10 @@ interface ProductPageViewState {
676
721
  stockStatus: StockStatus,
677
722
  quantity: QuantityOfProductPageViewState,
678
723
  actionsEnabled: boolean,
724
+ isAddingToCart: boolean,
679
725
  options: Array<OptionOfProductPageViewState>,
680
726
  infoSections: Array<InfoSectionOfProductPageViewState>,
681
- modifiers: Array<ModifierOfProductPageViewState>,
682
- seoData: SeoDatumOfProductPageViewState
727
+ modifiers: Array<ModifierOfProductPageViewState>
683
728
  }
684
729
 
685
730
  type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName' | 'description' | 'brand' | 'ribbon' | 'productType'> & {
@@ -690,10 +735,9 @@ type ProductPageSlowViewState = Pick<ProductPageViewState, '_id' | 'productName'
690
735
  modifiers: Array<Pick<ProductPageViewState['modifiers'][number], '_id' | 'name' | 'modifierType' | 'textInputLength' | 'textInputRequired'> & {
691
736
  choices: Array<Pick<ProductPageViewState['modifiers'][number]['choices'][number], 'choiceId' | 'choiceType' | 'name' | 'colorCode'>>;
692
737
  }>;
693
- seoData: ProductPageViewState['seoData'];
694
738
  };
695
739
 
696
- type ProductPageFastViewState = Pick<ProductPageViewState, 'sku' | 'price' | 'strikethroughPrice' | 'pricePerUnit' | 'stockStatus' | 'actionsEnabled'> & {
740
+ type ProductPageFastViewState = Pick<ProductPageViewState, 'sku' | 'price' | 'strikethroughPrice' | 'pricePerUnit' | 'stockStatus' | 'actionsEnabled' | 'isAddingToCart'> & {
697
741
  mediaGallery: ProductPageViewState['mediaGallery'];
698
742
  quantity: ProductPageViewState['quantity'];
699
743
  options: Array<Pick<ProductPageViewState['options'][number], '_id' | 'textChoiceSelection'> & {
@@ -704,7 +748,7 @@ type ProductPageFastViewState = Pick<ProductPageViewState, 'sku' | 'price' | 'st
704
748
  }>;
705
749
  };
706
750
 
707
- type ProductPageInteractiveViewState = Pick<ProductPageViewState, 'sku' | 'price' | 'strikethroughPrice' | 'pricePerUnit' | 'stockStatus' | 'actionsEnabled'> & {
751
+ type ProductPageInteractiveViewState = Pick<ProductPageViewState, 'sku' | 'price' | 'strikethroughPrice' | 'pricePerUnit' | 'stockStatus' | 'actionsEnabled' | 'isAddingToCart'> & {
708
752
  mediaGallery: ProductPageViewState['mediaGallery'];
709
753
  quantity: ProductPageViewState['quantity'];
710
754
  options: Array<Pick<ProductPageViewState['options'][number], '_id' | 'textChoiceSelection'> & {
@@ -821,6 +865,14 @@ interface CategoryListRefs {
821
865
  }
822
866
  }
823
867
 
868
+ /**
869
+ * URL parameters for category list.
870
+ * Supports optional parentCategory to scope the list to direct children.
871
+ */
872
+ interface CategoryListParams extends UrlParams {
873
+ /** Parent category slug. When set, only direct children of this category are shown. */
874
+ parentCategory?: string;
875
+ }
824
876
  /**
825
877
  * Category List Full-Stack Component
826
878
  *
@@ -846,86 +898,17 @@ interface CategoryListRefs {
846
898
  * </div>
847
899
  * ```
848
900
  */
849
- declare const categoryList: _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [], PageProps, {}, _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>> & {
850
- withFastRender<NewCarryForward extends object>(fastRender: _jay_framework_fullstack_component.RenderFast<[Record<string, never>, WixStoresService], PageProps, CategoryListFastViewState, NewCarryForward>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps, {}, _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>> & {
851
- withClientDefaults(fn: (props: PageProps) => {
901
+ declare const categoryList: _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [], PageProps & CategoryListParams, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>> & {
902
+ withFastRender<NewCarryForward extends object>(fastRender: _jay_framework_fullstack_component.RenderFast<[Record<string, never>, WixStoresService], PageProps & CategoryListParams, CategoryListFastViewState, NewCarryForward>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps & CategoryListParams, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>> & {
903
+ withClientDefaults(fn: (props: PageProps & CategoryListParams) => {
852
904
  viewState: CategoryListFastViewState;
853
905
  carryForward?: any;
854
- }): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps, {}, _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>> & /*elided*/ any;
855
- withInteractive(comp: _jay_framework_component.ComponentConstructor<PageProps, CategoryListRefs, CategoryListInteractiveViewState, [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps, {}, _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>>;
906
+ }): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps & CategoryListParams, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>> & /*elided*/ any;
907
+ withInteractive(comp: _jay_framework_component.ComponentConstructor<PageProps & CategoryListParams, CategoryListRefs, CategoryListInteractiveViewState, [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [_jay_framework_fullstack_component.Signals<CategoryListFastViewState>, NewCarryForward], PageProps & CategoryListParams, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>>;
856
908
  };
857
- withInteractive(comp: _jay_framework_component.ComponentConstructor<PageProps, CategoryListRefs, CategoryListInteractiveViewState, [], _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [], PageProps, {}, _jay_framework_component.JayComponentCore<PageProps, CategoryListInteractiveViewState>>;
909
+ withInteractive(comp: _jay_framework_component.ComponentConstructor<PageProps & CategoryListParams, CategoryListRefs, CategoryListInteractiveViewState, [], _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>>): _jay_framework_fullstack_component.JayStackComponentDefinition<CategoryListRefs, CategoryListSlowViewState, CategoryListFastViewState, CategoryListInteractiveViewState, [Record<string, never>, WixStoresService], [], PageProps & CategoryListParams, {}, _jay_framework_component.JayComponentCore<PageProps & CategoryListParams, CategoryListInteractiveViewState>>;
858
910
  };
859
911
 
860
- /**
861
- * Sort options for product search
862
- */
863
- type ProductSortField = 'relevance' | 'price_asc' | 'price_desc' | 'name_asc' | 'name_desc' | 'newest';
864
- /**
865
- * Product search filters
866
- */
867
- interface ProductSearchFilters {
868
- /** Only show products in stock */
869
- inStockOnly?: boolean;
870
- /** Minimum price filter */
871
- minPrice?: number;
872
- /** Maximum price filter */
873
- maxPrice?: number;
874
- /** Filter by category IDs */
875
- categoryIds?: string[];
876
- }
877
- /**
878
- * Price range bucket for aggregation
879
- */
880
- interface PriceRangeBucket {
881
- rangeId: string;
882
- label: string;
883
- minValue: number | null;
884
- maxValue: number | null;
885
- productCount: number;
886
- isSelected: boolean;
887
- }
888
- /**
889
- * Price aggregation data from search
890
- */
891
- interface PriceAggregationData {
892
- /** Minimum price across all products */
893
- minBound: number;
894
- /** Maximum price across all products */
895
- maxBound: number;
896
- /** Price range buckets with product counts */
897
- ranges: PriceRangeBucket[];
898
- }
899
- /**
900
- * Input for searchProducts action
901
- */
902
- interface SearchProductsInput {
903
- /** Search query text */
904
- query: string;
905
- /** Filters to apply */
906
- filters?: ProductSearchFilters;
907
- /** Sort order */
908
- sortBy?: ProductSortField;
909
- /** Cursor for pagination (from previous response's nextCursor) */
910
- cursor?: string;
911
- /** Items per page (default: 12) */
912
- pageSize?: number;
913
- }
914
- /**
915
- * Output for searchProducts action
916
- */
917
- interface SearchProductsOutput {
918
- /** List of matching products */
919
- products: ProductCardViewState[];
920
- /** Total number of matching products */
921
- totalCount: number;
922
- /** Cursor for next page (null if no more results) */
923
- nextCursor: string | null;
924
- /** Whether there are more results */
925
- hasMore: boolean;
926
- /** Price aggregation data (bounds and ranges) */
927
- priceAggregation?: PriceAggregationData;
928
- }
929
912
  /**
930
913
  * Input for getProductBySlug action
931
914
  */
@@ -1007,4 +990,4 @@ declare function setupWixStores(ctx: PluginSetupContext): Promise<PluginSetupRes
1007
990
  */
1008
991
  declare function generateWixStoresReferences(ctx: PluginReferencesContext): Promise<PluginReferencesResult>;
1009
992
 
1010
- export { type CategoryTree, type GetProductBySlugInput, type PriceAggregationData, type PriceRangeBucket, type ProductPageParams, type ProductSearchFilters, type ProductSearchParams, type ProductSortField, type SearchProductsInput, type SearchProductsOutput, type SearchSortOption, 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, productSearch, provideWixStoresService, searchProducts, setupWixStores };
993
+ export { type CategoryListParams, type CategoryTree, type GetProductBySlugInput, type ProductPageParams, type ProductSearchParams, 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, productSearch, provideWixStoresService, searchProducts, setupWixStores };