@syntrologie/adapt-product 2.41.2 → 2.42.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/cdn.js +1 -1
- package/dist/{chunk-E5TZSKZV.js → chunk-6DWXPP5X.js} +221 -30
- package/dist/chunk-6DWXPP5X.js.map +7 -0
- package/dist/decision/card.d.ts +24 -2
- package/dist/decision/card.d.ts.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/widgets/ProductCardLit.d.ts.map +1 -1
- package/dist/widgets/VariantPanelLit.d.ts +13 -0
- package/dist/widgets/VariantPanelLit.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-E5TZSKZV.js.map +0 -7
package/dist/cdn.js
CHANGED
|
@@ -21,6 +21,21 @@ function n(n2) {
|
|
|
21
21
|
// ../../sdk-contracts/dist/canvas-context.js
|
|
22
22
|
var canvasRuntimeContext = n("syntrologie:canvas-runtime");
|
|
23
23
|
|
|
24
|
+
// ../../sdk-contracts/dist/detector-events.js
|
|
25
|
+
var DETECTOR_EVENT_NAMES = [
|
|
26
|
+
"ui.hover",
|
|
27
|
+
"ui.idle",
|
|
28
|
+
"ui.hesitate",
|
|
29
|
+
"ui.rage_click",
|
|
30
|
+
"ui.scroll_thrash",
|
|
31
|
+
"ui.focus_bounce"
|
|
32
|
+
];
|
|
33
|
+
var CANONICAL_BUS_EVENT_NAMES = [
|
|
34
|
+
...DETECTOR_EVENT_NAMES,
|
|
35
|
+
"nav.section_viewed",
|
|
36
|
+
"nav.scroll_depth"
|
|
37
|
+
];
|
|
38
|
+
|
|
24
39
|
// ../../sdk-contracts/dist/dive-deeper.js
|
|
25
40
|
var DIVE_DEEPER_EVENT = "syntro:chat:dive-deeper";
|
|
26
41
|
function dispatchDiveDeeper(detail) {
|
|
@@ -43,14 +58,132 @@ function stripMountPlumbing(config) {
|
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
// ../../sdk-contracts/dist/routes.js
|
|
61
|
+
var RESERVED_BYTES = /* @__PURE__ */ new Set([
|
|
62
|
+
33,
|
|
63
|
+
// !
|
|
64
|
+
35,
|
|
65
|
+
// #
|
|
66
|
+
36,
|
|
67
|
+
// $
|
|
68
|
+
38,
|
|
69
|
+
// &
|
|
70
|
+
39,
|
|
71
|
+
// '
|
|
72
|
+
40,
|
|
73
|
+
// (
|
|
74
|
+
41,
|
|
75
|
+
// )
|
|
76
|
+
42,
|
|
77
|
+
// *
|
|
78
|
+
43,
|
|
79
|
+
// +
|
|
80
|
+
44,
|
|
81
|
+
// ,
|
|
82
|
+
47,
|
|
83
|
+
// /
|
|
84
|
+
58,
|
|
85
|
+
// :
|
|
86
|
+
59,
|
|
87
|
+
// ;
|
|
88
|
+
61,
|
|
89
|
+
// =
|
|
90
|
+
63,
|
|
91
|
+
// ?
|
|
92
|
+
64,
|
|
93
|
+
// @
|
|
94
|
+
91,
|
|
95
|
+
// [
|
|
96
|
+
93
|
|
97
|
+
// ]
|
|
98
|
+
]);
|
|
46
99
|
var utf8Decoder = new TextDecoder("utf-8", { fatal: false });
|
|
100
|
+
function decodeUnreservedOnly(input) {
|
|
101
|
+
let out = "";
|
|
102
|
+
let pending2 = [];
|
|
103
|
+
const flushPending = () => {
|
|
104
|
+
if (pending2.length === 0)
|
|
105
|
+
return;
|
|
106
|
+
const bytes = new Uint8Array(pending2);
|
|
107
|
+
out += utf8Decoder.decode(bytes);
|
|
108
|
+
pending2 = [];
|
|
109
|
+
};
|
|
110
|
+
let i2 = 0;
|
|
111
|
+
while (i2 < input.length) {
|
|
112
|
+
const ch = input[i2];
|
|
113
|
+
if (ch === "%" && i2 + 2 < input.length && isHex(input[i2 + 1]) && isHex(input[i2 + 2])) {
|
|
114
|
+
const byte = parseInt(input.slice(i2 + 1, i2 + 3), 16);
|
|
115
|
+
if (RESERVED_BYTES.has(byte)) {
|
|
116
|
+
flushPending();
|
|
117
|
+
out += `%${input.slice(i2 + 1, i2 + 3).toUpperCase()}`;
|
|
118
|
+
i2 += 3;
|
|
119
|
+
} else {
|
|
120
|
+
pending2.push(byte);
|
|
121
|
+
i2 += 3;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
flushPending();
|
|
125
|
+
out += ch;
|
|
126
|
+
i2 += 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
flushPending();
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
function isHex(c2) {
|
|
133
|
+
return c2 >= "0" && c2 <= "9" || c2 >= "a" && c2 <= "f" || c2 >= "A" && c2 <= "F";
|
|
134
|
+
}
|
|
135
|
+
function stripQueryAndHash(s4) {
|
|
136
|
+
const q = s4.indexOf("?");
|
|
137
|
+
if (q !== -1)
|
|
138
|
+
s4 = s4.slice(0, q);
|
|
139
|
+
const h = s4.indexOf("#");
|
|
140
|
+
if (h !== -1)
|
|
141
|
+
s4 = s4.slice(0, h);
|
|
142
|
+
return s4;
|
|
143
|
+
}
|
|
144
|
+
function normalizeRoute(path) {
|
|
145
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
146
|
+
throw new TypeError("normalizeRoute: input must be a non-empty string");
|
|
147
|
+
}
|
|
148
|
+
if (!path.startsWith("/")) {
|
|
149
|
+
throw new TypeError(`normalizeRoute: input must be absolute (start with '/'); got ${JSON.stringify(path)}`);
|
|
150
|
+
}
|
|
151
|
+
let s4 = stripQueryAndHash(path);
|
|
152
|
+
s4 = decodeUnreservedOnly(s4);
|
|
153
|
+
s4 = s4.replace(/\/+/g, "/");
|
|
154
|
+
if (s4.length > 1 && s4.endsWith("/"))
|
|
155
|
+
s4 = s4.slice(0, -1);
|
|
156
|
+
return s4;
|
|
157
|
+
}
|
|
47
158
|
|
|
48
159
|
// ../../sdk-contracts/dist/schemas.js
|
|
49
160
|
import { z } from "zod";
|
|
161
|
+
var NO_CSS_BREAKOUT_PATTERN = /^[^{}]*$/;
|
|
50
162
|
var AnchorIdZ = z.object({
|
|
51
|
-
selector: z.string(),
|
|
52
|
-
|
|
53
|
-
}).
|
|
163
|
+
selector: z.string().regex(NO_CSS_BREAKOUT_PATTERN, {
|
|
164
|
+
message: 'selector must not contain "{" or "}" \u2014 not valid CSS selector syntax, and content:hideBySelector injects this value directly into a <style> element where these characters would break out of the generated rule.'
|
|
165
|
+
}).describe("CSS selector for the target element"),
|
|
166
|
+
route: z.union([z.string(), z.array(z.string())]).superRefine((value, ctx) => {
|
|
167
|
+
for (const route of Array.isArray(value) ? value : [value]) {
|
|
168
|
+
let canonical;
|
|
169
|
+
try {
|
|
170
|
+
canonical = normalizeRoute(route);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
ctx.addIssue({
|
|
173
|
+
code: z.ZodIssueCode.custom,
|
|
174
|
+
message: `route must be an absolute path starting with "/" (got ${JSON.stringify(route)}): ${err instanceof Error ? err.message : String(err)}`
|
|
175
|
+
});
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (canonical !== route) {
|
|
179
|
+
ctx.addIssue({
|
|
180
|
+
code: z.ZodIssueCode.custom,
|
|
181
|
+
message: `route ${JSON.stringify(route)} is not canonical \u2014 use ${JSON.stringify(canonical)} (this must match what the backend's RouteCanonicalityCheck accepts)`
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}).describe("URL path(s) where this element exists")
|
|
186
|
+
}).strict().describe("DOM element target. selector = CSS selector, route = URL path(s) where the element exists.");
|
|
54
187
|
var AuthoringFieldsZ = {
|
|
55
188
|
id: z.string().optional().describe('Stable action identifier (e.g. "act_3db6a14d2ab0").'),
|
|
56
189
|
title: z.string().max(200).optional().describe("Authoring-only: short label shown on the action plan dashboard. Stripped before serving to the runtime SDK."),
|
|
@@ -204,10 +337,10 @@ var EventScopeZ = z.object({
|
|
|
204
337
|
props: z.record(z.union([z.string(), z.number(), z.boolean()])).optional()
|
|
205
338
|
});
|
|
206
339
|
var NotifyZ = z.object({
|
|
207
|
-
title: z.string().optional(),
|
|
208
|
-
body: z.string().optional(),
|
|
209
|
-
icon: z.string().optional()
|
|
210
|
-
}).nullable().optional();
|
|
340
|
+
title: z.string().optional().describe("Notification title"),
|
|
341
|
+
body: z.string().optional().describe("Notification body text"),
|
|
342
|
+
icon: z.string().optional().describe("Notification icon (emoji or URL)")
|
|
343
|
+
}).describe("Optional toast notification shown when this action triggers.").nullable().optional();
|
|
211
344
|
|
|
212
345
|
// src/presets-store.ts
|
|
213
346
|
function presetsWindow() {
|
|
@@ -4245,6 +4378,14 @@ resolvePrice_fn = async function(productId, bind) {
|
|
|
4245
4378
|
};
|
|
4246
4379
|
|
|
4247
4380
|
// src/decision/card.ts
|
|
4381
|
+
var VARIANT_ERROR_COPY = {
|
|
4382
|
+
retryable: "Couldn't load options right now.",
|
|
4383
|
+
terminal: "Options aren't available for this item right now."
|
|
4384
|
+
};
|
|
4385
|
+
var NON_RETRYABLE_VARIANT_ERROR_NAME = "ProductNotFoundError";
|
|
4386
|
+
function isRetryableVariantError(errorName) {
|
|
4387
|
+
return errorName !== NON_RETRYABLE_VARIANT_ERROR_NAME;
|
|
4388
|
+
}
|
|
4248
4389
|
function createInitialCardState(generation = 0) {
|
|
4249
4390
|
return {
|
|
4250
4391
|
generation,
|
|
@@ -4267,18 +4408,23 @@ function selectCardView(state) {
|
|
|
4267
4408
|
mode: "add",
|
|
4268
4409
|
disabled: state.connection !== "connected" || state.commerce !== "available" || state.product.status !== "valid"
|
|
4269
4410
|
};
|
|
4270
|
-
let panel = { status: "hidden", payload: null, error: null };
|
|
4411
|
+
let panel = { status: "hidden", payload: null, error: null, retryable: false };
|
|
4271
4412
|
if (state.face === "back") {
|
|
4272
4413
|
switch (state.variants.status) {
|
|
4273
4414
|
case "ready":
|
|
4274
|
-
panel = { status: "ready", payload: state.variants.payload, error: null };
|
|
4415
|
+
panel = { status: "ready", payload: state.variants.payload, error: null, retryable: false };
|
|
4275
4416
|
break;
|
|
4276
4417
|
case "error":
|
|
4277
|
-
panel = {
|
|
4418
|
+
panel = {
|
|
4419
|
+
status: "error",
|
|
4420
|
+
payload: null,
|
|
4421
|
+
error: state.variants.retryable ? VARIANT_ERROR_COPY.retryable : VARIANT_ERROR_COPY.terminal,
|
|
4422
|
+
retryable: state.variants.retryable
|
|
4423
|
+
};
|
|
4278
4424
|
break;
|
|
4279
4425
|
case "idle":
|
|
4280
4426
|
case "loading":
|
|
4281
|
-
panel = { status: "loading", payload: null, error: null };
|
|
4427
|
+
panel = { status: "loading", payload: null, error: null, retryable: false };
|
|
4282
4428
|
break;
|
|
4283
4429
|
}
|
|
4284
4430
|
}
|
|
@@ -4297,7 +4443,7 @@ function replaceProps(state, event) {
|
|
|
4297
4443
|
const sameProduct = event.valid && event.productId !== null && state.product.status === "valid" && state.product.id === event.productId;
|
|
4298
4444
|
if (sameProduct && event.productId !== null) {
|
|
4299
4445
|
const effects2 = [{ type: "bind-product", productId: event.productId }];
|
|
4300
|
-
if (state.variants.status === "idle") {
|
|
4446
|
+
if (event.commerceCapable && state.variants.status === "idle") {
|
|
4301
4447
|
effects2.push({
|
|
4302
4448
|
type: "lookup-variants",
|
|
4303
4449
|
generation: state.generation,
|
|
@@ -4319,15 +4465,15 @@ function replaceProps(state, event) {
|
|
|
4319
4465
|
effects
|
|
4320
4466
|
};
|
|
4321
4467
|
}
|
|
4322
|
-
effects.push(
|
|
4323
|
-
|
|
4324
|
-
{ type: "lookup-variants", generation, productId: event.productId }
|
|
4325
|
-
|
|
4326
|
-
);
|
|
4468
|
+
effects.push({ type: "bind-product", productId: event.productId });
|
|
4469
|
+
if (event.commerceCapable) {
|
|
4470
|
+
effects.push({ type: "lookup-variants", generation, productId: event.productId });
|
|
4471
|
+
}
|
|
4472
|
+
effects.push({ type: "report-render-health" });
|
|
4327
4473
|
return {
|
|
4328
4474
|
state: {
|
|
4329
4475
|
...next,
|
|
4330
|
-
product: { status: "valid", id: event.productId }
|
|
4476
|
+
product: { status: "valid", id: event.productId, commerceCapable: event.commerceCapable }
|
|
4331
4477
|
},
|
|
4332
4478
|
effects
|
|
4333
4479
|
};
|
|
@@ -4336,7 +4482,12 @@ function publish(name, props) {
|
|
|
4336
4482
|
return { type: "publish-event", name, props };
|
|
4337
4483
|
}
|
|
4338
4484
|
function activatePrimary(state, event) {
|
|
4339
|
-
if (state.connection !== "connected" || state.commerce !== "available" || state.product.status !== "valid" ||
|
|
4485
|
+
if (state.connection !== "connected" || state.commerce !== "available" || state.product.status !== "valid" || // Defense in depth: the widget only wires this event to an
|
|
4486
|
+
// actionId==='add_to_cart' CTA click (a non-commerce/booking product's
|
|
4487
|
+
// CTA is a plain navigating <a>, never dispatched here) — but the state
|
|
4488
|
+
// machine itself must also refuse to start the Woo/Shopify variant-
|
|
4489
|
+
// lookup flow for a product that has none.
|
|
4490
|
+
!state.product.commerceCapable || state.face !== "front") {
|
|
4340
4491
|
return unchanged2(state);
|
|
4341
4492
|
}
|
|
4342
4493
|
const productId = state.product.id;
|
|
@@ -4487,7 +4638,11 @@ function transitionCard(state, event) {
|
|
|
4487
4638
|
});
|
|
4488
4639
|
const next = {
|
|
4489
4640
|
...state,
|
|
4490
|
-
variants: {
|
|
4641
|
+
variants: {
|
|
4642
|
+
status: "error",
|
|
4643
|
+
message: event.message,
|
|
4644
|
+
retryable: isRetryableVariantError(event.errorName)
|
|
4645
|
+
}
|
|
4491
4646
|
};
|
|
4492
4647
|
if (state.activation.status !== "pending") {
|
|
4493
4648
|
return { state: next, effects: [failureEffect] };
|
|
@@ -4521,7 +4676,10 @@ function transitionCard(state, event) {
|
|
|
4521
4676
|
case "add-failed":
|
|
4522
4677
|
return applyAddResult(state, event);
|
|
4523
4678
|
case "retry-activated":
|
|
4524
|
-
if (state.product.status !== "valid" || state.commerce !== "available" || state.variants.status !== "error"
|
|
4679
|
+
if (state.product.status !== "valid" || state.commerce !== "available" || state.variants.status !== "error" || // The panel never OFFERS a retry affordance when the failure isn't
|
|
4680
|
+
// retryable (see selectCardView), but a stale/duplicate dispatch of
|
|
4681
|
+
// this event must still be a no-op — it can never succeed.
|
|
4682
|
+
!state.variants.retryable) {
|
|
4525
4683
|
return unchanged2(state);
|
|
4526
4684
|
}
|
|
4527
4685
|
return {
|
|
@@ -4568,7 +4726,12 @@ function transitionCard(state, event) {
|
|
|
4568
4726
|
state: { ...state, generation, connection: "connected" },
|
|
4569
4727
|
effects: state.product.status === "valid" && state.commerce === "available" ? [
|
|
4570
4728
|
{ type: "bind-product", productId: state.product.id },
|
|
4571
|
-
|
|
4729
|
+
// Same commerce gate as replaceProps — a booking-fulfilment
|
|
4730
|
+
// product never re-fires the Woo/Shopify variant lookup,
|
|
4731
|
+
// including on the reconnect prefetch.
|
|
4732
|
+
...state.product.commerceCapable ? [
|
|
4733
|
+
{ type: "lookup-variants", generation, productId: state.product.id }
|
|
4734
|
+
] : [],
|
|
4572
4735
|
{ type: "report-render-health" }
|
|
4573
4736
|
] : []
|
|
4574
4737
|
};
|
|
@@ -5238,7 +5401,17 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement7 {
|
|
|
5238
5401
|
* used as the fallback when the selected variant carries no featured_image. */
|
|
5239
5402
|
this.productImage = null;
|
|
5240
5403
|
this.state = "idle";
|
|
5404
|
+
/** Already sanitized, visitor-safe copy by the time it reaches this
|
|
5405
|
+
* component — the decision core (`card.ts`'s `selectCardView`) NEVER
|
|
5406
|
+
* forwards the raw platform error text (which may name an internal
|
|
5407
|
+
* slug/handle, e.g. `WooCommerce product not found for slug "botox"`).
|
|
5408
|
+
* This component's only job is to render whatever generic string it's
|
|
5409
|
+
* given; it must never be handed a raw message to begin with. */
|
|
5241
5410
|
this.error = null;
|
|
5411
|
+
/** Whether "Try again" is offered — false for a structurally dead-end
|
|
5412
|
+
* failure (retrying the identical query can never succeed) so the panel
|
|
5413
|
+
* never invites a retry that's already known to be pointless. */
|
|
5414
|
+
this.retryable = true;
|
|
5242
5415
|
/** @internal */
|
|
5243
5416
|
this._selection = {};
|
|
5244
5417
|
/** @internal */
|
|
@@ -5332,8 +5505,10 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement7 {
|
|
|
5332
5505
|
if (this.state === "error") {
|
|
5333
5506
|
return html7`
|
|
5334
5507
|
<div class="svp-error-block" data-error-block>
|
|
5335
|
-
<div
|
|
5336
|
-
|
|
5508
|
+
<div>${this.error ?? "Couldn't load options."}</div>
|
|
5509
|
+
${this.retryable ? html7`<button class="svp-retry-btn" data-retry-button @click=${this._onRetry}>
|
|
5510
|
+
Try again
|
|
5511
|
+
</button>` : nothing3}
|
|
5337
5512
|
</div>
|
|
5338
5513
|
`;
|
|
5339
5514
|
}
|
|
@@ -5580,6 +5755,7 @@ _VariantPanelLit.properties = {
|
|
|
5580
5755
|
productImage: { attribute: false },
|
|
5581
5756
|
state: { type: String },
|
|
5582
5757
|
error: { type: String },
|
|
5758
|
+
retryable: { type: Boolean },
|
|
5583
5759
|
_selection: { state: true },
|
|
5584
5760
|
_touched: { state: true },
|
|
5585
5761
|
_expandedAxes: { state: true },
|
|
@@ -5818,6 +5994,7 @@ var ProductCardLit = class extends LitElement8 {
|
|
|
5818
5994
|
.productImage=${product.image ? { src: product.image.src, alt: product.image.alt } : null}
|
|
5819
5995
|
.state=${view.panel.status === "error" ? "error" : view.panel.status === "ready" ? "idle" : "loading"}
|
|
5820
5996
|
.error=${view.panel.error}
|
|
5997
|
+
.retryable=${view.panel.retryable}
|
|
5821
5998
|
@variant-panel-back=${this._onVariantBack}
|
|
5822
5999
|
@variant-panel-add=${this._onVariantAdd}
|
|
5823
6000
|
@variant-panel-retry=${this._onVariantRetry}
|
|
@@ -5958,7 +6135,14 @@ readProductObservation_fn = function() {
|
|
|
5958
6135
|
const rawProductId = this.props?.product?.id;
|
|
5959
6136
|
return {
|
|
5960
6137
|
productId: parsed?.success ? parsed.data.product.id : typeof rawProductId === "string" ? rawProductId : null,
|
|
5961
|
-
valid: parsed?.success === true
|
|
6138
|
+
valid: parsed?.success === true,
|
|
6139
|
+
// Does this product have a REAL Add-to-cart action? A booking-
|
|
6140
|
+
// fulfilment product (server-hydrated with a single "Book a consult"
|
|
6141
|
+
// href CTA — see product_hydration.build_product_from_hit) has none,
|
|
6142
|
+
// and its platform variant-lookup endpoint has nothing to find — the
|
|
6143
|
+
// decision core (card.ts) uses this to skip the Woo/Shopify variant
|
|
6144
|
+
// prefetch entirely for it, never just to disable a button.
|
|
6145
|
+
commerceCapable: parsed?.success === true && parsed.data.product.ctas.some((cta) => cta.actionId === "add_to_cart")
|
|
5962
6146
|
};
|
|
5963
6147
|
};
|
|
5964
6148
|
syncDecisionInputsBeforeIntent_fn = function() {
|
|
@@ -5968,7 +6152,7 @@ syncDecisionInputsBeforeIntent_fn = function() {
|
|
|
5968
6152
|
});
|
|
5969
6153
|
const observation = __privateMethod(this, _ProductCardLit_instances, readProductObservation_fn).call(this);
|
|
5970
6154
|
const product = this._decisionState.product;
|
|
5971
|
-
const isCurrent = observation.valid === (product.status === "valid") && observation.productId === product.id;
|
|
6155
|
+
const isCurrent = observation.valid === (product.status === "valid") && observation.productId === product.id && (product.status !== "valid" || observation.commerceCapable === product.commerceCapable);
|
|
5972
6156
|
if (!isCurrent) __privateMethod(this, _ProductCardLit_instances, dispatchCard_fn).call(this, { type: "props-replaced", ...observation });
|
|
5973
6157
|
};
|
|
5974
6158
|
ProductCardLit.properties = {
|
|
@@ -6395,9 +6579,16 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
6395
6579
|
style=${styleMap(ctaStyles)}
|
|
6396
6580
|
@click=${disabled2 ? (e2) => {
|
|
6397
6581
|
e2.preventDefault();
|
|
6398
|
-
} :
|
|
6399
|
-
|
|
6400
|
-
|
|
6582
|
+
} : (
|
|
6583
|
+
// The commerce (Add-to-cart / open-picker) intent wires ONLY to
|
|
6584
|
+
// an actual add_to_cart CTA. A plain navigating CTA — e.g. a
|
|
6585
|
+
// booking-fulfilment product's "Book a consult" href, which
|
|
6586
|
+
// sits at i===0 too — must fall through to its own <a href>
|
|
6587
|
+
// and never enter the Woo/Shopify variant-lookup flow.
|
|
6588
|
+
i2 === 0 && c2.actionId === "add_to_cart" && onPrimaryCtaClick ? onPrimaryCtaClick : c2.actionId === "add_to_cart" ? (e2) => {
|
|
6589
|
+
e2.preventDefault();
|
|
6590
|
+
} : void 0
|
|
6591
|
+
)}
|
|
6401
6592
|
>${// Secondary "Product Page" link gets a trailing chevron (panel's
|
|
6402
6593
|
// quiet-secondary affordance) unless the author already added one.
|
|
6403
6594
|
i2 !== 0 && !/[›>→]\s*$/.test(ctaLabel) ? `${ctaLabel} \u203A` : ctaLabel}</a
|
|
@@ -11736,4 +11927,4 @@ export {
|
|
|
11736
11927
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
11737
11928
|
*)
|
|
11738
11929
|
*/
|
|
11739
|
-
//# sourceMappingURL=chunk-
|
|
11930
|
+
//# sourceMappingURL=chunk-6DWXPP5X.js.map
|