@lime-bundles/react 7.1.0 → 7.3.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/index.js CHANGED
@@ -961,7 +961,9 @@ function FixedProductRow({ bundle, product, currency, isOos, onVariantChange })
961
961
  src: thumbImage.url,
962
962
  alt: thumbImage.altText ?? product.title,
963
963
  className: "lb-bundle__product-image",
964
- loading: "lazy"
964
+ loading: "lazy",
965
+ width: thumbImage.width ?? void 0,
966
+ height: thumbImage.height ?? void 0
965
967
  }
966
968
  ),
967
969
  /* @__PURE__ */ jsxs3("div", { className: "lb-bundle__product-info", children: [
@@ -1584,7 +1586,9 @@ function MixMatchPickerRow({
1584
1586
  {
1585
1587
  src: thumbImage.url,
1586
1588
  alt: thumbImage.altText ?? product.title,
1587
- loading: "lazy"
1589
+ loading: "lazy",
1590
+ width: thumbImage.width ?? void 0,
1591
+ height: thumbImage.height ?? void 0
1588
1592
  }
1589
1593
  ),
1590
1594
  variantInBundle && /* @__PURE__ */ jsx4("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
@@ -2506,7 +2510,9 @@ function VolumeBundle(props) {
2506
2510
  src: thumbImage.url,
2507
2511
  alt: thumbImage.altText ?? product.title,
2508
2512
  className: "lb-bundle__product-image",
2509
- loading: "lazy"
2513
+ loading: "lazy",
2514
+ width: thumbImage.width ?? void 0,
2515
+ height: thumbImage.height ?? void 0
2510
2516
  }
2511
2517
  ),
2512
2518
  /* @__PURE__ */ jsxs6("div", { className: "lb-bundle__product-info", children: [
@@ -2954,7 +2960,9 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
2954
2960
  src: thumbImage.url,
2955
2961
  alt: thumbImage.altText ?? product.title,
2956
2962
  className: "lb-bundle__product-image",
2957
- loading: "lazy"
2963
+ loading: "lazy",
2964
+ width: thumbImage.width ?? void 0,
2965
+ height: thumbImage.height ?? void 0
2958
2966
  }
2959
2967
  ),
2960
2968
  /* @__PURE__ */ jsxs7("div", { className: "lb-bundle__product-info", children: [
@@ -3006,14 +3014,13 @@ function BogoProductRow({ side, product, quantity, percent, badge, currency, onV
3006
3014
  }
3007
3015
 
3008
3016
  // src/components/MultiStepBundle.tsx
3009
- import { useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo10, useState as useState12 } from "react";
3017
+ import { Fragment, useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo10, useState as useState12 } from "react";
3010
3018
  import {
3011
3019
  formatMoney as formatMoney7,
3012
3020
  formatUnitPrice as formatUnitPrice7,
3013
3021
  calculateDiscount as calculateDiscount3,
3014
3022
  isVariantFulfillable as isVariantFulfillable7,
3015
3023
  productsForStep as productsForStep2,
3016
- stepHeadroom as stepHeadroom2,
3017
3024
  DEFAULT_PRODUCT_RULE as DEFAULT_PRODUCT_RULE4
3018
3025
  } from "@lime-bundles/core";
3019
3026
 
@@ -3148,6 +3155,17 @@ function MultiStepPicker({
3148
3155
  }
3149
3156
  return front.concat(back);
3150
3157
  }, [eligible, selectedAtLoad]);
3158
+ const autoAdvance = wc.multiStepAutoAdvance === true;
3159
+ const lastSeen = useRef7({ step: stepIndex, units: unitsInStep });
3160
+ useEffect14(() => {
3161
+ const prev = lastSeen.current;
3162
+ lastSeen.current = { step: stepIndex, units: unitsInStep };
3163
+ if (!autoAdvance || isLastStep || prev.step !== stepIndex) return;
3164
+ if (unitsInStep <= prev.units) return;
3165
+ if (stepHeadroom(step?.maxQuantity ?? null, unitsInStep) === 0) {
3166
+ goToStep(stepIndex + 1);
3167
+ }
3168
+ });
3151
3169
  function goToStep(i) {
3152
3170
  const clamped = Math.max(0, Math.min(steps.length - 1, i));
3153
3171
  setStepIndex(clamped);
@@ -3527,7 +3545,9 @@ function MultiStepPickerRow({
3527
3545
  {
3528
3546
  src: thumbImage.url,
3529
3547
  alt: thumbImage.altText ?? product.title,
3530
- loading: "lazy"
3548
+ loading: "lazy",
3549
+ width: thumbImage.width ?? void 0,
3550
+ height: thumbImage.height ?? void 0
3531
3551
  }
3532
3552
  ),
3533
3553
  variantInStep && /* @__PURE__ */ jsx8("span", { className: "lb-mix-match__modal-added-badge", children: "Added" })
@@ -3821,6 +3841,9 @@ function MultiStepBundle(props) {
3821
3841
  const allSatisfied = steps.length > 0 && steps.every((_, i) => stepSatisfied(i));
3822
3842
  const valid = !!bundle && allSatisfied;
3823
3843
  const completedSteps = steps.filter((_, i) => stepSatisfied(i)).length;
3844
+ const firstUnsatisfied = steps.findIndex((_, i) => !stepSatisfied(i));
3845
+ const remainingSteps = steps.length - completedSteps;
3846
+ const anyPicks = selections.some((s) => s.length > 0);
3824
3847
  const summary = useMemo10(() => {
3825
3848
  let comparePrice = 0;
3826
3849
  let salePrice = 0;
@@ -4063,115 +4086,156 @@ function MultiStepBundle(props) {
4063
4086
  )
4064
4087
  ] })
4065
4088
  ] }),
4066
- /* @__PURE__ */ jsx9("div", { className: "lb-multi-step__groups", "data-step-groups": true, children: steps.map((step, i) => /* @__PURE__ */ jsxs9(
4067
- "section",
4068
- {
4069
- className: "lb-multi-step__group",
4070
- "data-step-group": i,
4071
- children: [
4072
- /* @__PURE__ */ jsxs9("div", { className: "lb-multi-step__group-heading", children: [
4073
- /* @__PURE__ */ jsx9("span", { className: "lb-multi-step__group-name", children: step.name }),
4089
+ /* @__PURE__ */ jsx9("div", { className: "lb-multi-step__groups", "data-step-groups": true, children: steps.map((step, i) => /* @__PURE__ */ jsxs9(Fragment, { children: [
4090
+ i === firstUnsatisfied && /* @__PURE__ */ jsxs9(
4091
+ "button",
4092
+ {
4093
+ type: "button",
4094
+ className: "lb-mix-match__add-product lb-multi-step__door",
4095
+ "data-step-door": firstUnsatisfied,
4096
+ "aria-label": `${anyPicks ? "Continue building" : "Choose your products"}: ${step.name}`,
4097
+ onClick: () => setPickerOpenAt(firstUnsatisfied),
4098
+ children: [
4074
4099
  /* @__PURE__ */ jsx9(
4075
4100
  "span",
4076
4101
  {
4077
- className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
4078
- "data-step-count": i,
4079
- children: `${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`
4102
+ className: "lb-mix-match__add-product-icon",
4103
+ "aria-hidden": "true",
4104
+ children: /* @__PURE__ */ jsx9(PlusIcon2, {})
4080
4105
  }
4081
- )
4082
- ] }),
4083
- /* @__PURE__ */ jsx9(
4084
- "div",
4085
- {
4086
- className: "lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots",
4087
- "data-step-slots": i,
4088
- children: (selections[i] ?? []).map((item, index) => (
4089
- /* Whole card reopens the wizard AT this step. The inner
4090
- title button provides the keyboard/AT path (its
4091
- activation bubbles here); × stops propagation. */
4092
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner "Edit selection" title button whose activation bubbles to this handler
4093
- /* @__PURE__ */ jsxs9(
4094
- "div",
4095
- {
4096
- className: "lb-mix-match__slot lb-mix-match__slot--filled",
4097
- onClick: () => setPickerOpenAt(i),
4098
- children: [
4099
- item.featuredImage && /* @__PURE__ */ jsx9("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx9(
4100
- "img",
4101
- {
4102
- src: item.featuredImage,
4103
- alt: item.title,
4104
- loading: "lazy"
4105
- }
4106
- ) }),
4107
- /* @__PURE__ */ jsxs9("div", { className: "lb-mix-match__filled-info", children: [
4108
- /* @__PURE__ */ jsx9(
4109
- "button",
4110
- {
4111
- type: "button",
4112
- className: "lb-mix-match__filled-title",
4113
- "aria-label": `Edit selection: ${item.title}`,
4114
- children: item.title
4115
- }
4116
- ),
4117
- item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
4118
- /* @__PURE__ */ jsxs9("span", { className: "lb-mix-match__filled-price", children: [
4119
- item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx9("s", { className: "lb-mix-match__filled-compare", children: formatMoney7(item.compareAtPrice, currency) }),
4120
- /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-price", children: formatMoney7(item.price, currency) }),
4121
- /* @__PURE__ */ jsx9("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
4122
- ] }),
4123
- item.unitPrice && /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
4124
- ] }),
4125
- canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ jsx9(
4126
- "button",
4127
- {
4128
- type: "button",
4129
- className: "lb-mix-match__slot-remove",
4130
- "aria-label": `Remove ${item.title}`,
4131
- onClick: (e) => {
4132
- e.stopPropagation();
4133
- removeSlot(i, index);
4134
- },
4135
- children: /* @__PURE__ */ jsx9(CloseIcon4, {})
4136
- }
4137
- ) : (
4138
- /* Required pick at its floor — quiet state chip instead
4139
- of the ×; removal returns once another slot covers
4140
- the product's minimum (variant swap flow). */
4141
- /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__slot-required", children: "Required" })
4142
- )
4143
- ]
4144
- },
4145
- `${item.productId}:${item.variantId}:${index}`
4146
- )
4147
- ))
4148
- }
4149
- ),
4150
- stepHeadroom2(step.maxQuantity, unitsByStep[i] ?? 0) !== 0 && /* @__PURE__ */ jsxs9(
4106
+ ),
4107
+ /* @__PURE__ */ jsxs9("span", { className: "lb-multi-step__door-copy", children: [
4108
+ /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__add-product-label", children: anyPicks ? "Continue building" : "Choose your products" }),
4109
+ /* @__PURE__ */ jsx9("span", { className: "lb-multi-step__door-sub", children: anyPicks ? `${remainingSteps} ${remainingSteps === 1 ? "step" : "steps"} to go` : `${steps.length} quick ${steps.length === 1 ? "step" : "steps"}` })
4110
+ ] })
4111
+ ]
4112
+ }
4113
+ ),
4114
+ (selections[i] ?? []).length === 0 ? /* @__PURE__ */ jsx9(
4115
+ "section",
4116
+ {
4117
+ className: "lb-multi-step__group",
4118
+ "data-step-group": i,
4119
+ "data-step-mode": "row",
4120
+ children: /* @__PURE__ */ jsxs9(
4151
4121
  "button",
4152
4122
  {
4153
4123
  type: "button",
4154
- className: "lb-mix-match__add-product lb-multi-step__step-trigger",
4155
- "data-step-trigger": i,
4124
+ className: "lb-multi-step__step-row",
4125
+ "data-step-row": i,
4156
4126
  "aria-label": `${step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products"}: ${step.name}`,
4157
4127
  onClick: () => setPickerOpenAt(i),
4158
4128
  children: [
4159
4129
  /* @__PURE__ */ jsx9(
4160
4130
  "span",
4161
4131
  {
4162
- className: "lb-mix-match__add-product-icon",
4132
+ className: "lb-multi-step__step-ix",
4163
4133
  "aria-hidden": "true",
4164
- children: /* @__PURE__ */ jsx9(PlusIcon2, {})
4134
+ children: i + 1
4165
4135
  }
4166
4136
  ),
4167
- /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__add-product-label", children: step.minQuantity === 1 && step.maxQuantity === 1 ? "Choose a product" : "Choose products" })
4137
+ /* @__PURE__ */ jsx9("span", { className: "lb-multi-step__group-name", children: step.name }),
4138
+ /* @__PURE__ */ jsx9(
4139
+ "span",
4140
+ {
4141
+ className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
4142
+ "data-step-count": i,
4143
+ children: `${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`
4144
+ }
4145
+ )
4168
4146
  ]
4169
4147
  }
4170
4148
  )
4171
- ]
4172
- },
4173
- i
4174
- )) }),
4149
+ }
4150
+ ) : /* @__PURE__ */ jsxs9(
4151
+ "section",
4152
+ {
4153
+ className: "lb-multi-step__group",
4154
+ "data-step-group": i,
4155
+ "data-step-mode": "open",
4156
+ children: [
4157
+ /* @__PURE__ */ jsxs9("div", { className: "lb-multi-step__group-heading", children: [
4158
+ /* @__PURE__ */ jsx9("span", { className: "lb-multi-step__group-name", children: step.name }),
4159
+ /* @__PURE__ */ jsx9(
4160
+ "span",
4161
+ {
4162
+ className: `lb-multi-step__group-count${stepSatisfied(i) ? " lb-multi-step__group-count--met" : ""}`,
4163
+ "data-step-count": i,
4164
+ children: `${Math.min(unitsByStep[i] ?? 0, step.minQuantity)} of ${step.minQuantity} added`
4165
+ }
4166
+ )
4167
+ ] }),
4168
+ /* @__PURE__ */ jsx9(
4169
+ "div",
4170
+ {
4171
+ className: "lb-mix-match__slots lb-edge-fade lb-multi-step__group-slots",
4172
+ "data-step-slots": i,
4173
+ children: (selections[i] ?? []).map((item, index) => (
4174
+ /* Whole card reopens the wizard AT this step. The inner
4175
+ title button provides the keyboard/AT path (its
4176
+ activation bubbles here); × stops propagation. */
4177
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- keyboard path is the inner "Edit selection" title button whose activation bubbles to this handler
4178
+ /* @__PURE__ */ jsxs9(
4179
+ "div",
4180
+ {
4181
+ className: "lb-mix-match__slot lb-mix-match__slot--filled",
4182
+ onClick: () => setPickerOpenAt(i),
4183
+ children: [
4184
+ item.featuredImage && /* @__PURE__ */ jsx9("div", { className: "lb-bundle-thumbnail", children: /* @__PURE__ */ jsx9(
4185
+ "img",
4186
+ {
4187
+ src: item.featuredImage,
4188
+ alt: item.title,
4189
+ loading: "lazy"
4190
+ }
4191
+ ) }),
4192
+ /* @__PURE__ */ jsxs9("div", { className: "lb-mix-match__filled-info", children: [
4193
+ /* @__PURE__ */ jsx9(
4194
+ "button",
4195
+ {
4196
+ type: "button",
4197
+ className: "lb-mix-match__filled-title",
4198
+ "aria-label": `Edit selection: ${item.title}`,
4199
+ children: item.title
4200
+ }
4201
+ ),
4202
+ item.variantTitle && item.variantTitle !== "Default Title" && /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__filled-variant", children: item.variantTitle }),
4203
+ /* @__PURE__ */ jsxs9("span", { className: "lb-mix-match__filled-price", children: [
4204
+ item.compareAtPrice !== null && item.compareAtPrice > item.price && /* @__PURE__ */ jsx9("s", { className: "lb-mix-match__filled-compare", children: formatMoney7(item.compareAtPrice, currency) }),
4205
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-price", children: formatMoney7(item.price, currency) }),
4206
+ /* @__PURE__ */ jsx9("span", { className: "lb-bundle-qty-inline", children: `\xD7${item.quantity}` })
4207
+ ] }),
4208
+ item.unitPrice && /* @__PURE__ */ jsx9("span", { className: "lb-bundle-product-unit-price", children: item.unitPrice })
4209
+ ] }),
4210
+ canRemoveItem2(bundle, selections, item) ? /* @__PURE__ */ jsx9(
4211
+ "button",
4212
+ {
4213
+ type: "button",
4214
+ className: "lb-mix-match__slot-remove",
4215
+ "aria-label": `Remove ${item.title}`,
4216
+ onClick: (e) => {
4217
+ e.stopPropagation();
4218
+ removeSlot(i, index);
4219
+ },
4220
+ children: /* @__PURE__ */ jsx9(CloseIcon4, {})
4221
+ }
4222
+ ) : (
4223
+ /* Required pick at its floor — quiet state chip instead
4224
+ of the ×; removal returns once another slot covers
4225
+ the product's minimum (variant swap flow). */
4226
+ /* @__PURE__ */ jsx9("span", { className: "lb-mix-match__slot-required", children: "Required" })
4227
+ )
4228
+ ]
4229
+ },
4230
+ `${item.productId}:${item.variantId}:${index}`
4231
+ )
4232
+ ))
4233
+ }
4234
+ )
4235
+ ]
4236
+ }
4237
+ )
4238
+ ] }, i)) }),
4175
4239
  /* @__PURE__ */ jsx9("div", { className: "lb-bundle-divider" }),
4176
4240
  allSatisfied && /* @__PURE__ */ jsxs9("div", { className: "lb-bundle-summary", "data-pricing-section": true, children: [
4177
4241
  /* @__PURE__ */ jsxs9("div", { className: "lb-bundle-summary__text", children: [
@@ -4350,7 +4414,7 @@ import {
4350
4414
  calculateTierSavings as calculateTierSavings2,
4351
4415
  getActiveTier as getActiveTier2,
4352
4416
  productsForStep as productsForStep3,
4353
- stepHeadroom as stepHeadroom3,
4417
+ stepHeadroom as stepHeadroom2,
4354
4418
  validateQuantity,
4355
4419
  transformImageUrl,
4356
4420
  formatCountdown,
@@ -4411,7 +4475,7 @@ export {
4411
4475
  reportAddToCart2 as reportAddToCart,
4412
4476
  reportImpression2 as reportImpression,
4413
4477
  sanitizeCustomCss,
4414
- stepHeadroom3 as stepHeadroom,
4478
+ stepHeadroom2 as stepHeadroom,
4415
4479
  thumbnailRatioVars,
4416
4480
  transformImageUrl,
4417
4481
  useAnalytics,