@wix/himalaya-cli 0.1096.0 → 0.1097.0

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.
@@ -66,6 +66,17 @@ export interface StoreProduct {
66
66
  currency?: string;
67
67
  };
68
68
  };
69
+ /** Option groups, both spellings: V1 `productOptions`, V3 `options`. Declared
70
+ * because the wire carries them on BOTH catalogs and this type denying them is
71
+ * what let every template product screen drop the colour/size picker. Shapes
72
+ * differ per catalog, so read them with `productOptions()` from ./options. */
73
+ productOptions?: unknown[];
74
+ options?: unknown[];
75
+ /** V3 purchasable variants. The cart addresses a V3 option choice by `variantId`,
76
+ * which `cartOptionsPayload()` resolves out of this. */
77
+ variantsInfo?: {
78
+ variants?: unknown[];
79
+ };
69
80
  }
70
81
  export interface StoreProductsResponse {
71
82
  products?: StoreProduct[];
@@ -43,6 +43,7 @@ export declare function queryInventory(productId: string): Promise<WixQueryInven
43
43
  * Only the supplied fields change (e.g. trackQuantity + a variant's quantity). */
44
44
  export declare function updateInventory(inventoryItemId: string, inventoryItem: WixInventoryItemWrite): Promise<WixUpdateInventoryResponse>;
45
45
  export * from "./display.js";
46
+ export * from "./options.js";
46
47
  /** Forget the resolved Stores catalog version, in this worker and app-wide.
47
48
  * Call this when the app points itself at a DIFFERENT Wix site. */
48
49
  export declare function forgetCatalogVersion(): void;
@@ -0,0 +1,74 @@
1
+ import type { StoreProduct } from "./display.js";
2
+ import { type WixImageSize } from "@wix/himalaya/wix-media";
3
+ /** One selectable choice inside an option group. */
4
+ export interface StoreOptionChoice {
5
+ /** Stable id within the group. V3: the `choiceId`. V1: the choice's own label,
6
+ * which is what V1 has and what its cart payload carries. */
7
+ id: string;
8
+ /** What the shopper reads on the chip — "BEIGE", "M". */
9
+ label: string;
10
+ /** Is at least one variant carrying this choice in stock? */
11
+ inStock: boolean;
12
+ /** HEX swatch the site configured for this choice ("#e1bfc5"), or "" — a colour
13
+ * group carries one, a size group does not. */
14
+ colorCode: string;
15
+ /** Choice-linked image, sized, or "" when the choice has none. */
16
+ image: string;
17
+ }
18
+ /** One option group, e.g. `COLOR` with `BEIGE` / `PINK`. */
19
+ export interface StoreOption {
20
+ /** V3: the option id, used to resolve the variant. V1: the option name. */
21
+ id: string;
22
+ name: string;
23
+ /** `color` groups are the ones worth rendering as swatches — the choices carry
24
+ * a `colorCode`. Everything else is a list of words. */
25
+ kind: "color" | "list";
26
+ choices: StoreOptionChoice[];
27
+ }
28
+ /** The shopper's pick: option id → choice id. A group the shopper has not chosen
29
+ * yet is absent (or maps to ""). */
30
+ export type StoreOptionSelection = Record<string, string>;
31
+ /**
32
+ * Every offerable option group on a product, in site order, from either catalog.
33
+ *
34
+ * `[]` for a product with no options — the common case, so a caller must render
35
+ * nothing rather than an empty picker.
36
+ *
37
+ * `size` sizes the per-choice swatch image, like `productImage`; pass `null` for
38
+ * the stored original.
39
+ */
40
+ export declare function productOptions(product: StoreProduct | undefined, size?: WixImageSize | null): StoreOption[];
41
+ /** The choice to preselect for a group: the only one when there is exactly one,
42
+ * otherwise "" so the shopper picks deliberately. */
43
+ export declare function defaultChoice(option: StoreOption): string;
44
+ /** A selection with every single-choice group pre-filled — what a product screen
45
+ * starts from. */
46
+ export declare function defaultSelection(options: StoreOption[]): StoreOptionSelection;
47
+ /** Has the shopper chosen in EVERY group? Add to cart stays disabled until this
48
+ * is true — a half-chosen product is the unfulfillable order. */
49
+ export declare function isSelectionComplete(options: StoreOption[], selection: StoreOptionSelection): boolean;
50
+ /** Human summary of the current selection, e.g. "BEIGE · M" ("" when nothing is
51
+ * chosen). Labels, not ids — this is shopper-facing text. */
52
+ export declare function selectionSummary(options: StoreOption[], selection: StoreOptionSelection): string;
53
+ /**
54
+ * The V3 variant matching the shopper's choices, or "" when none does.
55
+ *
56
+ * Set equality on `{optionId, choiceId}` pairs, not order — V3 does not promise
57
+ * the variant's `choices` array is in the product's option order, and a positional
58
+ * compare passes on a two-option product until the day the site reorders it.
59
+ */
60
+ export declare function resolveVariantId(product: StoreProduct | undefined, selection: StoreOptionSelection): string;
61
+ /**
62
+ * The `catalogReference.options` value for `addToCurrentCart`, built for whichever
63
+ * catalog this product came from — V3 `{ variantId }`, V1 `{ options: {…} }`.
64
+ *
65
+ * `undefined` for a product with no options at all, which is what the cart wants
66
+ * (the line needs no `options` object).
67
+ *
68
+ * THROWS on V3 when the selection matches no variant, rather than returning a
69
+ * payload that adds an un-fulfillable line. The two ways to get here are a
70
+ * selection that is still incomplete (guard with `isSelectionComplete`) and a read
71
+ * whose `variantsInfo` did not come back — both are the caller's to fix, and both
72
+ * are invisible if this returns a plausible-looking payload instead.
73
+ */
74
+ export declare function cartOptionsPayload(product: StoreProduct | undefined, options: StoreOption[], selection: StoreOptionSelection): Record<string, unknown> | undefined;
@@ -577,6 +577,131 @@ function plainText(value) {
577
577
  return (value || "").replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
578
578
  }
579
579
 
580
+ // ../../stdlib/wix-sdk/stores-v1/src/options.ts
581
+ function str(v) {
582
+ return typeof v === "string" ? v.trim() : "";
583
+ }
584
+ function choiceImage(raw, size) {
585
+ const m = raw;
586
+ const slot = m?.mainMedia ?? m?.items?.[0] ?? raw;
587
+ return slot ? mediaSlotUrl(slot, size) : "";
588
+ }
589
+ function hex(raw) {
590
+ const v = str(raw);
591
+ return /^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/.test(v) ? v.toLowerCase() : "";
592
+ }
593
+ function v1Choices(raw, size) {
594
+ const out = [];
595
+ for (const c of Array.isArray(raw) ? raw : []) {
596
+ const o = c;
597
+ if (o.visible === false) continue;
598
+ const label = str(o.description) || str(o.value);
599
+ if (!label || out.some((x) => x.id === label)) continue;
600
+ out.push({
601
+ id: label,
602
+ label,
603
+ inStock: o.inStock !== false,
604
+ colorCode: hex(o.value),
605
+ image: choiceImage(o.media, size)
606
+ });
607
+ }
608
+ return out;
609
+ }
610
+ function v3Choices(raw, size) {
611
+ const settings = raw;
612
+ const out = [];
613
+ for (const c of Array.isArray(settings?.choices) ? settings.choices : []) {
614
+ const o = c;
615
+ if (o.visible === false) continue;
616
+ const label = str(o.name) || str(o.key);
617
+ const id = str(o.choiceId);
618
+ if (!id || !label || out.some((x) => x.id === id)) continue;
619
+ const linked = Array.isArray(o.linkedMedia) ? o.linkedMedia[0] : void 0;
620
+ out.push({
621
+ id,
622
+ label,
623
+ inStock: o.inStock !== false,
624
+ colorCode: hex(o.colorCode) || hex(o.value?.colorCode),
625
+ image: choiceImage(o.displayImage ?? linked, size)
626
+ });
627
+ }
628
+ return out;
629
+ }
630
+ function kindOf(raw) {
631
+ const v = str(raw).toUpperCase();
632
+ return v.includes("COLOR") || v.includes("COLOUR") || v === "SWATCH_CHOICES" ? "color" : "list";
633
+ }
634
+ function productOptions(product, size = WIX_LIST_IMAGE) {
635
+ const p = product;
636
+ const out = [];
637
+ for (const raw of Array.isArray(p?.productOptions) ? p.productOptions : []) {
638
+ const o = raw;
639
+ const name = str(o.name);
640
+ const choices = v1Choices(o.choices, size);
641
+ if (name) out.push({ id: name, name, kind: kindOf(o.optionType), choices });
642
+ }
643
+ if (out.length) return out;
644
+ for (const raw of Array.isArray(p?.options) ? p.options : []) {
645
+ const o = raw;
646
+ const name = str(o.name);
647
+ const id = str(o.id) || name;
648
+ const choices = v3Choices(o.choicesSettings, size);
649
+ if (name) out.push({ id, name, kind: kindOf(o.optionRenderType), choices });
650
+ }
651
+ return out;
652
+ }
653
+ function defaultChoice(option) {
654
+ return option.choices.length === 1 ? option.choices[0].id : "";
655
+ }
656
+ function defaultSelection(options) {
657
+ const out = {};
658
+ for (const o of options) {
659
+ const choice = defaultChoice(o);
660
+ if (choice) out[o.id] = choice;
661
+ }
662
+ return out;
663
+ }
664
+ function isSelectionComplete(options, selection) {
665
+ return options.every((o) => !!selection[o.id]);
666
+ }
667
+ function selectionSummary(options, selection) {
668
+ return options.map((o) => o.choices.find((c) => c.id === selection[o.id])?.label ?? "").filter(Boolean).join(" \xB7 ");
669
+ }
670
+ function isV3(p) {
671
+ return Array.isArray(p.options) || !!p.variantsInfo;
672
+ }
673
+ function resolveVariantId(product, selection) {
674
+ const p = product;
675
+ const variants = p?.variantsInfo?.variants ?? [];
676
+ const want = Object.entries(selection).filter(([, choice]) => !!choice);
677
+ for (const v of variants) {
678
+ if (v.visible === false) continue;
679
+ const pairs = (v.choices ?? []).map((c) => [str(c.optionChoiceIds?.optionId), str(c.optionChoiceIds?.choiceId)]);
680
+ if (pairs.length !== want.length) continue;
681
+ if (want.every(([optionId, choiceId]) => pairs.some(([o, c]) => o === optionId && c === choiceId))) {
682
+ return str(v.id);
683
+ }
684
+ }
685
+ return "";
686
+ }
687
+ function cartOptionsPayload(product, options, selection) {
688
+ const p = product ?? {};
689
+ if (isV3(p)) {
690
+ const variantId = resolveVariantId(product, selection);
691
+ if (variantId) return { variantId };
692
+ if (options.length === 0) return void 0;
693
+ throw new Error(
694
+ "cartOptionsPayload: no Catalog V3 variant matches the chosen options \u2014 check every option group has a choice (isSelectionComplete) and that the product was read with its variantsInfo."
695
+ );
696
+ }
697
+ const picked = {};
698
+ for (const o of options) {
699
+ const choice = selection[o.id];
700
+ if (choice) picked[o.name] = choice;
701
+ }
702
+ return Object.keys(picked).length ? { options: picked } : void 0;
703
+ }
704
+
580
705
  // ../../stdlib/wix-sdk/stores-v1/src/extensions.ts
581
706
  function queryProducts(req = {}) {
582
707
  return readWithCatalogFallback(async (v) => {
@@ -685,21 +810,28 @@ export {
685
810
  WIX_DETAIL_IMAGE,
686
811
  WIX_LIST_IMAGE,
687
812
  addProductMedia,
813
+ cartOptionsPayload,
688
814
  createProduct,
815
+ defaultChoice,
816
+ defaultSelection,
689
817
  deleteProduct,
690
818
  forgetCatalogVersion2 as forgetCatalogVersion,
691
819
  getProduct,
692
820
  getStoreProduct,
821
+ isSelectionComplete,
693
822
  isUnsizedWixMedia,
694
823
  mediaSlotUrl,
695
824
  plainText,
696
825
  productGallery,
697
826
  productImage,
827
+ productOptions,
698
828
  productPrice,
699
829
  queryInventory,
700
830
  queryProducts,
701
831
  queryStoreProducts,
832
+ resolveVariantId,
702
833
  searchStoreProducts,
834
+ selectionSummary,
703
835
  updateInventory,
704
836
  updateProduct,
705
837
  wixCall,
@@ -21651,7 +21651,7 @@
21651
21651
  "name": "StoreProduct",
21652
21652
  "kind": "interface",
21653
21653
  "jsdoc": "",
21654
- "decl": "export interface StoreProduct {\n id?: string;\n name?: string;\n slug?: string;\n description?: string;\n plainDescription?: string;\n /** Both gallery layouts: V1 `mainMedia`/`items`, V3 `main`/`itemsInfo.items`. */\n media?: {\n mainMedia?: WixMediaSlot;\n main?: WixMediaSlot;\n items?: WixMediaSlot[];\n itemsInfo?: { items?: WixMediaSlot[] };\n };\n price?: { formatted?: { price?: string }; price?: number; currency?: string };\n priceData?: { formatted?: { price?: string }; price?: number; currency?: string };\n currency?: string;\n actualPriceRange?: {\n minValue?: { amount?: string; formattedAmount?: string; currency?: string };\n maxValue?: { amount?: string; formattedAmount?: string; currency?: string };\n };\n}"
21654
+ "decl": "export interface StoreProduct {\n id?: string;\n name?: string;\n slug?: string;\n description?: string;\n plainDescription?: string;\n /** Both gallery layouts: V1 `mainMedia`/`items`, V3 `main`/`itemsInfo.items`. */\n media?: {\n mainMedia?: WixMediaSlot;\n main?: WixMediaSlot;\n items?: WixMediaSlot[];\n itemsInfo?: { items?: WixMediaSlot[] };\n };\n price?: { formatted?: { price?: string }; price?: number; currency?: string };\n priceData?: { formatted?: { price?: string }; price?: number; currency?: string };\n currency?: string;\n actualPriceRange?: {\n minValue?: { amount?: string; formattedAmount?: string; currency?: string };\n maxValue?: { amount?: string; formattedAmount?: string; currency?: string };\n };\n /** Option groups, both spellings: V1 `productOptions`, V3 `options`. Declared\n * because the wire carries them on BOTH catalogs and this type denying them is\n * what let every template product screen drop the colour/size picker. Shapes\n * differ per catalog, so read them with `productOptions()` from ./options. */\n productOptions?: unknown[];\n options?: unknown[];\n /** V3 purchasable variants. The cart addresses a V3 option choice by `variantId`,\n * which `cartOptionsPayload()` resolves out of this. */\n variantsInfo?: { variants?: unknown[] };\n}"
21655
21655
  },
21656
21656
  {
21657
21657
  "name": "StoreProductsResponse",
@@ -21696,6 +21696,66 @@
21696
21696
  "jsdoc": "",
21697
21697
  "decl": "export function plainText(value?: string): string;"
21698
21698
  },
21699
+ {
21700
+ "name": "StoreOptionChoice",
21701
+ "kind": "interface",
21702
+ "jsdoc": "/** One selectable choice inside an option group. */",
21703
+ "decl": "export interface StoreOptionChoice {\n /** Stable id within the group. V3: the `choiceId`. V1: the choice's own label,\n * which is what V1 has and what its cart payload carries. */\n id: string;\n /** What the shopper reads on the chip — \"BEIGE\", \"M\". */\n label: string;\n /** Is at least one variant carrying this choice in stock? */\n inStock: boolean;\n /** HEX swatch the site configured for this choice (\"#e1bfc5\"), or \"\" — a colour\n * group carries one, a size group does not. */\n colorCode: string;\n /** Choice-linked image, sized, or \"\" when the choice has none. */\n image: string;\n}"
21704
+ },
21705
+ {
21706
+ "name": "StoreOption",
21707
+ "kind": "interface",
21708
+ "jsdoc": "/** One option group, e.g. `COLOR` with `BEIGE` / `PINK`. */",
21709
+ "decl": "export interface StoreOption {\n /** V3: the option id, used to resolve the variant. V1: the option name. */\n id: string;\n name: string;\n /** `color` groups are the ones worth rendering as swatches — the choices carry\n * a `colorCode`. Everything else is a list of words. */\n kind: \"color\" | \"list\";\n choices: StoreOptionChoice[];\n}"
21710
+ },
21711
+ {
21712
+ "name": "StoreOptionSelection",
21713
+ "kind": "type",
21714
+ "jsdoc": "/** The shopper's pick: option id → choice id. A group the shopper has not chosen\n * yet is absent (or maps to \"\"). */",
21715
+ "decl": "export type StoreOptionSelection = Record<string, string>;"
21716
+ },
21717
+ {
21718
+ "name": "productOptions",
21719
+ "kind": "function",
21720
+ "jsdoc": "/**\n * Every offerable option group on a product, in site order, from either catalog.\n *\n * `[]` for a product with no options — the common case, so a caller must render\n * nothing rather than an empty picker.\n *\n * `size` sizes the per-choice swatch image, like `productImage`; pass `null` for\n * the stored original.\n */",
21721
+ "decl": "export function productOptions(\n product: StoreProduct | undefined,\n size: WixImageSize | null = WIX_LIST_IMAGE,\n): StoreOption[];"
21722
+ },
21723
+ {
21724
+ "name": "defaultChoice",
21725
+ "kind": "function",
21726
+ "jsdoc": "/** The choice to preselect for a group: the only one when there is exactly one,\n * otherwise \"\" so the shopper picks deliberately. */",
21727
+ "decl": "export function defaultChoice(option: StoreOption): string;"
21728
+ },
21729
+ {
21730
+ "name": "defaultSelection",
21731
+ "kind": "function",
21732
+ "jsdoc": "/** A selection with every single-choice group pre-filled — what a product screen\n * starts from. */",
21733
+ "decl": "export function defaultSelection(options: StoreOption[]): StoreOptionSelection;"
21734
+ },
21735
+ {
21736
+ "name": "isSelectionComplete",
21737
+ "kind": "function",
21738
+ "jsdoc": "/** Has the shopper chosen in EVERY group? Add to cart stays disabled until this\n * is true — a half-chosen product is the unfulfillable order. */",
21739
+ "decl": "export function isSelectionComplete(options: StoreOption[], selection: StoreOptionSelection): boolean;"
21740
+ },
21741
+ {
21742
+ "name": "selectionSummary",
21743
+ "kind": "function",
21744
+ "jsdoc": "/** Human summary of the current selection, e.g. \"BEIGE · M\" (\"\" when nothing is\n * chosen). Labels, not ids — this is shopper-facing text. */",
21745
+ "decl": "export function selectionSummary(options: StoreOption[], selection: StoreOptionSelection): string;"
21746
+ },
21747
+ {
21748
+ "name": "resolveVariantId",
21749
+ "kind": "function",
21750
+ "jsdoc": "/**\n * The V3 variant matching the shopper's choices, or \"\" when none does.\n *\n * Set equality on `{optionId, choiceId}` pairs, not order — V3 does not promise\n * the variant's `choices` array is in the product's option order, and a positional\n * compare passes on a two-option product until the day the site reorders it.\n */",
21751
+ "decl": "export function resolveVariantId(product: StoreProduct | undefined, selection: StoreOptionSelection): string;"
21752
+ },
21753
+ {
21754
+ "name": "cartOptionsPayload",
21755
+ "kind": "function",
21756
+ "jsdoc": "/**\n * The `catalogReference.options` value for `addToCurrentCart`, built for whichever\n * catalog this product came from — V3 `{ variantId }`, V1 `{ options: {…} }`.\n *\n * `undefined` for a product with no options at all, which is what the cart wants\n * (the line needs no `options` object).\n *\n * THROWS on V3 when the selection matches no variant, rather than returning a\n * payload that adds an un-fulfillable line. The two ways to get here are a\n * selection that is still incomplete (guard with `isSelectionComplete`) and a read\n * whose `variantsInfo` did not come back — both are the caller's to fix, and both\n * are invisible if this returns a plausible-looking payload instead.\n */",
21757
+ "decl": "export function cartOptionsPayload(\n product: StoreProduct | undefined,\n options: StoreOption[],\n selection: StoreOptionSelection,\n): Record<string, unknown> | undefined;"
21758
+ },
21699
21759
  {
21700
21760
  "name": "forgetCatalogVersion",
21701
21761
  "kind": "function",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1096.0",
3
+ "version": "0.1097.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -67,5 +67,5 @@
67
67
  "artifactId": "himalaya-cli"
68
68
  }
69
69
  },
70
- "falconPackageHash": "8c3d412276bbc440753d0cea961d942686f0bc403cf0c4552ef2f12c"
70
+ "falconPackageHash": "a14970a4ab0b5e14659e9a75dc3d4ddbcaa2a0955fc287caf553d82c"
71
71
  }
@@ -25998,6 +25998,219 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
25998
25998
  }
25999
25999
  }
26000
26000
  },
