codexly-ui 0.10.67 → 0.10.69
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/fesm2022/codexly-ui.mjs +44 -3
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +21 -0
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -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';
|
|
@@ -14453,14 +14457,30 @@ class ClxProductDetailComponent {
|
|
|
14453
14457
|
{ id: 'specs', label: 'Especificaciones' },
|
|
14454
14458
|
{ id: 'description', label: 'Descripción' },
|
|
14455
14459
|
];
|
|
14460
|
+
/** Tracks which product the spec selection was initialized for — the init effect below must run
|
|
14461
|
+
* once per actual product change, not every time initialVariationId() changes. A host app that
|
|
14462
|
+
* syncs its own ?variant= URL param from the (variationChange) output (see codexly-store's
|
|
14463
|
+
* product-detail page) feeds that id back into this same input; without this guard, every spec
|
|
14464
|
+
* click would round-trip through the host and re-trigger initialization, silently overwriting
|
|
14465
|
+
* the visitor's in-progress selection with the just-resolved variation's full spec set. */
|
|
14466
|
+
_initializedForProductId = null;
|
|
14456
14467
|
constructor() {
|
|
14457
14468
|
effect(() => {
|
|
14458
14469
|
const p = this.product();
|
|
14459
14470
|
if (!p?.variations?.length)
|
|
14460
14471
|
return;
|
|
14472
|
+
if (this._initializedForProductId === p.product_id)
|
|
14473
|
+
return;
|
|
14474
|
+
this._initializedForProductId = p.product_id;
|
|
14461
14475
|
const initialId = this.initialVariationId();
|
|
14462
14476
|
const initial = (initialId && p.variations.find(v => v.id === initialId)) || p.variations[0];
|
|
14463
|
-
this.
|
|
14477
|
+
this._initialVariation.set(initial);
|
|
14478
|
+
// Pre-select the full spec combination only when the landing variation has stock — every
|
|
14479
|
+
// other combination stays reachable by changing any one spec. When it's sold out, starting
|
|
14480
|
+
// fully selected would fix both Color and Talla to a combination that can never resolve to
|
|
14481
|
+
// an in-stock variation, hiding every other option (see isOptionAvailable's fallback) with
|
|
14482
|
+
// no selected value left to toggle off — so start empty and let the visitor pick from scratch.
|
|
14483
|
+
this.selectedSpecs.set(initial.in_stock ? { ...initial.specs } : {});
|
|
14464
14484
|
});
|
|
14465
14485
|
effect(() => {
|
|
14466
14486
|
const v = this.activeVariation();
|
|
@@ -14468,12 +14488,22 @@ class ClxProductDetailComponent {
|
|
|
14468
14488
|
this.variationChange.emit(v);
|
|
14469
14489
|
});
|
|
14470
14490
|
}
|
|
14491
|
+
/** With no specs selected (fresh load, or every spec toggled back off) this is the variation
|
|
14492
|
+
* the visitor originally landed on. Otherwise, resolves the variation matching every currently
|
|
14493
|
+
* selected spec — with a partial selection (some spec types still untouched), any variation
|
|
14494
|
+
* whose specs are a superset of the selection counts as a match, since the visitor hasn't
|
|
14495
|
+
* narrowed those other spec types down to one value yet. */
|
|
14471
14496
|
activeVariation = computed(() => {
|
|
14472
14497
|
const p = this.product();
|
|
14473
14498
|
if (!p?.variations?.length)
|
|
14474
14499
|
return null;
|
|
14475
14500
|
const sel = this.selectedSpecs();
|
|
14476
|
-
|
|
14501
|
+
if (Object.keys(sel).length === 0)
|
|
14502
|
+
return this._initialVariation() ?? p.variations[0];
|
|
14503
|
+
const matches = p.variations.filter(v => Object.entries(sel).every(([typeId, optId]) => v.specs[typeId] === optId));
|
|
14504
|
+
// With a partial selection, several variations can match (e.g. only Color chosen) — prefer
|
|
14505
|
+
// one with stock so the price/gallery/CTA reflect a purchasable option by default.
|
|
14506
|
+
return matches.find(v => v.in_stock) ?? matches[0] ?? this._initialVariation() ?? p.variations[0];
|
|
14477
14507
|
}, ...(ngDevMode ? [{ debugName: "activeVariation" }] : /* istanbul ignore next */ []));
|
|
14478
14508
|
finalPrice = computed(() => {
|
|
14479
14509
|
const v = this.activeVariation();
|
|
@@ -14512,8 +14542,19 @@ class ClxProductDetailComponent {
|
|
|
14512
14542
|
}
|
|
14513
14543
|
return variations.some(v => v.specs[specTypeId] === specOptionId && v.in_stock && matchesCrossSelection(v));
|
|
14514
14544
|
}
|
|
14545
|
+
/** Clicking an already-selected option deselects it (toggle) instead of being a no-op — the only
|
|
14546
|
+
* way to escape a narrowed-down selection and see all options again, per the "hide unavailable
|
|
14547
|
+
* options" design: there's no separate disabled state to click through, so toggling off is the
|
|
14548
|
+
* sole path back. Once every spec is toggled off, activeVariation() falls back to the variation
|
|
14549
|
+
* the visitor originally landed on (see _initialVariation). */
|
|
14515
14550
|
selectSpec(specTypeId, specOptionId) {
|
|
14516
|
-
this.selectedSpecs.update(s =>
|
|
14551
|
+
this.selectedSpecs.update(s => {
|
|
14552
|
+
if (s[specTypeId] === specOptionId) {
|
|
14553
|
+
const { [specTypeId]: _removed, ...rest } = s;
|
|
14554
|
+
return rest;
|
|
14555
|
+
}
|
|
14556
|
+
return { ...s, [specTypeId]: specOptionId };
|
|
14557
|
+
});
|
|
14517
14558
|
this._carousel()?.goTo(0);
|
|
14518
14559
|
}
|
|
14519
14560
|
isSpecSelected(specTypeId, specOptionId) {
|