@cimplify/sdk 0.8.14 → 0.9.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.
package/dist/react.js CHANGED
@@ -612,6 +612,12 @@ function normalizeCatalogueProductPayload(product) {
612
612
  if (variantAdjustment === void 0 || variantAdjustment === null || variantAdjustment === "") {
613
613
  normalizedVariant["price_adjustment"] = readFinalPrice(normalizedVariant["price_info"]) ?? "0";
614
614
  }
615
+ if (!normalizedVariant["name"]) {
616
+ const attrs = normalizedVariant["display_attributes"];
617
+ if (Array.isArray(attrs) && attrs.length > 0) {
618
+ normalizedVariant["name"] = attrs.map((a) => a.value_name).filter(Boolean).join(" / ");
619
+ }
620
+ }
615
621
  return normalizedVariant;
616
622
  });
617
623
  }
@@ -6778,16 +6784,940 @@ function useCheckout() {
6778
6784
  );
6779
6785
  return { submit, process, isLoading };
6780
6786
  }
6787
+ function QuantitySelector({
6788
+ value,
6789
+ onChange,
6790
+ min = 1,
6791
+ max,
6792
+ className
6793
+ }) {
6794
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-quantity": true, className, style: { display: "inline-flex", alignItems: "center", gap: "0.5rem" }, children: [
6795
+ /* @__PURE__ */ jsxRuntime.jsx(
6796
+ "button",
6797
+ {
6798
+ type: "button",
6799
+ onClick: () => onChange(Math.max(min, value - 1)),
6800
+ disabled: value <= min,
6801
+ "aria-label": "Decrease quantity",
6802
+ "data-cimplify-quantity-decrement": true,
6803
+ children: "\u2212"
6804
+ }
6805
+ ),
6806
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-quantity-value": true, "aria-live": "polite", children: value }),
6807
+ /* @__PURE__ */ jsxRuntime.jsx(
6808
+ "button",
6809
+ {
6810
+ type: "button",
6811
+ onClick: () => onChange(max != null ? Math.min(max, value + 1) : value + 1),
6812
+ disabled: max != null && value >= max,
6813
+ "aria-label": "Increase quantity",
6814
+ "data-cimplify-quantity-increment": true,
6815
+ children: "+"
6816
+ }
6817
+ )
6818
+ ] });
6819
+ }
6820
+
6821
+ // src/utils/variant.ts
6822
+ function getVariantDisplayName(variant) {
6823
+ if (variant.name) return variant.name;
6824
+ if (variant.display_attributes?.length) {
6825
+ return variant.display_attributes.map((a) => a.value_name).join(" / ");
6826
+ }
6827
+ return variant.is_default ? "Default" : "Option";
6828
+ }
6829
+ function VariantSelector({
6830
+ variants,
6831
+ variantAxes,
6832
+ basePrice,
6833
+ selectedVariantId,
6834
+ onVariantChange,
6835
+ className
6836
+ }) {
6837
+ const [axisSelections, setAxisSelections] = React3.useState({});
6838
+ const initialized = React3.useRef(false);
6839
+ React3.useEffect(() => {
6840
+ initialized.current = false;
6841
+ }, [variants]);
6842
+ React3.useEffect(() => {
6843
+ if (initialized.current) return;
6844
+ if (!variants || variants.length === 0) return;
6845
+ const defaultVariant = variants.find((v) => v.is_default) || variants[0];
6846
+ if (!defaultVariant) return;
6847
+ initialized.current = true;
6848
+ onVariantChange(defaultVariant.id, defaultVariant);
6849
+ if (defaultVariant.display_attributes) {
6850
+ const initial = {};
6851
+ for (const attr of defaultVariant.display_attributes) {
6852
+ initial[attr.axis_id] = attr.value_id;
6853
+ }
6854
+ setAxisSelections(initial);
6855
+ }
6856
+ }, [variants, onVariantChange]);
6857
+ React3.useEffect(() => {
6858
+ if (!initialized.current) return;
6859
+ if (!variantAxes || variantAxes.length === 0) return;
6860
+ const match = variants.find((v) => {
6861
+ if (!v.display_attributes) return false;
6862
+ return v.display_attributes.every(
6863
+ (attr) => axisSelections[attr.axis_id] === attr.value_id
6864
+ );
6865
+ });
6866
+ if (match && match.id !== selectedVariantId) {
6867
+ onVariantChange(match.id, match);
6868
+ }
6869
+ }, [axisSelections, variants, variantAxes, selectedVariantId, onVariantChange]);
6870
+ if (!variants || variants.length <= 1) {
6871
+ return null;
6872
+ }
6873
+ const basePriceNum = basePrice != null ? parsePrice(basePrice) : 0;
6874
+ if (variantAxes && variantAxes.length > 0) {
6875
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-selector": true, className, children: variantAxes.map((axis) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-variant-axis": true, children: [
6876
+ /* @__PURE__ */ jsxRuntime.jsx("label", { "data-cimplify-variant-axis-label": true, children: axis.name }),
6877
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-axis-options": true, children: axis.values.map((value) => {
6878
+ const isSelected = axisSelections[axis.id] === value.id;
6879
+ return /* @__PURE__ */ jsxRuntime.jsx(
6880
+ "button",
6881
+ {
6882
+ type: "button",
6883
+ "aria-selected": isSelected,
6884
+ onClick: () => {
6885
+ setAxisSelections((prev) => ({
6886
+ ...prev,
6887
+ [axis.id]: value.id
6888
+ }));
6889
+ },
6890
+ "data-cimplify-variant-option": true,
6891
+ "data-selected": isSelected || void 0,
6892
+ children: value.name
6893
+ },
6894
+ value.id
6895
+ );
6896
+ }) })
6897
+ ] }, axis.id)) });
6898
+ }
6899
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-variant-selector": true, className, children: [
6900
+ /* @__PURE__ */ jsxRuntime.jsx("label", { "data-cimplify-variant-list-label": true, children: "Options" }),
6901
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-list": true, children: variants.map((variant) => {
6902
+ const isSelected = selectedVariantId === variant.id;
6903
+ const adjustment = parsePrice(variant.price_adjustment);
6904
+ const effectivePrice = basePriceNum + adjustment;
6905
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6906
+ "button",
6907
+ {
6908
+ type: "button",
6909
+ "aria-selected": isSelected,
6910
+ onClick: () => onVariantChange(variant.id, variant),
6911
+ "data-cimplify-variant-option": true,
6912
+ "data-selected": isSelected || void 0,
6913
+ children: [
6914
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-variant-name": true, children: getVariantDisplayName(variant) }),
6915
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, children: [
6916
+ adjustment !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-adjustment": true, children: [
6917
+ adjustment > 0 ? "+" : "",
6918
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: variant.price_adjustment })
6919
+ ] }),
6920
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: effectivePrice })
6921
+ ] })
6922
+ ]
6923
+ },
6924
+ variant.id
6925
+ );
6926
+ }) })
6927
+ ] });
6928
+ }
6929
+ function AddOnSelector({
6930
+ addOns,
6931
+ selectedOptions,
6932
+ onOptionsChange,
6933
+ className
6934
+ }) {
6935
+ const isOptionSelected = React3.useCallback(
6936
+ (optionId) => selectedOptions.includes(optionId),
6937
+ [selectedOptions]
6938
+ );
6939
+ const toggleOption = React3.useCallback(
6940
+ (addOn, optionId) => {
6941
+ const isSelected = selectedOptions.includes(optionId);
6942
+ if (addOn.is_mutually_exclusive || !addOn.is_multiple_allowed) {
6943
+ const groupOptionIds = new Set(addOn.options.map((o) => o.id));
6944
+ const withoutGroup = selectedOptions.filter((id) => !groupOptionIds.has(id));
6945
+ if (isSelected) {
6946
+ if (!addOn.is_required) {
6947
+ onOptionsChange(withoutGroup);
6948
+ }
6949
+ } else {
6950
+ onOptionsChange([...withoutGroup, optionId]);
6951
+ }
6952
+ } else {
6953
+ if (isSelected) {
6954
+ onOptionsChange(selectedOptions.filter((id) => id !== optionId));
6955
+ } else {
6956
+ const currentCount = selectedOptions.filter(
6957
+ (id) => addOn.options.some((o) => o.id === id)
6958
+ ).length;
6959
+ if (addOn.max_selections && currentCount >= addOn.max_selections) {
6960
+ return;
6961
+ }
6962
+ onOptionsChange([...selectedOptions, optionId]);
6963
+ }
6964
+ }
6965
+ },
6966
+ [selectedOptions, onOptionsChange]
6967
+ );
6968
+ if (!addOns || addOns.length === 0) {
6969
+ return null;
6970
+ }
6971
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-addon-selector": true, className, children: addOns.map((addOn) => {
6972
+ const currentSelections = selectedOptions.filter(
6973
+ (id) => addOn.options.some((o) => o.id === id)
6974
+ ).length;
6975
+ const minMet = !addOn.min_selections || currentSelections >= addOn.min_selections;
6976
+ const isSingleSelect = addOn.is_mutually_exclusive || !addOn.is_multiple_allowed;
6977
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-addon-group": true, children: [
6978
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-addon-header": true, children: [
6979
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6980
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-addon-name": true, children: [
6981
+ addOn.name,
6982
+ addOn.is_required && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-addon-required": true, children: " *" })
6983
+ ] }),
6984
+ (addOn.min_selections || addOn.max_selections) && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-addon-constraint": true, children: addOn.min_selections && addOn.max_selections ? `Choose ${addOn.min_selections}\u2013${addOn.max_selections}` : addOn.min_selections ? `Choose at least ${addOn.min_selections}` : `Choose up to ${addOn.max_selections}` })
6985
+ ] }),
6986
+ !minMet && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-addon-validation": true, children: "Required" })
6987
+ ] }),
6988
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-addon-options": true, children: addOn.options.map((option) => {
6989
+ const isSelected = isOptionSelected(option.id);
6990
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6991
+ "button",
6992
+ {
6993
+ type: "button",
6994
+ role: isSingleSelect ? "radio" : "checkbox",
6995
+ "aria-checked": isSelected,
6996
+ onClick: () => toggleOption(addOn, option.id),
6997
+ "data-cimplify-addon-option": true,
6998
+ "data-selected": isSelected || void 0,
6999
+ children: [
7000
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-addon-option-name": true, children: option.name }),
7001
+ option.default_price && option.default_price !== "0" && /* @__PURE__ */ jsxRuntime.jsx(
7002
+ Price,
7003
+ {
7004
+ amount: option.default_price,
7005
+ prefix: "+"
7006
+ }
7007
+ )
7008
+ ]
7009
+ },
7010
+ option.id
7011
+ );
7012
+ }) })
7013
+ ] }, addOn.id);
7014
+ }) });
7015
+ }
7016
+ function CompositeSelector({
7017
+ productId,
7018
+ onSelectionsChange,
7019
+ onPriceChange,
7020
+ onReady,
7021
+ className
7022
+ }) {
7023
+ const { composite, isLoading, error, calculatePrice, priceResult, isPriceLoading } = useComposite(productId);
7024
+ const [groupSelections, setGroupSelections] = React3.useState({});
7025
+ const selections = React3.useMemo(() => {
7026
+ const result = [];
7027
+ for (const groupSels of Object.values(groupSelections)) {
7028
+ for (const [componentId, qty] of Object.entries(groupSels)) {
7029
+ if (qty > 0) {
7030
+ result.push({ component_id: componentId, quantity: qty });
7031
+ }
7032
+ }
7033
+ }
7034
+ return result;
7035
+ }, [groupSelections]);
7036
+ React3.useEffect(() => {
7037
+ onSelectionsChange(selections);
7038
+ }, [selections, onSelectionsChange]);
7039
+ React3.useEffect(() => {
7040
+ onPriceChange?.(priceResult);
7041
+ }, [priceResult, onPriceChange]);
7042
+ const allGroupsSatisfied = React3.useMemo(() => {
7043
+ if (!composite) return false;
7044
+ for (const group of composite.groups) {
7045
+ const groupSels = groupSelections[group.id] || {};
7046
+ const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7047
+ if (totalSelected < group.min_selections) return false;
7048
+ }
7049
+ return true;
7050
+ }, [composite, groupSelections]);
7051
+ React3.useEffect(() => {
7052
+ onReady?.(allGroupsSatisfied);
7053
+ }, [allGroupsSatisfied, onReady]);
7054
+ React3.useEffect(() => {
7055
+ if (allGroupsSatisfied && selections.length > 0) {
7056
+ void calculatePrice(selections);
7057
+ }
7058
+ }, [selections, allGroupsSatisfied, calculatePrice]);
7059
+ const toggleComponent = React3.useCallback(
7060
+ (group, component) => {
7061
+ setGroupSelections((prev) => {
7062
+ const groupSels = { ...prev[group.id] || {} };
7063
+ const currentQty = groupSels[component.id] || 0;
7064
+ if (currentQty > 0) {
7065
+ if (group.min_selections > 0) {
7066
+ const totalOthers = Object.entries(groupSels).filter(([id]) => id !== component.id).reduce((sum, [, q]) => sum + q, 0);
7067
+ if (totalOthers < group.min_selections) {
7068
+ return prev;
7069
+ }
7070
+ }
7071
+ delete groupSels[component.id];
7072
+ } else {
7073
+ const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7074
+ if (group.max_selections && totalSelected >= group.max_selections) {
7075
+ if (group.max_selections === 1) {
7076
+ return { ...prev, [group.id]: { [component.id]: 1 } };
7077
+ }
7078
+ return prev;
7079
+ }
7080
+ groupSels[component.id] = 1;
7081
+ }
7082
+ return { ...prev, [group.id]: groupSels };
7083
+ });
7084
+ },
7085
+ []
7086
+ );
7087
+ const updateQuantity = React3.useCallback(
7088
+ (group, componentId, delta) => {
7089
+ setGroupSelections((prev) => {
7090
+ const groupSels = { ...prev[group.id] || {} };
7091
+ const current = groupSels[componentId] || 0;
7092
+ const next = Math.max(0, current + delta);
7093
+ if (group.max_quantity_per_component && next > group.max_quantity_per_component) {
7094
+ return prev;
7095
+ }
7096
+ if (next === 0) {
7097
+ delete groupSels[componentId];
7098
+ } else {
7099
+ groupSels[componentId] = next;
7100
+ }
7101
+ return { ...prev, [group.id]: groupSels };
7102
+ });
7103
+ },
7104
+ []
7105
+ );
7106
+ if (isLoading) {
7107
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-selector": true, "data-loading": true, className, children: "Loading options..." });
7108
+ }
7109
+ if (error || !composite) {
7110
+ return null;
7111
+ }
7112
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-selector": true, className, children: [
7113
+ composite.groups.sort((a, b) => a.display_order - b.display_order).map((group) => {
7114
+ const groupSels = groupSelections[group.id] || {};
7115
+ const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
7116
+ const minMet = totalSelected >= group.min_selections;
7117
+ const isSingleSelect = group.max_selections === 1;
7118
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-group": true, children: [
7119
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-group-header": true, children: [
7120
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7121
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-composite-group-name": true, children: [
7122
+ group.name,
7123
+ group.min_selections > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-required": true, children: " *" })
7124
+ ] }),
7125
+ group.description && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-group-description": true, children: group.description }),
7126
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-group-constraint": true, children: group.min_selections > 0 && group.max_selections ? `Choose ${group.min_selections}\u2013${group.max_selections}` : group.min_selections > 0 ? `Choose at least ${group.min_selections}` : group.max_selections ? `Choose up to ${group.max_selections}` : "Choose as many as you like" })
7127
+ ] }),
7128
+ !minMet && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-validation": true, children: "Required" })
7129
+ ] }),
7130
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-components": true, children: group.components.filter((c) => c.is_available && !c.is_archived).sort((a, b) => a.display_order - b.display_order).map((component) => {
7131
+ const qty = groupSels[component.id] || 0;
7132
+ const isSelected = qty > 0;
7133
+ const displayName = component.display_name || component.product_id || component.id;
7134
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7135
+ "button",
7136
+ {
7137
+ type: "button",
7138
+ role: isSingleSelect ? "radio" : "checkbox",
7139
+ "aria-checked": isSelected,
7140
+ onClick: () => toggleComponent(group, component),
7141
+ "data-cimplify-composite-component": true,
7142
+ "data-selected": isSelected || void 0,
7143
+ children: [
7144
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-component-info": true, children: [
7145
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-component-name": true, children: displayName }),
7146
+ component.is_popular && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-badge": "popular", children: "Popular" }),
7147
+ component.is_premium && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-badge": "premium", children: "Premium" }),
7148
+ component.display_description && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-composite-component-description": true, children: component.display_description }),
7149
+ component.calories != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-composite-component-calories": true, children: [
7150
+ component.calories,
7151
+ " cal"
7152
+ ] })
7153
+ ] }),
7154
+ group.allow_quantity && isSelected && /* @__PURE__ */ jsxRuntime.jsxs(
7155
+ "span",
7156
+ {
7157
+ "data-cimplify-composite-qty": true,
7158
+ onClick: (e) => e.stopPropagation(),
7159
+ children: [
7160
+ /* @__PURE__ */ jsxRuntime.jsx(
7161
+ "button",
7162
+ {
7163
+ type: "button",
7164
+ onClick: () => updateQuantity(group, component.id, -1),
7165
+ "aria-label": `Decrease ${displayName} quantity`,
7166
+ children: "\u2212"
7167
+ }
7168
+ ),
7169
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: qty }),
7170
+ /* @__PURE__ */ jsxRuntime.jsx(
7171
+ "button",
7172
+ {
7173
+ type: "button",
7174
+ onClick: () => updateQuantity(group, component.id, 1),
7175
+ "aria-label": `Increase ${displayName} quantity`,
7176
+ children: "+"
7177
+ }
7178
+ )
7179
+ ]
7180
+ }
7181
+ ),
7182
+ component.price && component.price !== "0" && /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: component.price, prefix: "+" })
7183
+ ]
7184
+ },
7185
+ component.id
7186
+ );
7187
+ }) })
7188
+ ] }, group.id);
7189
+ }),
7190
+ priceResult && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary": true, children: [
7191
+ priceResult.base_price !== "0" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-line": true, children: [
7192
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Base" }),
7193
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.base_price })
7194
+ ] }),
7195
+ priceResult.components_total !== "0" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-line": true, children: [
7196
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Selections" }),
7197
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.components_total })
7198
+ ] }),
7199
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-composite-summary-total": true, children: [
7200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
7201
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: priceResult.final_price })
7202
+ ] })
7203
+ ] }),
7204
+ isPriceLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-composite-calculating": true, children: "Calculating price..." })
7205
+ ] });
7206
+ }
7207
+ function BundleSelector({
7208
+ bundleIdOrSlug,
7209
+ onSelectionsChange,
7210
+ onReady,
7211
+ className
7212
+ }) {
7213
+ const { bundle, isLoading, error } = useBundle(bundleIdOrSlug);
7214
+ const [variantChoices, setVariantChoices] = React3.useState({});
7215
+ React3.useEffect(() => {
7216
+ if (!bundle) return;
7217
+ const defaults = {};
7218
+ for (const comp of bundle.components) {
7219
+ if (comp.component.variant_id) {
7220
+ defaults[comp.component.id] = comp.component.variant_id;
7221
+ } else if (comp.variants.length > 0) {
7222
+ const defaultVariant = comp.variants.find((v) => v.is_default) || comp.variants[0];
7223
+ if (defaultVariant) {
7224
+ defaults[comp.component.id] = defaultVariant.id;
7225
+ }
7226
+ }
7227
+ }
7228
+ setVariantChoices(defaults);
7229
+ }, [bundle]);
7230
+ const selections = React3.useMemo(() => {
7231
+ if (!bundle) return [];
7232
+ return bundle.components.map((comp) => ({
7233
+ component_id: comp.component.id,
7234
+ variant_id: variantChoices[comp.component.id],
7235
+ quantity: comp.component.quantity
7236
+ }));
7237
+ }, [bundle, variantChoices]);
7238
+ React3.useEffect(() => {
7239
+ onSelectionsChange(selections);
7240
+ }, [selections, onSelectionsChange]);
7241
+ React3.useEffect(() => {
7242
+ onReady?.(bundle != null && selections.length > 0);
7243
+ }, [bundle, selections, onReady]);
7244
+ const handleVariantChange = React3.useCallback(
7245
+ (componentId, variantId) => {
7246
+ setVariantChoices((prev) => ({ ...prev, [componentId]: variantId }));
7247
+ },
7248
+ []
7249
+ );
7250
+ if (isLoading) {
7251
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-selector": true, "data-loading": true, className, children: "Loading bundle..." });
7252
+ }
7253
+ if (error || !bundle) {
7254
+ return null;
7255
+ }
7256
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-selector": true, className, children: [
7257
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-bundle-heading": true, children: "Included in this bundle" }),
7258
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-components": true, children: bundle.components.map((comp) => /* @__PURE__ */ jsxRuntime.jsx(
7259
+ BundleComponentCard,
7260
+ {
7261
+ data: comp,
7262
+ selectedVariantId: variantChoices[comp.component.id],
7263
+ onVariantChange: (variantId) => handleVariantChange(comp.component.id, variantId)
7264
+ },
7265
+ comp.component.id
7266
+ )) }),
7267
+ bundle.bundle_price && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-summary": true, children: [
7268
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Bundle price" }),
7269
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: bundle.bundle_price })
7270
+ ] }),
7271
+ bundle.discount_value && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-savings": true, children: [
7272
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "You save" }),
7273
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: bundle.discount_value })
7274
+ ] })
7275
+ ] });
7276
+ }
7277
+ function BundleComponentCard({
7278
+ data,
7279
+ selectedVariantId,
7280
+ onVariantChange
7281
+ }) {
7282
+ const { component, product, variants } = data;
7283
+ const showVariantPicker = component.allow_variant_choice && variants.length > 1;
7284
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-component": true, children: [
7285
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bundle-component-header": true, children: [
7286
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7287
+ component.quantity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-bundle-component-qty": true, children: [
7288
+ "\xD7",
7289
+ component.quantity
7290
+ ] }),
7291
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-bundle-component-name": true, children: product.name })
7292
+ ] }),
7293
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price })
7294
+ ] }),
7295
+ showVariantPicker && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bundle-variant-picker": true, children: variants.map((variant) => {
7296
+ const isSelected = selectedVariantId === variant.id;
7297
+ const adjustment = parsePrice(variant.price_adjustment);
7298
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7299
+ "button",
7300
+ {
7301
+ type: "button",
7302
+ "aria-selected": isSelected,
7303
+ onClick: () => onVariantChange(variant.id),
7304
+ "data-cimplify-bundle-variant-option": true,
7305
+ "data-selected": isSelected || void 0,
7306
+ children: [
7307
+ getVariantDisplayName(variant),
7308
+ adjustment !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-bundle-variant-adjustment": true, children: [
7309
+ adjustment > 0 ? "+" : "",
7310
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: variant.price_adjustment })
7311
+ ] })
7312
+ ]
7313
+ },
7314
+ variant.id
7315
+ );
7316
+ }) })
7317
+ ] });
7318
+ }
7319
+ function ProductCustomizer({
7320
+ product,
7321
+ onAddToCart,
7322
+ className
7323
+ }) {
7324
+ const [quantity, setQuantity] = React3.useState(1);
7325
+ const [isAdded, setIsAdded] = React3.useState(false);
7326
+ const [isSubmitting, setIsSubmitting] = React3.useState(false);
7327
+ const [selectedVariantId, setSelectedVariantId] = React3.useState();
7328
+ const [selectedVariant, setSelectedVariant] = React3.useState();
7329
+ const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] = React3.useState([]);
7330
+ const [compositeSelections, setCompositeSelections] = React3.useState([]);
7331
+ const [compositePrice, setCompositePrice] = React3.useState(null);
7332
+ const [compositeReady, setCompositeReady] = React3.useState(false);
7333
+ const [bundleSelections, setBundleSelections] = React3.useState([]);
7334
+ const [bundleReady, setBundleReady] = React3.useState(false);
7335
+ const cart = useCart();
7336
+ const productType = product.product_type || "product";
7337
+ const isComposite = productType === "composite";
7338
+ const isBundle = productType === "bundle";
7339
+ const isStandard = !isComposite && !isBundle;
7340
+ const hasVariants = isStandard && product.variants && product.variants.length > 0;
7341
+ const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
7342
+ React3.useEffect(() => {
7343
+ setQuantity(1);
7344
+ setIsAdded(false);
7345
+ setIsSubmitting(false);
7346
+ setSelectedVariantId(void 0);
7347
+ setSelectedVariant(void 0);
7348
+ setSelectedAddOnOptionIds([]);
7349
+ setCompositeSelections([]);
7350
+ setCompositePrice(null);
7351
+ setCompositeReady(false);
7352
+ setBundleSelections([]);
7353
+ setBundleReady(false);
7354
+ }, [product.id]);
7355
+ const selectedAddOnOptions = React3.useMemo(() => {
7356
+ if (!product.add_ons) return [];
7357
+ const options = [];
7358
+ for (const addOn of product.add_ons) {
7359
+ for (const option of addOn.options) {
7360
+ if (selectedAddOnOptionIds.includes(option.id)) {
7361
+ options.push(option);
7362
+ }
7363
+ }
7364
+ }
7365
+ return options;
7366
+ }, [product.add_ons, selectedAddOnOptionIds]);
7367
+ const normalizedAddOnOptionIds = React3.useMemo(() => {
7368
+ if (selectedAddOnOptionIds.length === 0) return [];
7369
+ return Array.from(new Set(selectedAddOnOptionIds.map((id) => id.trim()).filter(Boolean))).sort();
7370
+ }, [selectedAddOnOptionIds]);
7371
+ const localTotalPrice = React3.useMemo(() => {
7372
+ if (isComposite && compositePrice) {
7373
+ return parsePrice(compositePrice.final_price) * quantity;
7374
+ }
7375
+ let price = parsePrice(product.default_price);
7376
+ if (selectedVariant?.price_adjustment) {
7377
+ price += parsePrice(selectedVariant.price_adjustment);
7378
+ }
7379
+ for (const option of selectedAddOnOptions) {
7380
+ if (option.default_price) {
7381
+ price += parsePrice(option.default_price);
7382
+ }
7383
+ }
7384
+ return price * quantity;
7385
+ }, [product.default_price, selectedVariant, selectedAddOnOptions, quantity, isComposite, compositePrice]);
7386
+ const requiredAddOnsSatisfied = React3.useMemo(() => {
7387
+ if (!product.add_ons) return true;
7388
+ for (const addOn of product.add_ons) {
7389
+ if (addOn.is_required) {
7390
+ const selectedInGroup = selectedAddOnOptionIds.filter(
7391
+ (id) => addOn.options.some((opt) => opt.id === id)
7392
+ ).length;
7393
+ const minRequired = addOn.min_selections || 1;
7394
+ if (selectedInGroup < minRequired) {
7395
+ return false;
7396
+ }
7397
+ }
7398
+ }
7399
+ return true;
7400
+ }, [product.add_ons, selectedAddOnOptionIds]);
7401
+ const quoteInput = React3.useMemo(
7402
+ () => ({
7403
+ productId: product.id,
7404
+ quantity,
7405
+ variantId: selectedVariantId,
7406
+ addOnOptionIds: normalizedAddOnOptionIds.length > 0 ? normalizedAddOnOptionIds : void 0
7407
+ }),
7408
+ [product.id, quantity, selectedVariantId, normalizedAddOnOptionIds]
7409
+ );
7410
+ const { quote } = useQuote(quoteInput, {
7411
+ enabled: isStandard && requiredAddOnsSatisfied
7412
+ });
7413
+ const quoteId = quote?.quote_id;
7414
+ const quotedTotalPrice = React3.useMemo(() => {
7415
+ if (!quote) return void 0;
7416
+ const quotedTotal = quote.quoted_total_price_info?.final_price ?? quote.final_price_info.final_price;
7417
+ return quotedTotal === void 0 || quotedTotal === null ? void 0 : parsePrice(quotedTotal);
7418
+ }, [quote]);
7419
+ const displayTotalPrice = quotedTotalPrice ?? localTotalPrice;
7420
+ const canAddToCart = React3.useMemo(() => {
7421
+ if (isComposite) return compositeReady;
7422
+ if (isBundle) return bundleReady;
7423
+ return requiredAddOnsSatisfied;
7424
+ }, [isComposite, isBundle, compositeReady, bundleReady, requiredAddOnsSatisfied]);
7425
+ const handleVariantChange = React3.useCallback(
7426
+ (variantId, variant) => {
7427
+ setSelectedVariantId(variantId);
7428
+ setSelectedVariant(variant);
7429
+ },
7430
+ []
7431
+ );
7432
+ const handleAddToCart = async () => {
7433
+ if (isSubmitting) return;
7434
+ setIsSubmitting(true);
7435
+ const options = {
7436
+ variantId: selectedVariantId,
7437
+ variant: selectedVariant ? { id: selectedVariant.id, name: selectedVariant.name || "", price_adjustment: selectedVariant.price_adjustment } : void 0,
7438
+ quoteId,
7439
+ addOnOptionIds: normalizedAddOnOptionIds.length > 0 ? normalizedAddOnOptionIds : void 0,
7440
+ addOnOptions: selectedAddOnOptions.length > 0 ? selectedAddOnOptions.map((opt) => ({
7441
+ id: opt.id,
7442
+ name: opt.name,
7443
+ add_on_id: opt.add_on_id,
7444
+ default_price: opt.default_price
7445
+ })) : void 0,
7446
+ compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
7447
+ bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0
7448
+ };
7449
+ try {
7450
+ if (onAddToCart) {
7451
+ await onAddToCart(product, quantity, options);
7452
+ } else {
7453
+ await cart.addItem(product, quantity, options);
7454
+ }
7455
+ setIsAdded(true);
7456
+ setTimeout(() => {
7457
+ setIsAdded(false);
7458
+ setQuantity(1);
7459
+ }, 2e3);
7460
+ } catch {
7461
+ } finally {
7462
+ setIsSubmitting(false);
7463
+ }
7464
+ };
7465
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer": true, className, children: [
7466
+ isComposite && /* @__PURE__ */ jsxRuntime.jsx(
7467
+ CompositeSelector,
7468
+ {
7469
+ productId: product.id,
7470
+ onSelectionsChange: setCompositeSelections,
7471
+ onPriceChange: setCompositePrice,
7472
+ onReady: setCompositeReady
7473
+ }
7474
+ ),
7475
+ isBundle && /* @__PURE__ */ jsxRuntime.jsx(
7476
+ BundleSelector,
7477
+ {
7478
+ bundleIdOrSlug: product.slug,
7479
+ onSelectionsChange: setBundleSelections,
7480
+ onReady: setBundleReady
7481
+ }
7482
+ ),
7483
+ hasVariants && /* @__PURE__ */ jsxRuntime.jsx(
7484
+ VariantSelector,
7485
+ {
7486
+ variants: product.variants,
7487
+ variantAxes: product.variant_axes,
7488
+ basePrice: product.default_price,
7489
+ selectedVariantId,
7490
+ onVariantChange: handleVariantChange
7491
+ }
7492
+ ),
7493
+ hasAddOns && /* @__PURE__ */ jsxRuntime.jsx(
7494
+ AddOnSelector,
7495
+ {
7496
+ addOns: product.add_ons,
7497
+ selectedOptions: selectedAddOnOptionIds,
7498
+ onOptionsChange: setSelectedAddOnOptionIds
7499
+ }
7500
+ ),
7501
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer-actions": true, children: [
7502
+ /* @__PURE__ */ jsxRuntime.jsx(
7503
+ QuantitySelector,
7504
+ {
7505
+ value: quantity,
7506
+ onChange: setQuantity,
7507
+ min: 1
7508
+ }
7509
+ ),
7510
+ /* @__PURE__ */ jsxRuntime.jsx(
7511
+ "button",
7512
+ {
7513
+ type: "button",
7514
+ onClick: handleAddToCart,
7515
+ disabled: isAdded || isSubmitting || !canAddToCart,
7516
+ "data-cimplify-customizer-submit": true,
7517
+ children: isAdded ? "Added to Cart" : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7518
+ "Add to Cart \xB7 ",
7519
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: displayTotalPrice })
7520
+ ] })
7521
+ }
7522
+ )
7523
+ ] }),
7524
+ !canAddToCart && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-customizer-validation": true, children: "Please select all required options" })
7525
+ ] });
7526
+ }
7527
+ var ASPECT_STYLES = {
7528
+ square: { aspectRatio: "1/1" },
7529
+ "4/3": { aspectRatio: "4/3" },
7530
+ "16/10": { aspectRatio: "16/10" },
7531
+ "3/4": { aspectRatio: "3/4" }
7532
+ };
7533
+ function ProductImageGallery({
7534
+ images,
7535
+ productName,
7536
+ aspectRatio = "4/3",
7537
+ className
7538
+ }) {
7539
+ const normalizedImages = React3.useMemo(
7540
+ () => images.filter(
7541
+ (image) => typeof image === "string" && image.trim().length > 0
7542
+ ),
7543
+ [images]
7544
+ );
7545
+ const [selectedImage, setSelectedImage] = React3.useState(0);
7546
+ React3.useEffect(() => {
7547
+ setSelectedImage(0);
7548
+ }, [normalizedImages.length, productName]);
7549
+ if (normalizedImages.length === 0) {
7550
+ return null;
7551
+ }
7552
+ const activeImage = normalizedImages[selectedImage] || normalizedImages[0];
7553
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-image-gallery": true, className, children: [
7554
+ /* @__PURE__ */ jsxRuntime.jsx(
7555
+ "div",
7556
+ {
7557
+ "data-cimplify-image-gallery-main": true,
7558
+ style: { position: "relative", overflow: "hidden", ...ASPECT_STYLES[aspectRatio] },
7559
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7560
+ "img",
7561
+ {
7562
+ src: activeImage,
7563
+ alt: productName,
7564
+ style: { width: "100%", height: "100%", objectFit: "cover" },
7565
+ "data-cimplify-image-gallery-active": true
7566
+ }
7567
+ )
7568
+ }
7569
+ ),
7570
+ normalizedImages.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-image-gallery-thumbnails": true, style: { display: "flex", gap: "0.5rem", marginTop: "0.75rem" }, children: normalizedImages.map((image, index) => /* @__PURE__ */ jsxRuntime.jsx(
7571
+ "button",
7572
+ {
7573
+ type: "button",
7574
+ onClick: () => setSelectedImage(index),
7575
+ "aria-selected": selectedImage === index,
7576
+ "data-cimplify-image-gallery-thumb": true,
7577
+ "data-selected": selectedImage === index || void 0,
7578
+ style: {
7579
+ width: "4rem",
7580
+ height: "4rem",
7581
+ overflow: "hidden",
7582
+ padding: 0,
7583
+ border: "none",
7584
+ cursor: "pointer"
7585
+ },
7586
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7587
+ "img",
7588
+ {
7589
+ src: image,
7590
+ alt: "",
7591
+ style: { width: "100%", height: "100%", objectFit: "cover" }
7592
+ }
7593
+ )
7594
+ },
7595
+ `${image}-${index}`
7596
+ )) })
7597
+ ] });
7598
+ }
7599
+ function computeUnitPrice(item) {
7600
+ let price = parsePrice(item.product.default_price);
7601
+ if (item.variant?.price_adjustment) {
7602
+ price += parsePrice(item.variant.price_adjustment);
7603
+ }
7604
+ for (const option of item.addOnOptions || []) {
7605
+ if (option.default_price) {
7606
+ price += parsePrice(option.default_price);
7607
+ }
7608
+ }
7609
+ return Math.round(price * 100) / 100;
7610
+ }
7611
+ function CartSummary({
7612
+ onCheckout,
7613
+ onItemRemove,
7614
+ onQuantityChange,
7615
+ emptyMessage = "Your cart is empty",
7616
+ className
7617
+ }) {
7618
+ const { items, itemCount, subtotal, tax, total, isEmpty, removeItem, updateQuantity } = useCart();
7619
+ const handleRemove = (itemId) => {
7620
+ if (onItemRemove) {
7621
+ onItemRemove(itemId);
7622
+ } else {
7623
+ void removeItem(itemId);
7624
+ }
7625
+ };
7626
+ const handleQuantityChange = (itemId, qty) => {
7627
+ if (onQuantityChange) {
7628
+ onQuantityChange(itemId, qty);
7629
+ } else {
7630
+ void updateQuantity(itemId, qty);
7631
+ }
7632
+ };
7633
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-summary": true, className, children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-empty": true, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7634
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-items": true, children: items.map((item) => {
7635
+ const unitPrice = computeUnitPrice(item);
7636
+ const hasComposite = item.compositeSelections && item.compositeSelections.length > 0;
7637
+ const hasBundle = item.bundleSelections && item.bundleSelections.length > 0;
7638
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item": true, children: [
7639
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-info": true, children: [
7640
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-name": true, children: item.product.name }),
7641
+ item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: getVariantDisplayName(item.variant) }),
7642
+ item.addOnOptions && item.addOnOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-cart-item-addons": true, children: [
7643
+ "+ ",
7644
+ item.addOnOptions.map((opt) => opt.name).join(", ")
7645
+ ] }),
7646
+ (hasComposite || hasBundle) && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-badge": true, children: hasComposite ? "Custom" : "Bundle" }),
7647
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: unitPrice })
7648
+ ] }),
7649
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-controls": true, children: [
7650
+ /* @__PURE__ */ jsxRuntime.jsx(
7651
+ QuantitySelector,
7652
+ {
7653
+ value: item.quantity,
7654
+ onChange: (qty) => handleQuantityChange(item.id, qty),
7655
+ min: 0
7656
+ }
7657
+ ),
7658
+ /* @__PURE__ */ jsxRuntime.jsx(
7659
+ "button",
7660
+ {
7661
+ type: "button",
7662
+ onClick: () => handleRemove(item.id),
7663
+ "data-cimplify-cart-item-remove": true,
7664
+ "aria-label": `Remove ${item.product.name}`,
7665
+ children: "Remove"
7666
+ }
7667
+ )
7668
+ ] })
7669
+ ] }, item.id);
7670
+ }) }),
7671
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-totals": true, children: [
7672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-subtotal": true, children: [
7673
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7674
+ "Subtotal (",
7675
+ itemCount,
7676
+ " ",
7677
+ itemCount === 1 ? "item" : "items",
7678
+ ")"
7679
+ ] }),
7680
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: subtotal })
7681
+ ] }),
7682
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-tax": true, children: [
7683
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Tax" }),
7684
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: tax })
7685
+ ] }),
7686
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-total": true, children: [
7687
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
7688
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: total })
7689
+ ] })
7690
+ ] }),
7691
+ onCheckout && /* @__PURE__ */ jsxRuntime.jsx(
7692
+ "button",
7693
+ {
7694
+ type: "button",
7695
+ onClick: onCheckout,
7696
+ "data-cimplify-cart-checkout": true,
7697
+ children: "Proceed to Checkout"
7698
+ }
7699
+ )
7700
+ ] }) });
7701
+ }
6781
7702
 
6782
7703
  exports.Ad = Ad;
6783
7704
  exports.AdProvider = AdProvider;
7705
+ exports.AddOnSelector = AddOnSelector;
6784
7706
  exports.AddressElement = AddressElement;
6785
7707
  exports.AuthElement = AuthElement;
7708
+ exports.BundleSelector = BundleSelector;
7709
+ exports.CartSummary = CartSummary;
6786
7710
  exports.CimplifyCheckout = CimplifyCheckout;
6787
7711
  exports.CimplifyProvider = CimplifyProvider;
7712
+ exports.CompositeSelector = CompositeSelector;
6788
7713
  exports.ElementsProvider = ElementsProvider;
6789
7714
  exports.PaymentElement = PaymentElement;
6790
7715
  exports.Price = Price;
7716
+ exports.ProductCustomizer = ProductCustomizer;
7717
+ exports.ProductImageGallery = ProductImageGallery;
7718
+ exports.QuantitySelector = QuantitySelector;
7719
+ exports.VariantSelector = VariantSelector;
7720
+ exports.getVariantDisplayName = getVariantDisplayName;
6791
7721
  exports.useAds = useAds;
6792
7722
  exports.useBundle = useBundle;
6793
7723
  exports.useCart = useCart;