26001
+ {
26002
+ "id": "himi_product.options_card",
26003
+ "body": {
26004
+ "package": "himalaya",
26005
+ "type": "VStack",
26006
+ "props": {
26007
+ "spacing": 12,
26008
+ "alignment": "leading",
26009
+ "children": [
26010
+ {
26011
+ "id": "himi_product.opt1_row",
26012
+ "body": {
26013
+ "package": "himalaya",
26014
+ "type": "VStack",
26015
+ "props": {
26016
+ "spacing": 8,
26017
+ "alignment": "leading",
26018
+ "children": [
26019
+ {
26020
+ "id": "",
26021
+ "body": {
26022
+ "package": "himalaya",
26023
+ "type": "Text",
26024
+ "props": {
26025
+ "text": "$service:himiStoreProduct.opt1Label",
26026
+ "style": "bodyEmphasis",
26027
+ "collapseWhenEmpty": true
26028
+ }
26029
+ }
26030
+ },
26031
+ {
26032
+ "id": "himi_product.opt1",
26033
+ "body": {
26034
+ "package": "himalaya",
26035
+ "type": "FilterChips",
26036
+ "props": {
26037
+ "chips": [],
26038
+ "optionsPath": "$service:himiStoreProduct.opt1Chips",
26039
+ "selectedIds": [
26040
+ "$service:himiStoreProduct.opt1Selected"
26041
+ ],
26042
+ "onChange": {
26043
+ "actionId": "tier5.himiStoreProduct.selectOption",
26044
+ "params": {
26045
+ "group": "1"
26046
+ }
26047
+ }
26048
+ }
26049
+ },
26050
+ "modifiers": {
26051
+ "accessibilityLabel": "$service:himiStoreProduct.opt1Label"
26052
+ }
26053
+ }
26054
+ ]
26055
+ }
26056
+ },
26057
+ "modifiers": {
26058
+ "hiddenPath": "$service:himiStoreProduct.noOpt1"
26059
+ }
26060
+ },
26061
+ {
26062
+ "id": "himi_product.opt2_row",
26063
+ "body": {
26064
+ "package": "himalaya",
26065
+ "type": "VStack",
26066
+ "props": {
26067
+ "spacing": 8,
26068
+ "alignment": "leading",
26069
+ "children": [
26070
+ {
26071
+ "id": "",
26072
+ "body": {
26073
+ "package": "himalaya",
26074
+ "type": "Text",
26075
+ "props": {
26076
+ "text": "$service:himiStoreProduct.opt2Label",
26077
+ "style": "bodyEmphasis",
26078
+ "collapseWhenEmpty": true
26079
+ }
26080
+ }
26081
+ },
26082
+ {
26083
+ "id": "himi_product.opt2",
26084
+ "body": {
26085
+ "package": "himalaya",
26086
+ "type": "FilterChips",
26087
+ "props": {
26088
+ "chips": [],
26089
+ "optionsPath": "$service:himiStoreProduct.opt2Chips",
26090
+ "selectedIds": [
26091
+ "$service:himiStoreProduct.opt2Selected"
26092
+ ],
26093
+ "onChange": {
26094
+ "actionId": "tier5.himiStoreProduct.selectOption",
26095
+ "params": {
26096
+ "group": "2"
26097
+ }
26098
+ }
26099
+ }
26100
+ },
26101
+ "modifiers": {
26102
+ "accessibilityLabel": "$service:himiStoreProduct.opt2Label"
26103
+ }
26104
+ }
26105
+ ]
26106
+ }
26107
+ },
26108
+ "modifiers": {
26109
+ "hiddenPath": "$service:himiStoreProduct.noOpt2"
26110
+ }
26111
+ },
26112
+ {
26113
+ "id": "himi_product.opt3_row",
26114
+ "body": {
26115
+ "package": "himalaya",
26116
+ "type": "VStack",
26117
+ "props": {
26118
+ "spacing": 8,
26119
+ "alignment": "leading",
26120
+ "children": [
26121
+ {
26122
+ "id": "",
26123
+ "body": {
26124
+ "package": "himalaya",
26125
+ "type": "Text",
26126
+ "props": {
26127
+ "text": "$service:himiStoreProduct.opt3Label",
26128
+ "style": "bodyEmphasis",
26129
+ "collapseWhenEmpty": true
26130
+ }
26131
+ }
26132
+ },
26133
+ {
26134
+ "id": "himi_product.opt3",
26135
+ "body": {
26136
+ "package": "himalaya",
26137
+ "type": "FilterChips",
26138
+ "props": {
26139
+ "chips": [],
26140
+ "optionsPath": "$service:himiStoreProduct.opt3Chips",
26141
+ "selectedIds": [
26142
+ "$service:himiStoreProduct.opt3Selected"
26143
+ ],
26144
+ "onChange": {
26145
+ "actionId": "tier5.himiStoreProduct.selectOption",
26146
+ "params": {
26147
+ "group": "3"
26148
+ }
26149
+ }
26150
+ }
26151
+ },
26152
+ "modifiers": {
26153
+ "accessibilityLabel": "$service:himiStoreProduct.opt3Label"
26154
+ }
26155
+ }
26156
+ ]
26157
+ }
26158
+ },
26159
+ "modifiers": {
26160
+ "hiddenPath": "$service:himiStoreProduct.noOpt3"
26161
+ }
26162
+ },
26163
+ {
26164
+ "id": "himi_product.options_hint",
26165
+ "body": {
26166
+ "package": "himalaya",
26167
+ "type": "Text",
26168
+ "props": {
26169
+ "text": "$service:himiStoreProduct.optionsHint",
26170
+ "style": "footnote",
26171
+ "color": "textSecondary",
26172
+ "collapseWhenEmpty": true
26173
+ }
26174
+ }
26175
+ },
26176
+ {
26177
+ "id": "",
26178
+ "body": {
26179
+ "package": "himalaya",
26180
+ "type": "Text",
26181
+ "props": {
26182
+ "text": "This product has more options than this screen can show. Open it on the website to order.",
26183
+ "style": "footnote",
26184
+ "color": "textSecondary"
26185
+ }
26186
+ },
26187
+ "modifiers": {
26188
+ "hiddenPath": "$service:himiStoreProduct.noOptionsOverflow"
26189
+ }
26190
+ }
26191
+ ]
26192
+ }
26193
+ },
26194
+ "modifiers": {
26195
+ "background": {
26196
+ "token": "surfaceElevated"
26197
+ },
26198
+ "border": {
26199
+ "width": 1,
26200
+ "color": {
26201
+ "token": "border"
26202
+ }
26203
+ },
26204
+ "cornerRadius": 8,
26205
+ "padding": {
26206
+ "leading": 14,
26207
+ "trailing": 14,
26208
+ "top": 14,
26209
+ "bottom": 14
26210
+ },
26211
+ "hiddenPath": "$service:himiStoreProduct.noOptions"
26212
+ }
26213
+ },
26001
26214
  {
26002
26215
  "id": "himi_product.qty_card",
26003
26216
  "body": {
@@ -26282,7 +26495,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
26282
26495
  "fullWidth": true,
26283
26496
  "action": {
26284
26497
  "actionId": "tier5.himiStoreProduct.addToCart"
26285
- }
26498
+ },
26499
+ "disabledPath": "$service:himiStoreProduct.optionsIncomplete"
26286
26500
  }
26287
26501
  },
26288
26502
  "modifiers": {