codexly-ui 0.10.67 → 0.10.68

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.
@@ -14444,7 +14444,11 @@ class ClxProductDetailComponent {
14444
14444
  _carousel = viewChild(ClxCarouselComponent, ...(ngDevMode ? [{ debugName: "_carousel" }] : /* istanbul ignore next */ []));
14445
14445
  quantity = signal(1, ...(ngDevMode ? [{ debugName: "quantity" }] : /* istanbul ignore next */ []));
14446
14446
  activeTab = signal('general', ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
14447
+ /** Only holds specs the visitor has explicitly clicked — starts empty, not pre-filled with the
14448
+ * initial variation's specs, so a spec option can be toggled off (click again to deselect)
14449
+ * without fighting a "fully selected" starting state that never lets go of its last value. */
14447
14450
  selectedSpecs = signal({}, ...(ngDevMode ? [{ debugName: "selectedSpecs" }] : /* istanbul ignore next */ []));
14451
+ _initialVariation = signal(null, ...(ngDevMode ? [{ debugName: "_initialVariation" }] : /* istanbul ignore next */ []));
14448
14452
  /** Same card treatment as clx-product (bg-clx-surface + shadow-sm) — keeps the gallery/info
14449
14453
  * panels visually consistent with the rest of the e-commerce card set. */
14450
14454
  _panelClass = 'bg-clx-surface rounded-2xl shadow-sm p-4';
@@ -14460,7 +14464,13 @@ class ClxProductDetailComponent {
14460
14464
  return;
14461
14465
  const initialId = this.initialVariationId();
14462
14466
  const initial = (initialId && p.variations.find(v => v.id === initialId)) || p.variations[0];
14463
- this.selectedSpecs.set({ ...initial.specs });
14467
+ this._initialVariation.set(initial);
14468
+ // Pre-select the full spec combination only when the landing variation has stock — every
14469
+ // other combination stays reachable by changing any one spec. When it's sold out, starting
14470
+ // fully selected would fix both Color and Talla to a combination that can never resolve to
14471
+ // an in-stock variation, hiding every other option (see isOptionAvailable's fallback) with
14472
+ // no selected value left to toggle off — so start empty and let the visitor pick from scratch.
14473
+ this.selectedSpecs.set(initial.in_stock ? { ...initial.specs } : {});
14464
14474
  });
14465
14475
  effect(() => {
14466
14476
  const v = this.activeVariation();
@@ -14468,12 +14478,22 @@ class ClxProductDetailComponent {
14468
14478
  this.variationChange.emit(v);
14469
14479
  });
14470
14480
  }
14481
+ /** With no specs selected (fresh load, or every spec toggled back off) this is the variation
14482
+ * the visitor originally landed on. Otherwise, resolves the variation matching every currently
14483
+ * selected spec — with a partial selection (some spec types still untouched), any variation
14484
+ * whose specs are a superset of the selection counts as a match, since the visitor hasn't
14485
+ * narrowed those other spec types down to one value yet. */
14471
14486
  activeVariation = computed(() => {
14472
14487
  const p = this.product();
14473
14488
  if (!p?.variations?.length)
14474
14489
  return null;
14475
14490
  const sel = this.selectedSpecs();
14476
- return p.variations.find(v => Object.entries(v.specs).every(([typeId, optId]) => sel[typeId] === optId)) ?? p.variations[0];
14491
+ if (Object.keys(sel).length === 0)
14492
+ return this._initialVariation() ?? p.variations[0];
14493
+ const matches = p.variations.filter(v => Object.entries(sel).every(([typeId, optId]) => v.specs[typeId] === optId));
14494
+ // With a partial selection, several variations can match (e.g. only Color chosen) — prefer
14495
+ // one with stock so the price/gallery/CTA reflect a purchasable option by default.
14496
+ return matches.find(v => v.in_stock) ?? matches[0] ?? this._initialVariation() ?? p.variations[0];
14477
14497
  }, ...(ngDevMode ? [{ debugName: "activeVariation" }] : /* istanbul ignore next */ []));
14478
14498
  finalPrice = computed(() => {
14479
14499
  const v = this.activeVariation();
@@ -14512,8 +14532,19 @@ class ClxProductDetailComponent {
14512
14532
  }
14513
14533
  return variations.some(v => v.specs[specTypeId] === specOptionId && v.in_stock && matchesCrossSelection(v));
14514
14534
  }
14535
+ /** Clicking an already-selected option deselects it (toggle) instead of being a no-op — the only
14536
+ * way to escape a narrowed-down selection and see all options again, per the "hide unavailable
14537
+ * options" design: there's no separate disabled state to click through, so toggling off is the
14538
+ * sole path back. Once every spec is toggled off, activeVariation() falls back to the variation
14539
+ * the visitor originally landed on (see _initialVariation). */
14515
14540
  selectSpec(specTypeId, specOptionId) {
14516
- this.selectedSpecs.update(s => ({ ...s, [specTypeId]: specOptionId }));
14541
+ this.selectedSpecs.update(s => {
14542
+ if (s[specTypeId] === specOptionId) {
14543
+ const { [specTypeId]: _removed, ...rest } = s;
14544
+ return rest;
14545
+ }
14546
+ return { ...s, [specTypeId]: specOptionId };
14547
+ });
14517
14548
  this._carousel()?.goTo(0);
14518
14549
  }
14519
14550
  isSpecSelected(specTypeId, specOptionId) {