@lime-bundles/widget 2.4.1 → 2.5.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.cjs +817 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +736 -19
- package/dist/index.js.map +1 -1
- package/dist/lime-bundle.global.js +337 -20
- package/dist/lime-bundle.global.js.map +1 -1
- package/docs/css-variables.md +3 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -26,16 +26,393 @@ __export(index_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
|
|
28
28
|
// src/lime-bundle.ts
|
|
29
|
-
var
|
|
29
|
+
var import_core7 = require("@lime-bundles/core");
|
|
30
30
|
|
|
31
31
|
// src/renderers/fixed.ts
|
|
32
|
-
var
|
|
32
|
+
var import_core5 = require("@lime-bundles/core");
|
|
33
33
|
|
|
34
|
-
// src/
|
|
34
|
+
// src/dropdown/bind-dropdown.ts
|
|
35
35
|
var import_core = require("@lime-bundles/core");
|
|
36
|
+
var { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } = import_core.dropdown;
|
|
37
|
+
var ITEM_HEIGHT_PX = 32;
|
|
38
|
+
var LIST_PAD_Y = 8;
|
|
39
|
+
var MAX_VISIBLE_ITEMS = 8;
|
|
40
|
+
var openInstances = [];
|
|
41
|
+
function closeOutsideEvent(event) {
|
|
42
|
+
const path = event.composedPath();
|
|
43
|
+
for (let i = openInstances.length - 1; i >= 0; i--) {
|
|
44
|
+
const inst = openInstances[i];
|
|
45
|
+
if (!path.includes(inst.shell) && !path.includes(inst.listbox)) {
|
|
46
|
+
inst.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function onDocResize() {
|
|
51
|
+
for (let i = openInstances.length - 1; i >= 0; i--) openInstances[i].close();
|
|
52
|
+
}
|
|
53
|
+
var docListenersAttached = false;
|
|
54
|
+
function attachDocumentListeners() {
|
|
55
|
+
if (docListenersAttached) return;
|
|
56
|
+
document.addEventListener("pointerdown", closeOutsideEvent, true);
|
|
57
|
+
window.addEventListener("scroll", closeOutsideEvent, true);
|
|
58
|
+
window.addEventListener("resize", onDocResize);
|
|
59
|
+
docListenersAttached = true;
|
|
60
|
+
}
|
|
61
|
+
function detachDocumentListeners() {
|
|
62
|
+
if (!docListenersAttached || openInstances.length > 0) return;
|
|
63
|
+
document.removeEventListener("pointerdown", closeOutsideEvent, true);
|
|
64
|
+
window.removeEventListener("scroll", closeOutsideEvent, true);
|
|
65
|
+
window.removeEventListener("resize", onDocResize);
|
|
66
|
+
docListenersAttached = false;
|
|
67
|
+
}
|
|
68
|
+
function readOptions(select) {
|
|
69
|
+
const out = [];
|
|
70
|
+
for (let i = 0; i < select.options.length; i++) {
|
|
71
|
+
const o = select.options[i];
|
|
72
|
+
out.push({ disabled: o.disabled, label: o.textContent || o.value });
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function firstEnabled(opts) {
|
|
77
|
+
for (let i = 0; i < opts.length; i++) if (!opts[i].disabled) return i;
|
|
78
|
+
return -1;
|
|
79
|
+
}
|
|
80
|
+
var VARIANT_SELECT_CLASSES = [
|
|
81
|
+
"lb-bundle-variant-select",
|
|
82
|
+
"lb-mix-match__variant-select"
|
|
83
|
+
];
|
|
84
|
+
var BIND_SELECTOR = VARIANT_SELECT_CLASSES.map(
|
|
85
|
+
(c) => `select.${c}:not(.lb-dropdown-state)`
|
|
86
|
+
).join(", ");
|
|
87
|
+
function bindDropdown(select) {
|
|
88
|
+
const slot = select;
|
|
89
|
+
if (select.classList.contains("lb-dropdown-state")) {
|
|
90
|
+
return slot.__lbDropdownInstance ?? null;
|
|
91
|
+
}
|
|
92
|
+
const doc = select.ownerDocument;
|
|
93
|
+
const rootNode = select.getRootNode();
|
|
94
|
+
const labelText = select.getAttribute("aria-label") ?? "";
|
|
95
|
+
const idBase = `lb-dd-${Math.random().toString(36).slice(2, 9)}`;
|
|
96
|
+
select.classList.add("lb-dropdown-state");
|
|
97
|
+
select.setAttribute("aria-hidden", "true");
|
|
98
|
+
select.setAttribute("tabindex", "-1");
|
|
99
|
+
const shell = doc.createElement("div");
|
|
100
|
+
shell.className = "lb-dropdown";
|
|
101
|
+
shell.setAttribute("data-lb-dropdown", "");
|
|
102
|
+
const trigger = doc.createElement("button");
|
|
103
|
+
trigger.type = "button";
|
|
104
|
+
trigger.className = "lb-dropdown-trigger";
|
|
105
|
+
trigger.setAttribute("role", "combobox");
|
|
106
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
107
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
108
|
+
const listboxId = `${idBase}-listbox`;
|
|
109
|
+
trigger.setAttribute("aria-controls", listboxId);
|
|
110
|
+
if (labelText) trigger.setAttribute("aria-label", labelText);
|
|
111
|
+
const triggerLabel = doc.createElement("span");
|
|
112
|
+
triggerLabel.className = "lb-dropdown-trigger-value";
|
|
113
|
+
const chevron = doc.createElement("span");
|
|
114
|
+
chevron.className = "lb-dropdown-chevron";
|
|
115
|
+
chevron.setAttribute("aria-hidden", "true");
|
|
116
|
+
trigger.appendChild(triggerLabel);
|
|
117
|
+
trigger.appendChild(chevron);
|
|
118
|
+
const listbox = doc.createElement("ul");
|
|
119
|
+
listbox.id = listboxId;
|
|
120
|
+
listbox.className = "lb-dropdown-listbox";
|
|
121
|
+
listbox.setAttribute("role", "listbox");
|
|
122
|
+
if (labelText) listbox.setAttribute("aria-label", labelText);
|
|
123
|
+
listbox.hidden = true;
|
|
124
|
+
shell.appendChild(trigger);
|
|
125
|
+
select.parentNode?.insertBefore(shell, select.nextSibling);
|
|
126
|
+
const modalOverlay = select.closest("[data-modal-overlay]");
|
|
127
|
+
if (modalOverlay) {
|
|
128
|
+
modalOverlay.appendChild(listbox);
|
|
129
|
+
listbox.setAttribute("data-lb-dropdown-portal", "");
|
|
130
|
+
} else {
|
|
131
|
+
shell.appendChild(listbox);
|
|
132
|
+
}
|
|
133
|
+
let isOpen = false;
|
|
134
|
+
let activeIndex = -1;
|
|
135
|
+
let typeAhead = emptyTypeAheadState();
|
|
136
|
+
let optionEls = [];
|
|
137
|
+
let instance;
|
|
138
|
+
function syncFromSelect() {
|
|
139
|
+
const opts = readOptions(select);
|
|
140
|
+
const idx = select.selectedIndex;
|
|
141
|
+
triggerLabel.textContent = idx >= 0 && opts[idx] ? opts[idx].label : "";
|
|
142
|
+
while (listbox.firstChild) listbox.removeChild(listbox.firstChild);
|
|
143
|
+
optionEls = [];
|
|
144
|
+
for (let i = 0; i < opts.length; i++) {
|
|
145
|
+
const li = doc.createElement("li");
|
|
146
|
+
li.id = `${idBase}-opt-${i}`;
|
|
147
|
+
li.className = "lb-dropdown-option";
|
|
148
|
+
li.setAttribute("role", "option");
|
|
149
|
+
li.setAttribute("aria-selected", i === idx ? "true" : "false");
|
|
150
|
+
if (opts[i].disabled) li.setAttribute("aria-disabled", "true");
|
|
151
|
+
li.setAttribute("data-value", select.options[i].value);
|
|
152
|
+
li.setAttribute("data-index", String(i));
|
|
153
|
+
li.textContent = opts[i].label;
|
|
154
|
+
listbox.appendChild(li);
|
|
155
|
+
optionEls.push(li);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function setActive(newIndex) {
|
|
159
|
+
if (activeIndex >= 0 && optionEls[activeIndex]) {
|
|
160
|
+
optionEls[activeIndex].classList.remove("is-active");
|
|
161
|
+
}
|
|
162
|
+
activeIndex = newIndex;
|
|
163
|
+
if (newIndex >= 0 && optionEls[newIndex]) {
|
|
164
|
+
const li = optionEls[newIndex];
|
|
165
|
+
li.classList.add("is-active");
|
|
166
|
+
trigger.setAttribute("aria-activedescendant", li.id);
|
|
167
|
+
const liTop = li.offsetTop;
|
|
168
|
+
const liBottom = liTop + li.offsetHeight;
|
|
169
|
+
const visTop = listbox.scrollTop;
|
|
170
|
+
const visBottom = visTop + listbox.clientHeight;
|
|
171
|
+
if (liTop < visTop) {
|
|
172
|
+
listbox.scrollTop = liTop;
|
|
173
|
+
} else if (liBottom > visBottom) {
|
|
174
|
+
listbox.scrollTop = liBottom - listbox.clientHeight;
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
trigger.setAttribute("aria-activedescendant", "");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function position() {
|
|
181
|
+
const rect = trigger.getBoundingClientRect();
|
|
182
|
+
if (rect.width === 0) return false;
|
|
183
|
+
const visibleCount = Math.min(optionEls.length || 1, MAX_VISIBLE_ITEMS);
|
|
184
|
+
const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;
|
|
185
|
+
const result = computePosition({
|
|
186
|
+
trigger: {
|
|
187
|
+
top: rect.top,
|
|
188
|
+
bottom: rect.bottom,
|
|
189
|
+
left: rect.left,
|
|
190
|
+
width: rect.width
|
|
191
|
+
},
|
|
192
|
+
viewportHeight: window.innerHeight,
|
|
193
|
+
desiredHeight
|
|
194
|
+
});
|
|
195
|
+
listbox.setAttribute("data-placement", result.placement);
|
|
196
|
+
listbox.style.maxHeight = `${result.maxHeight}px`;
|
|
197
|
+
if (listbox.hasAttribute("data-lb-dropdown-portal")) {
|
|
198
|
+
listbox.style.top = `${result.offsetTop}px`;
|
|
199
|
+
listbox.style.left = `${result.offsetLeft}px`;
|
|
200
|
+
listbox.style.width = `${result.width}px`;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
function open() {
|
|
205
|
+
if (isOpen) return;
|
|
206
|
+
for (let i = openInstances.length - 1; i >= 0; i--) {
|
|
207
|
+
if (openInstances[i] !== instance) openInstances[i].close();
|
|
208
|
+
}
|
|
209
|
+
isOpen = true;
|
|
210
|
+
listbox.hidden = false;
|
|
211
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
212
|
+
if (!position()) {
|
|
213
|
+
requestAnimationFrame(() => position());
|
|
214
|
+
}
|
|
215
|
+
const opts = readOptions(select);
|
|
216
|
+
const selIdx = select.selectedIndex;
|
|
217
|
+
if (selIdx >= 0 && opts[selIdx] && !opts[selIdx].disabled) {
|
|
218
|
+
setActive(selIdx);
|
|
219
|
+
} else {
|
|
220
|
+
setActive(firstEnabled(opts));
|
|
221
|
+
}
|
|
222
|
+
openInstances.push(instance);
|
|
223
|
+
if (openInstances.length === 1) attachDocumentListeners();
|
|
224
|
+
}
|
|
225
|
+
function close(restoreFocus) {
|
|
226
|
+
if (!isOpen) return;
|
|
227
|
+
isOpen = false;
|
|
228
|
+
listbox.hidden = true;
|
|
229
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
230
|
+
trigger.setAttribute("aria-activedescendant", "");
|
|
231
|
+
if (activeIndex >= 0 && optionEls[activeIndex]) {
|
|
232
|
+
optionEls[activeIndex].classList.remove("is-active");
|
|
233
|
+
}
|
|
234
|
+
activeIndex = -1;
|
|
235
|
+
const idx = openInstances.indexOf(instance);
|
|
236
|
+
if (idx >= 0) openInstances.splice(idx, 1);
|
|
237
|
+
if (openInstances.length === 0) detachDocumentListeners();
|
|
238
|
+
if (restoreFocus) trigger.focus();
|
|
239
|
+
}
|
|
240
|
+
function commit(index) {
|
|
241
|
+
const opt = select.options[index];
|
|
242
|
+
if (!opt || opt.disabled) return;
|
|
243
|
+
if (select.value !== opt.value) {
|
|
244
|
+
select.value = opt.value;
|
|
245
|
+
const event = new Event("change", { bubbles: true });
|
|
246
|
+
select.dispatchEvent(event);
|
|
247
|
+
}
|
|
248
|
+
syncFromSelect();
|
|
249
|
+
close(true);
|
|
250
|
+
}
|
|
251
|
+
function applyAction(action) {
|
|
252
|
+
switch (action.type) {
|
|
253
|
+
case "open":
|
|
254
|
+
open();
|
|
255
|
+
if (action.activeIndex >= 0) setActive(action.activeIndex);
|
|
256
|
+
return;
|
|
257
|
+
case "close":
|
|
258
|
+
close(action.restoreFocus);
|
|
259
|
+
return;
|
|
260
|
+
case "move-active":
|
|
261
|
+
setActive(action.activeIndex);
|
|
262
|
+
return;
|
|
263
|
+
case "commit":
|
|
264
|
+
commit(action.index);
|
|
265
|
+
return;
|
|
266
|
+
case "type-ahead": {
|
|
267
|
+
const opts = readOptions(select);
|
|
268
|
+
const result = pushTypeAheadChar(
|
|
269
|
+
typeAhead,
|
|
270
|
+
action.char,
|
|
271
|
+
Date.now(),
|
|
272
|
+
opts
|
|
273
|
+
);
|
|
274
|
+
typeAhead = result.newState;
|
|
275
|
+
if (result.matchedIndex !== null) {
|
|
276
|
+
if (!isOpen) open();
|
|
277
|
+
setActive(result.matchedIndex);
|
|
278
|
+
}
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
case "passthrough":
|
|
282
|
+
return;
|
|
283
|
+
default: {
|
|
284
|
+
const _exhaustive = action;
|
|
285
|
+
void _exhaustive;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function onKeydown(event) {
|
|
290
|
+
const opts = readOptions(select);
|
|
291
|
+
const action = handleKey(
|
|
292
|
+
{
|
|
293
|
+
key: event.key,
|
|
294
|
+
ctrlKey: event.ctrlKey,
|
|
295
|
+
metaKey: event.metaKey,
|
|
296
|
+
altKey: event.altKey,
|
|
297
|
+
shiftKey: event.shiftKey
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
isOpen,
|
|
301
|
+
activeIndex,
|
|
302
|
+
selectedIndex: select.selectedIndex,
|
|
303
|
+
options: opts
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
if (action.preventDefault) event.preventDefault();
|
|
307
|
+
applyAction(action);
|
|
308
|
+
}
|
|
309
|
+
function onTriggerClick(event) {
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
if (isOpen) close(false);
|
|
312
|
+
else open();
|
|
313
|
+
}
|
|
314
|
+
function onListboxClick(event) {
|
|
315
|
+
let target = event.target;
|
|
316
|
+
while (target && target !== listbox) {
|
|
317
|
+
if (target.classList?.contains("lb-dropdown-option")) {
|
|
318
|
+
const idx = parseInt(target.getAttribute("data-index") ?? "", 10);
|
|
319
|
+
if (!Number.isNaN(idx)) {
|
|
320
|
+
commit(idx);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
target = target.parentElement;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function onListboxMousemove(event) {
|
|
328
|
+
let target = event.target;
|
|
329
|
+
while (target && target !== listbox) {
|
|
330
|
+
if (target.classList?.contains("lb-dropdown-option")) {
|
|
331
|
+
if (target.getAttribute("aria-disabled") === "true") return;
|
|
332
|
+
const idx = parseInt(target.getAttribute("data-index") ?? "", 10);
|
|
333
|
+
if (!Number.isNaN(idx) && idx !== activeIndex) setActive(idx);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
target = target.parentElement;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function onShellFocusout() {
|
|
340
|
+
setTimeout(() => {
|
|
341
|
+
if (!isOpen) return;
|
|
342
|
+
const active = rootNode.activeElement ?? doc.activeElement;
|
|
343
|
+
if (!shell.contains(active)) close(false);
|
|
344
|
+
}, 0);
|
|
345
|
+
}
|
|
346
|
+
function onSelectChange() {
|
|
347
|
+
syncFromSelect();
|
|
348
|
+
}
|
|
349
|
+
const observer = new MutationObserver(() => {
|
|
350
|
+
syncFromSelect();
|
|
351
|
+
});
|
|
352
|
+
observer.observe(select, {
|
|
353
|
+
childList: true,
|
|
354
|
+
subtree: true,
|
|
355
|
+
attributes: true,
|
|
356
|
+
attributeFilter: ["disabled", "value", "selected"]
|
|
357
|
+
});
|
|
358
|
+
const onListboxMousedown = (event) => event.preventDefault();
|
|
359
|
+
trigger.addEventListener("click", onTriggerClick);
|
|
360
|
+
trigger.addEventListener("keydown", onKeydown);
|
|
361
|
+
shell.addEventListener("focusout", onShellFocusout);
|
|
362
|
+
listbox.addEventListener("mousedown", onListboxMousedown);
|
|
363
|
+
listbox.addEventListener("click", onListboxClick);
|
|
364
|
+
listbox.addEventListener("mousemove", onListboxMousemove);
|
|
365
|
+
select.addEventListener("change", onSelectChange);
|
|
366
|
+
function destroy() {
|
|
367
|
+
if (isOpen) close(false);
|
|
368
|
+
observer.disconnect();
|
|
369
|
+
trigger.removeEventListener("click", onTriggerClick);
|
|
370
|
+
trigger.removeEventListener("keydown", onKeydown);
|
|
371
|
+
shell.removeEventListener("focusout", onShellFocusout);
|
|
372
|
+
listbox.removeEventListener("mousedown", onListboxMousedown);
|
|
373
|
+
listbox.removeEventListener("click", onListboxClick);
|
|
374
|
+
listbox.removeEventListener("mousemove", onListboxMousemove);
|
|
375
|
+
select.removeEventListener("change", onSelectChange);
|
|
376
|
+
if (shell.parentNode) shell.parentNode.removeChild(shell);
|
|
377
|
+
if (listbox.parentNode) listbox.parentNode.removeChild(listbox);
|
|
378
|
+
select.classList.remove("lb-dropdown-state");
|
|
379
|
+
select.removeAttribute("aria-hidden");
|
|
380
|
+
select.removeAttribute("tabindex");
|
|
381
|
+
delete slot.__lbDropdownInstance;
|
|
382
|
+
}
|
|
383
|
+
instance = {
|
|
384
|
+
shell,
|
|
385
|
+
listbox,
|
|
386
|
+
select,
|
|
387
|
+
close: () => close(false),
|
|
388
|
+
destroy
|
|
389
|
+
};
|
|
390
|
+
slot.__lbDropdownInstance = instance;
|
|
391
|
+
syncFromSelect();
|
|
392
|
+
return instance;
|
|
393
|
+
}
|
|
394
|
+
function bindAllDropdowns(root) {
|
|
395
|
+
const selects = root.querySelectorAll(BIND_SELECTOR);
|
|
396
|
+
const instances = [];
|
|
397
|
+
selects.forEach((sel) => {
|
|
398
|
+
const inst = bindDropdown(sel);
|
|
399
|
+
if (inst) instances.push(inst);
|
|
400
|
+
});
|
|
401
|
+
return instances;
|
|
402
|
+
}
|
|
403
|
+
function unbindAllDropdowns(root) {
|
|
404
|
+
const bound = root.querySelectorAll("select.lb-dropdown-state");
|
|
405
|
+
bound.forEach((sel) => {
|
|
406
|
+
const inst = sel.__lbDropdownInstance;
|
|
407
|
+
if (inst) inst.destroy();
|
|
408
|
+
});
|
|
409
|
+
}
|
|
36
410
|
|
|
37
|
-
// src/renderers/
|
|
411
|
+
// src/renderers/pricing.ts
|
|
38
412
|
var import_core2 = require("@lime-bundles/core");
|
|
413
|
+
|
|
414
|
+
// src/renderers/countdown.ts
|
|
415
|
+
var import_core3 = require("@lime-bundles/core");
|
|
39
416
|
function renderCountdown(endsAtIso) {
|
|
40
417
|
const parsed = parseIso(endsAtIso);
|
|
41
418
|
if (parsed === null) return null;
|
|
@@ -62,7 +439,7 @@ function renderCountdown(endsAtIso) {
|
|
|
62
439
|
stop();
|
|
63
440
|
return;
|
|
64
441
|
}
|
|
65
|
-
timer.textContent = (0,
|
|
442
|
+
timer.textContent = (0, import_core3.formatCountdown)(msLeft);
|
|
66
443
|
}
|
|
67
444
|
function stop() {
|
|
68
445
|
if (intervalId !== null) {
|
|
@@ -116,7 +493,7 @@ function el(tag, className, attrs = {}) {
|
|
|
116
493
|
}
|
|
117
494
|
|
|
118
495
|
// src/renderers/image.ts
|
|
119
|
-
var
|
|
496
|
+
var import_core4 = require("@lime-bundles/core");
|
|
120
497
|
|
|
121
498
|
// src/renderers/fixed.ts
|
|
122
499
|
var PLACEHOLDER_THUMB_SVG = `
|
|
@@ -127,7 +504,7 @@ var PLACEHOLDER_THUMB_SVG = `
|
|
|
127
504
|
</svg>`;
|
|
128
505
|
function renderFixedBundle(container, bundle, onAddToCart, onCleanup) {
|
|
129
506
|
const wc = bundle.widgetConfig;
|
|
130
|
-
const qtyFor = (productId, variantId) => (0,
|
|
507
|
+
const qtyFor = (productId, variantId) => (0, import_core5.resolveBundleQty)(bundle, productId, variantId);
|
|
131
508
|
const rows = [];
|
|
132
509
|
let oosCount = 0;
|
|
133
510
|
bundle.products.forEach((product, idx) => {
|
|
@@ -192,11 +569,13 @@ function renderFixedBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
192
569
|
})
|
|
193
570
|
);
|
|
194
571
|
container.appendChild(root);
|
|
572
|
+
bindAllDropdowns(root);
|
|
573
|
+
onCleanup?.(() => unbindAllDropdowns(root));
|
|
195
574
|
updatePricing();
|
|
196
575
|
function updatePricing() {
|
|
197
576
|
const totalCents = rows.reduce((sum, r) => {
|
|
198
577
|
if (!r.selected) return sum;
|
|
199
|
-
const unit = (0,
|
|
578
|
+
const unit = (0, import_core2.parseCents)(r.selected.price.amount);
|
|
200
579
|
return sum + unit * r.qty;
|
|
201
580
|
}, 0);
|
|
202
581
|
const saleCents = computeSale(totalCents, bundle.discountConfig, rows);
|
|
@@ -217,7 +596,7 @@ function buildRowState(bundle, product, productIndex) {
|
|
|
217
596
|
const eligibleVariants = merchantScoped;
|
|
218
597
|
const isOos = !firstInStock;
|
|
219
598
|
const selected = firstInStock ?? merchantScoped[0] ?? null;
|
|
220
|
-
const qty = selected ? (0,
|
|
599
|
+
const qty = selected ? (0, import_core5.resolveBundleQty)(bundle, product.id, selected.id) : 1;
|
|
221
600
|
return { product, eligibleVariants, selected, qty, isOos };
|
|
222
601
|
}
|
|
223
602
|
function renderHeader(bundle, currency) {
|
|
@@ -237,7 +616,7 @@ function renderHeader(bundle, currency) {
|
|
|
237
616
|
"data-header-badge": ""
|
|
238
617
|
});
|
|
239
618
|
header.appendChild(badgeEl);
|
|
240
|
-
const initialPricing = (0,
|
|
619
|
+
const initialPricing = (0, import_core2.computeFixedPricing)(
|
|
241
620
|
bundle,
|
|
242
621
|
bundle.productQuantities,
|
|
243
622
|
wc.pricing.showSaveBadge
|
|
@@ -273,9 +652,9 @@ function deriveHeaderBadge(bundle, totalCents, saleCents, currency) {
|
|
|
273
652
|
return `-${Math.round(dc.discountValue)}%`;
|
|
274
653
|
}
|
|
275
654
|
if (dc.discountType === "fixed_amount" && dc.discountValue > 0) {
|
|
276
|
-
return `-${(0,
|
|
655
|
+
return `-${(0, import_core2.formatCents)(Math.round(dc.discountValue * 100), currency)}`;
|
|
277
656
|
}
|
|
278
|
-
return `-${(0,
|
|
657
|
+
return `-${(0, import_core2.formatCents)(savings, currency)}`;
|
|
279
658
|
}
|
|
280
659
|
function renderProductRow(state, currency, qtyFor, onVariantChange) {
|
|
281
660
|
const rowEl = el(
|
|
@@ -287,18 +666,20 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
|
|
|
287
666
|
}
|
|
288
667
|
);
|
|
289
668
|
const thumb = el("div", "lb-bundle-thumbnail", { "data-thumbnail": "" });
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
669
|
+
const initialThumbImage = state.selected?.image ?? state.product.featuredImage ?? null;
|
|
670
|
+
let thumbImg = null;
|
|
671
|
+
if (initialThumbImage) {
|
|
672
|
+
thumbImg = document.createElement("img");
|
|
673
|
+
thumbImg.src = (0, import_core4.transformImageUrl)(initialThumbImage.url, {
|
|
674
|
+
width: import_core4.THUMB_PX,
|
|
675
|
+
height: import_core4.THUMB_PX,
|
|
295
676
|
crop: "center"
|
|
296
677
|
});
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
thumb.appendChild(
|
|
678
|
+
thumbImg.alt = initialThumbImage.altText ?? state.product.title;
|
|
679
|
+
thumbImg.width = import_core4.THUMB_PX;
|
|
680
|
+
thumbImg.height = import_core4.THUMB_PX;
|
|
681
|
+
thumbImg.loading = "lazy";
|
|
682
|
+
thumb.appendChild(thumbImg);
|
|
302
683
|
} else {
|
|
303
684
|
thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG);
|
|
304
685
|
}
|
|
@@ -338,12 +719,12 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
|
|
|
338
719
|
unitPriceEl.setAttribute("hidden", "");
|
|
339
720
|
info.appendChild(unitPriceEl);
|
|
340
721
|
const applyVariantToRow = (variant) => {
|
|
341
|
-
const unit = (0,
|
|
342
|
-
priceEl.textContent = (0,
|
|
722
|
+
const unit = (0, import_core2.parseCents)(variant.price.amount);
|
|
723
|
+
priceEl.textContent = (0, import_core2.formatCents)(unit, currency);
|
|
343
724
|
if (variant.compareAtPrice) {
|
|
344
|
-
const cmp = (0,
|
|
725
|
+
const cmp = (0, import_core2.parseCents)(variant.compareAtPrice.amount);
|
|
345
726
|
if (cmp > unit) {
|
|
346
|
-
compare.textContent = (0,
|
|
727
|
+
compare.textContent = (0, import_core2.formatCents)(cmp, currency);
|
|
347
728
|
compare.removeAttribute("hidden");
|
|
348
729
|
} else {
|
|
349
730
|
compare.setAttribute("hidden", "");
|
|
@@ -351,7 +732,7 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
|
|
|
351
732
|
} else {
|
|
352
733
|
compare.setAttribute("hidden", "");
|
|
353
734
|
}
|
|
354
|
-
const unitText = (0,
|
|
735
|
+
const unitText = (0, import_core2.formatUnitPrice)(
|
|
355
736
|
variant.unitPrice,
|
|
356
737
|
variant.unitPriceMeasurement,
|
|
357
738
|
currency
|
|
@@ -362,6 +743,15 @@ function renderProductRow(state, currency, qtyFor, onVariantChange) {
|
|
|
362
743
|
} else {
|
|
363
744
|
unitPriceEl.setAttribute("hidden", "");
|
|
364
745
|
}
|
|
746
|
+
const nextImage = variant.image ?? state.product.featuredImage;
|
|
747
|
+
if (thumbImg && nextImage) {
|
|
748
|
+
thumbImg.src = (0, import_core4.transformImageUrl)(nextImage.url, {
|
|
749
|
+
width: import_core4.THUMB_PX,
|
|
750
|
+
height: import_core4.THUMB_PX,
|
|
751
|
+
crop: "center"
|
|
752
|
+
});
|
|
753
|
+
thumbImg.alt = nextImage.altText ?? state.product.title;
|
|
754
|
+
}
|
|
365
755
|
};
|
|
366
756
|
applyVariantToRow(state.selected);
|
|
367
757
|
if (state.eligibleVariants.length > 1) {
|
|
@@ -472,9 +862,9 @@ function renderPricingRow(bundle) {
|
|
|
472
862
|
return {
|
|
473
863
|
el: row,
|
|
474
864
|
update({ totalCents, saleCents, savingsCents, currency }) {
|
|
475
|
-
sale.textContent = (0,
|
|
865
|
+
sale.textContent = (0, import_core2.formatCents)(saleCents, currency);
|
|
476
866
|
if (bundle.widgetConfig.pricing.showCompareAtPrice && savingsCents > 0) {
|
|
477
|
-
compare.textContent = (0,
|
|
867
|
+
compare.textContent = (0, import_core2.formatCents)(totalCents, currency);
|
|
478
868
|
compare.style.display = "";
|
|
479
869
|
} else {
|
|
480
870
|
compare.style.display = "none";
|
|
@@ -499,7 +889,7 @@ function renderSavingsBar() {
|
|
|
499
889
|
return;
|
|
500
890
|
}
|
|
501
891
|
bar.style.display = "";
|
|
502
|
-
amount.textContent = (0,
|
|
892
|
+
amount.textContent = (0, import_core2.formatCents)(savingsCents, currency);
|
|
503
893
|
}
|
|
504
894
|
};
|
|
505
895
|
}
|
|
@@ -521,7 +911,7 @@ function computeSale(totalCents, discount, rows) {
|
|
|
521
911
|
let saleCents = 0;
|
|
522
912
|
for (const r of rows) {
|
|
523
913
|
if (!r.selected) continue;
|
|
524
|
-
const unit = (0,
|
|
914
|
+
const unit = (0, import_core2.parseCents)(r.selected.price.amount);
|
|
525
915
|
const off = Math.floor(unit * discount.discountValue / 100);
|
|
526
916
|
const perUnit = Math.max(0, unit - off);
|
|
527
917
|
saleCents += perUnit * r.qty;
|
|
@@ -532,7 +922,7 @@ function computeSale(totalCents, discount, rows) {
|
|
|
532
922
|
}
|
|
533
923
|
|
|
534
924
|
// src/renderers/mix-match.ts
|
|
535
|
-
var
|
|
925
|
+
var import_core6 = require("@lime-bundles/core");
|
|
536
926
|
var PLACEHOLDER_THUMB_SVG2 = `
|
|
537
927
|
<svg class="lb-bundle-placeholder-icon" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
|
|
538
928
|
<rect x="4" y="4" width="20" height="20" rx="3"></rect>
|
|
@@ -628,6 +1018,7 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
628
1018
|
})
|
|
629
1019
|
);
|
|
630
1020
|
container.appendChild(root);
|
|
1021
|
+
onCleanup?.(() => unbindAllDropdowns(root));
|
|
631
1022
|
const firstEligible = eligible.find((ep) => !ep.isOos);
|
|
632
1023
|
const firstVariant = firstEligible?.firstAvailableVariant ?? firstEligible?.variants[0];
|
|
633
1024
|
if (firstEligible && firstVariant) {
|
|
@@ -636,15 +1027,15 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
636
1027
|
productTitle: firstEligible.product.title,
|
|
637
1028
|
variantId: firstVariant.id,
|
|
638
1029
|
variantTitle: firstVariant.title,
|
|
639
|
-
imageUrl: firstEligible.product.featuredImage?.url ?? null,
|
|
640
|
-
priceCents: (0,
|
|
641
|
-
compareCents: firstVariant.compareAtPrice ? (0,
|
|
642
|
-
unitPriceLabel: (0,
|
|
1030
|
+
imageUrl: firstVariant.image?.url ?? firstEligible.product.featuredImage?.url ?? null,
|
|
1031
|
+
priceCents: (0, import_core2.parseCents)(firstVariant.price.amount),
|
|
1032
|
+
compareCents: firstVariant.compareAtPrice ? (0, import_core2.parseCents)(firstVariant.compareAtPrice.amount) : null,
|
|
1033
|
+
unitPriceLabel: (0, import_core2.formatUnitPrice)(
|
|
643
1034
|
firstVariant.unitPrice,
|
|
644
1035
|
firstVariant.unitPriceMeasurement,
|
|
645
1036
|
currency
|
|
646
1037
|
),
|
|
647
|
-
quantity: (0,
|
|
1038
|
+
quantity: (0, import_core6.resolveBundleQty)(bundle, firstEligible.product.id, firstVariant.id)
|
|
648
1039
|
});
|
|
649
1040
|
}
|
|
650
1041
|
afterMutation();
|
|
@@ -655,15 +1046,15 @@ function renderMixMatchBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
655
1046
|
productTitle: product.title,
|
|
656
1047
|
variantId: variant.id,
|
|
657
1048
|
variantTitle: variant.title,
|
|
658
|
-
imageUrl: product.featuredImage?.url ?? null,
|
|
659
|
-
priceCents: (0,
|
|
660
|
-
compareCents: variant.compareAtPrice ? (0,
|
|
661
|
-
unitPriceLabel: (0,
|
|
1049
|
+
imageUrl: variant.image?.url ?? product.featuredImage?.url ?? null,
|
|
1050
|
+
priceCents: (0, import_core2.parseCents)(variant.price.amount),
|
|
1051
|
+
compareCents: variant.compareAtPrice ? (0, import_core2.parseCents)(variant.compareAtPrice.amount) : null,
|
|
1052
|
+
unitPriceLabel: (0, import_core2.formatUnitPrice)(
|
|
662
1053
|
variant.unitPrice,
|
|
663
1054
|
variant.unitPriceMeasurement,
|
|
664
1055
|
currency
|
|
665
1056
|
),
|
|
666
|
-
quantity: (0,
|
|
1057
|
+
quantity: (0, import_core6.resolveBundleQty)(bundle, product.id, variant.id)
|
|
667
1058
|
});
|
|
668
1059
|
afterMutation();
|
|
669
1060
|
}
|
|
@@ -730,7 +1121,7 @@ function renderHeader2(bundle) {
|
|
|
730
1121
|
if (discountType === "percentage" && discountValue > 0) {
|
|
731
1122
|
label = `-${Math.round(discountValue)}%`;
|
|
732
1123
|
} else if (discountType === "fixed_amount" && discountValue > 0) {
|
|
733
|
-
label = `-${(0,
|
|
1124
|
+
label = `-${(0, import_core2.formatCents)(
|
|
734
1125
|
Math.round(discountValue * 100),
|
|
735
1126
|
bundle.products[0]?.priceRange.minVariantPrice.currencyCode ?? "USD"
|
|
736
1127
|
)}`;
|
|
@@ -817,14 +1208,14 @@ function renderFilledSlot(selection, index, currency, onRemove) {
|
|
|
817
1208
|
const thumb = el("div", "lb-bundle-thumbnail", { "data-thumbnail": "" });
|
|
818
1209
|
if (selection.imageUrl) {
|
|
819
1210
|
const img = document.createElement("img");
|
|
820
|
-
img.src = (0,
|
|
821
|
-
width:
|
|
822
|
-
height:
|
|
1211
|
+
img.src = (0, import_core4.transformImageUrl)(selection.imageUrl, {
|
|
1212
|
+
width: import_core4.THUMB_PX,
|
|
1213
|
+
height: import_core4.THUMB_PX,
|
|
823
1214
|
crop: "center"
|
|
824
1215
|
});
|
|
825
1216
|
img.alt = selection.productTitle;
|
|
826
|
-
img.width =
|
|
827
|
-
img.height =
|
|
1217
|
+
img.width = import_core4.THUMB_PX;
|
|
1218
|
+
img.height = import_core4.THUMB_PX;
|
|
828
1219
|
img.loading = "lazy";
|
|
829
1220
|
thumb.appendChild(img);
|
|
830
1221
|
} else {
|
|
@@ -848,11 +1239,11 @@ function renderFilledSlot(selection, index, currency, onRemove) {
|
|
|
848
1239
|
const priceWrap = el("span", "lb-mix-match__filled-price");
|
|
849
1240
|
if (lineCompare !== null && lineCompare > linePrice) {
|
|
850
1241
|
const compare = el("span", "lb-mix-match__filled-compare");
|
|
851
|
-
compare.textContent = (0,
|
|
1242
|
+
compare.textContent = (0, import_core2.formatCents)(lineCompare, currency);
|
|
852
1243
|
priceWrap.appendChild(compare);
|
|
853
1244
|
}
|
|
854
1245
|
const priceEl = document.createElement("span");
|
|
855
|
-
priceEl.textContent = (0,
|
|
1246
|
+
priceEl.textContent = (0, import_core2.formatCents)(linePrice, currency);
|
|
856
1247
|
priceWrap.appendChild(priceEl);
|
|
857
1248
|
info.appendChild(priceWrap);
|
|
858
1249
|
if (selection.unitPriceLabel) {
|
|
@@ -897,14 +1288,14 @@ function renderPricingSection(showCompareAtPrice) {
|
|
|
897
1288
|
(s, sel) => s + sel.priceCents * sel.quantity,
|
|
898
1289
|
0
|
|
899
1290
|
);
|
|
900
|
-
const saleCents = (0,
|
|
1291
|
+
const saleCents = (0, import_core2.computeBundleSaleCents)(totalCents, bundle.discountConfig);
|
|
901
1292
|
if (showCompareAtPrice && totalCents > saleCents) {
|
|
902
|
-
compare.textContent = (0,
|
|
1293
|
+
compare.textContent = (0, import_core2.formatCents)(totalCents, currency);
|
|
903
1294
|
compare.style.display = "";
|
|
904
1295
|
} else {
|
|
905
1296
|
compare.style.display = "none";
|
|
906
1297
|
}
|
|
907
|
-
sale.textContent = (0,
|
|
1298
|
+
sale.textContent = (0, import_core2.formatCents)(saleCents, currency);
|
|
908
1299
|
}
|
|
909
1300
|
return { el: wrap, update };
|
|
910
1301
|
}
|
|
@@ -927,14 +1318,14 @@ function renderSavingsBar2() {
|
|
|
927
1318
|
(s, sel) => s + sel.priceCents * sel.quantity,
|
|
928
1319
|
0
|
|
929
1320
|
);
|
|
930
|
-
const saleCents = (0,
|
|
1321
|
+
const saleCents = (0, import_core2.computeBundleSaleCents)(totalCents, bundle.discountConfig);
|
|
931
1322
|
const savings = Math.max(0, totalCents - saleCents);
|
|
932
1323
|
if (savings <= 0) {
|
|
933
1324
|
wrap.style.display = "none";
|
|
934
1325
|
return;
|
|
935
1326
|
}
|
|
936
1327
|
wrap.style.display = "";
|
|
937
|
-
amount.textContent = (0,
|
|
1328
|
+
amount.textContent = (0, import_core2.formatCents)(savings, currency);
|
|
938
1329
|
}
|
|
939
1330
|
return { el: wrap, update };
|
|
940
1331
|
}
|
|
@@ -1030,24 +1421,27 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1030
1421
|
{ "data-product-id": ep.product.id.replace(/^.*\//, "") }
|
|
1031
1422
|
);
|
|
1032
1423
|
const thumb = el("div", "lb-mix-match__modal-product-thumb");
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1424
|
+
const initialThumbVariant = ep.variants.find((v) => v.availableForSale) ?? ep.variants[0] ?? null;
|
|
1425
|
+
const initialThumbImage = initialThumbVariant?.image ?? ep.product.featuredImage ?? null;
|
|
1426
|
+
let thumbImg = null;
|
|
1427
|
+
if (initialThumbImage) {
|
|
1428
|
+
thumbImg = document.createElement("img");
|
|
1429
|
+
thumbImg.src = (0, import_core4.transformImageUrl)(initialThumbImage.url, {
|
|
1430
|
+
width: import_core4.THUMB_PX,
|
|
1431
|
+
height: import_core4.THUMB_PX,
|
|
1038
1432
|
crop: "center"
|
|
1039
1433
|
});
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
thumb.appendChild(
|
|
1434
|
+
thumbImg.alt = initialThumbImage.altText ?? ep.product.title;
|
|
1435
|
+
thumbImg.width = import_core4.THUMB_PX;
|
|
1436
|
+
thumbImg.height = import_core4.THUMB_PX;
|
|
1437
|
+
thumbImg.loading = "lazy";
|
|
1438
|
+
thumb.appendChild(thumbImg);
|
|
1045
1439
|
} else {
|
|
1046
1440
|
thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG2);
|
|
1047
1441
|
}
|
|
1048
1442
|
const countBadge = el("span", "lb-bundle-qty-badge");
|
|
1049
1443
|
countBadge.textContent = String(
|
|
1050
|
-
(0,
|
|
1444
|
+
(0, import_core6.resolveBundleQty)(bundle, ep.product.id, currentVariant.id)
|
|
1051
1445
|
);
|
|
1052
1446
|
thumb.appendChild(countBadge);
|
|
1053
1447
|
productEl.appendChild(thumb);
|
|
@@ -1056,8 +1450,8 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1056
1450
|
title.textContent = ep.product.title;
|
|
1057
1451
|
info.appendChild(title);
|
|
1058
1452
|
const price = el("p", "lb-mix-match__modal-product-price");
|
|
1059
|
-
price.textContent = (0,
|
|
1060
|
-
(0,
|
|
1453
|
+
price.textContent = (0, import_core2.formatCents)(
|
|
1454
|
+
(0, import_core2.parseCents)(currentVariant.price.amount) * (0, import_core6.resolveBundleQty)(bundle, ep.product.id, currentVariant.id),
|
|
1061
1455
|
currency
|
|
1062
1456
|
);
|
|
1063
1457
|
info.appendChild(price);
|
|
@@ -1065,7 +1459,7 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1065
1459
|
"p",
|
|
1066
1460
|
"lb-mix-match__modal-product-unit-price lb-bundle-product-unit-price"
|
|
1067
1461
|
);
|
|
1068
|
-
const initialUnitText = (0,
|
|
1462
|
+
const initialUnitText = (0, import_core2.formatUnitPrice)(
|
|
1069
1463
|
currentVariant.unitPrice,
|
|
1070
1464
|
currentVariant.unitPriceMeasurement,
|
|
1071
1465
|
currency
|
|
@@ -1124,16 +1518,16 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1124
1518
|
}
|
|
1125
1519
|
currentVariant = next;
|
|
1126
1520
|
row.variant = next;
|
|
1127
|
-
const nextQty = (0,
|
|
1521
|
+
const nextQty = (0, import_core6.resolveBundleQty)(
|
|
1128
1522
|
bundle,
|
|
1129
1523
|
ep.product.id,
|
|
1130
1524
|
currentVariant.id
|
|
1131
1525
|
);
|
|
1132
|
-
price.textContent = (0,
|
|
1133
|
-
(0,
|
|
1526
|
+
price.textContent = (0, import_core2.formatCents)(
|
|
1527
|
+
(0, import_core2.parseCents)(currentVariant.price.amount) * nextQty,
|
|
1134
1528
|
currency
|
|
1135
1529
|
);
|
|
1136
|
-
const nextUnitText = (0,
|
|
1530
|
+
const nextUnitText = (0, import_core2.formatUnitPrice)(
|
|
1137
1531
|
currentVariant.unitPrice,
|
|
1138
1532
|
currentVariant.unitPriceMeasurement,
|
|
1139
1533
|
currency
|
|
@@ -1145,6 +1539,15 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1145
1539
|
unitPrice.textContent = "";
|
|
1146
1540
|
unitPrice.hidden = true;
|
|
1147
1541
|
}
|
|
1542
|
+
const nextImage = currentVariant.image ?? ep.product.featuredImage;
|
|
1543
|
+
if (thumbImg && nextImage) {
|
|
1544
|
+
thumbImg.src = (0, import_core4.transformImageUrl)(nextImage.url, {
|
|
1545
|
+
width: import_core4.THUMB_PX,
|
|
1546
|
+
height: import_core4.THUMB_PX,
|
|
1547
|
+
crop: "center"
|
|
1548
|
+
});
|
|
1549
|
+
thumbImg.alt = nextImage.altText ?? ep.product.title;
|
|
1550
|
+
}
|
|
1148
1551
|
recomputeDisabled(next.selectedOptions.map((o) => o.value));
|
|
1149
1552
|
rowUpdateCount();
|
|
1150
1553
|
};
|
|
@@ -1195,7 +1598,7 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1195
1598
|
productEl.appendChild(info);
|
|
1196
1599
|
const rowUpdateCount = () => {
|
|
1197
1600
|
countBadge.textContent = String(
|
|
1198
|
-
(0,
|
|
1601
|
+
(0, import_core6.resolveBundleQty)(bundle, ep.product.id, currentVariant.id)
|
|
1199
1602
|
);
|
|
1200
1603
|
};
|
|
1201
1604
|
if (!ep.isOos) {
|
|
@@ -1215,6 +1618,7 @@ function renderModal(bundle, eligible, currency, handlers) {
|
|
|
1215
1618
|
productRows.push(row);
|
|
1216
1619
|
list.appendChild(productEl);
|
|
1217
1620
|
});
|
|
1621
|
+
bindAllDropdowns(list);
|
|
1218
1622
|
refreshCounts();
|
|
1219
1623
|
}
|
|
1220
1624
|
function applySearch() {
|
|
@@ -1318,7 +1722,7 @@ function renderVolumeBundle(container, bundle, onAddToCart, onCleanup) {
|
|
|
1318
1722
|
const product = bundle.products[0];
|
|
1319
1723
|
const variant = product?.variants.nodes.find((v) => v.availableForSale);
|
|
1320
1724
|
if (!variant && wc.outOfStockBehavior === "hide") return;
|
|
1321
|
-
const basePriceCents = variant ? (0,
|
|
1725
|
+
const basePriceCents = variant ? (0, import_core2.parseCents)(variant.price.amount) : 0;
|
|
1322
1726
|
const currency = variant?.price.currencyCode ?? "USD";
|
|
1323
1727
|
const discountType = bundle.discountConfig.discountType;
|
|
1324
1728
|
const resolved = bundle.volumeTiers.map((tier, index) => {
|
|
@@ -1497,13 +1901,13 @@ function renderTierCard(r, isSelected, currency, popularLabel, showComparePrice,
|
|
|
1497
1901
|
const price = el("span", "lb-volume__tier-price");
|
|
1498
1902
|
if (showComparePrice && r.pricePerUnitCents < r.basePricePerUnitCents) {
|
|
1499
1903
|
const compare = el("span", "lb-volume__tier-compare");
|
|
1500
|
-
compare.textContent = (0,
|
|
1904
|
+
compare.textContent = (0, import_core2.formatCents)(r.basePricePerUnitCents, currency);
|
|
1501
1905
|
price.appendChild(compare);
|
|
1502
1906
|
}
|
|
1503
1907
|
if (showPerUnitPrice) {
|
|
1504
1908
|
const each = document.createElement("span");
|
|
1505
1909
|
each.setAttribute("data-tier-price-each", "");
|
|
1506
|
-
each.textContent = (0,
|
|
1910
|
+
each.textContent = (0, import_core2.formatCents)(r.pricePerUnitCents, currency);
|
|
1507
1911
|
price.appendChild(each);
|
|
1508
1912
|
const unit = el("span", "lb-volume__tier-unit");
|
|
1509
1913
|
unit.textContent = " each";
|
|
@@ -1542,11 +1946,11 @@ function renderPricingRow2(resolved, selectedIndex, currency, showItemCount, sho
|
|
|
1542
1946
|
const compare = el("span", "lb-bundle-compare-price", {
|
|
1543
1947
|
"data-compare-price": ""
|
|
1544
1948
|
});
|
|
1545
|
-
compare.textContent = (0,
|
|
1949
|
+
compare.textContent = (0, import_core2.formatCents)(undiscountedCents, currency);
|
|
1546
1950
|
prices.appendChild(compare);
|
|
1547
1951
|
}
|
|
1548
1952
|
const sale = el("span", "lb-bundle-sale-price", { "data-total-price": "" });
|
|
1549
|
-
sale.textContent = (0,
|
|
1953
|
+
sale.textContent = (0, import_core2.formatCents)(totalCents, currency);
|
|
1550
1954
|
prices.appendChild(sale);
|
|
1551
1955
|
row.appendChild(prices);
|
|
1552
1956
|
return row;
|
|
@@ -1562,7 +1966,7 @@ function renderSavingsBar3(resolved, selectedIndex, currency) {
|
|
|
1562
1966
|
labelEl.textContent = "You save";
|
|
1563
1967
|
bar.appendChild(labelEl);
|
|
1564
1968
|
const amount = el("span", "", { "data-savings-amount": "" });
|
|
1565
|
-
amount.textContent = (0,
|
|
1969
|
+
amount.textContent = (0, import_core2.formatCents)(savings, currency);
|
|
1566
1970
|
bar.appendChild(amount);
|
|
1567
1971
|
return bar;
|
|
1568
1972
|
}
|
|
@@ -1583,7 +1987,7 @@ function badgeFor(resolved, currency, discountType) {
|
|
|
1583
1987
|
const { tier } = resolved;
|
|
1584
1988
|
if (discountType === "fixed_amount") {
|
|
1585
1989
|
const amount = tier.amount ?? 0;
|
|
1586
|
-
if (amount > 0) return `-${(0,
|
|
1990
|
+
if (amount > 0) return `-${(0, import_core2.formatCents)(Math.round(amount * 100), currency)}`;
|
|
1587
1991
|
return null;
|
|
1588
1992
|
}
|
|
1589
1993
|
if (discountType === "percentage") {
|
|
@@ -1610,7 +2014,7 @@ function clamp(n, min, max) {
|
|
|
1610
2014
|
}
|
|
1611
2015
|
|
|
1612
2016
|
// src/lime-bundle.ts
|
|
1613
|
-
var
|
|
2017
|
+
var import_core8 = require("@lime-bundles/core");
|
|
1614
2018
|
|
|
1615
2019
|
// src/utils/input-mode.ts
|
|
1616
2020
|
var NAV_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -1680,6 +2084,11 @@ var BUNDLE_BASE_CSS = `/* Lime Bundles \u2014 shared base styles for all bundle
|
|
|
1680
2084
|
--lb-thumbnail-bg: #F0F0F0;
|
|
1681
2085
|
--lb-widget-pad: 20px;
|
|
1682
2086
|
--lb-progress-color: var(--lb-primary-color);
|
|
2087
|
+
/* Cap on the per-bundle product/slot/tier list height \u2014 keeps long
|
|
2088
|
+
bundles from pushing the CTA off-screen. The list scrolls
|
|
2089
|
+
internally with the same custom 4px scrollbar as the variant
|
|
2090
|
+
dropdown when content exceeds this. */
|
|
2091
|
+
--lb-list-max-height: 360px;
|
|
1683
2092
|
|
|
1684
2093
|
font-family: inherit;
|
|
1685
2094
|
font-size: 16px;
|
|
@@ -2234,6 +2643,22 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
2234
2643
|
flex-direction: column;
|
|
2235
2644
|
gap: 0;
|
|
2236
2645
|
margin: 0;
|
|
2646
|
+
max-height: var(--lb-list-max-height);
|
|
2647
|
+
overflow-y: auto;
|
|
2648
|
+
/* Custom scrollbar \u2014 text colour at 15% opacity (thumb) and 5% (track). */
|
|
2649
|
+
scrollbar-width: thin;
|
|
2650
|
+
scrollbar-color: color-mix(in srgb, var(--lb-text) 15%, transparent)
|
|
2651
|
+
color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
.lb-fixed__products::-webkit-scrollbar { width: 4px; }
|
|
2655
|
+
.lb-fixed__products::-webkit-scrollbar-track {
|
|
2656
|
+
background: color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
2657
|
+
border-radius: 2px;
|
|
2658
|
+
}
|
|
2659
|
+
.lb-fixed__products::-webkit-scrollbar-thumb {
|
|
2660
|
+
background: color-mix(in srgb, var(--lb-text) 15%, transparent);
|
|
2661
|
+
border-radius: 2px;
|
|
2237
2662
|
}
|
|
2238
2663
|
|
|
2239
2664
|
/* Fixed bundles: product rows */
|
|
@@ -2289,6 +2714,28 @@ var BUNDLE_FIXED_CSS = `/* Lime Bundles \u2014 Fixed bundle styles */
|
|
|
2289
2714
|
`;
|
|
2290
2715
|
var BUNDLE_MIX_MATCH_CSS = `/* Lime Bundles \u2014 Mix & Match styles */
|
|
2291
2716
|
|
|
2717
|
+
/* === Slot list ============================================================
|
|
2718
|
+
Caps the height of the slot stack so long bundles don't push the CTA off
|
|
2719
|
+
the page. Internal scroll with the same custom 4px scrollbar as the
|
|
2720
|
+
variant dropdown panel. */
|
|
2721
|
+
.lb-mix-match__slots {
|
|
2722
|
+
max-height: var(--lb-list-max-height);
|
|
2723
|
+
overflow-y: auto;
|
|
2724
|
+
scrollbar-width: thin;
|
|
2725
|
+
scrollbar-color: color-mix(in srgb, var(--lb-text) 15%, transparent)
|
|
2726
|
+
color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
.lb-mix-match__slots::-webkit-scrollbar { width: 4px; }
|
|
2730
|
+
.lb-mix-match__slots::-webkit-scrollbar-track {
|
|
2731
|
+
background: color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
2732
|
+
border-radius: 2px;
|
|
2733
|
+
}
|
|
2734
|
+
.lb-mix-match__slots::-webkit-scrollbar-thumb {
|
|
2735
|
+
background: color-mix(in srgb, var(--lb-text) 15%, transparent);
|
|
2736
|
+
border-radius: 2px;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2292
2739
|
/* === Progress Bar === */
|
|
2293
2740
|
.lb-mix-match__progress {
|
|
2294
2741
|
margin-bottom: 16px;
|
|
@@ -2805,6 +3252,22 @@ var BUNDLE_VOLUME_CSS = `/* Lime Bundles \u2014 Volume / Quantity Breaks styles
|
|
|
2805
3252
|
display: flex;
|
|
2806
3253
|
flex-direction: column;
|
|
2807
3254
|
gap: 12px;
|
|
3255
|
+
max-height: var(--lb-list-max-height);
|
|
3256
|
+
overflow-y: auto;
|
|
3257
|
+
/* Custom scrollbar \u2014 text colour at 15% opacity (thumb) and 5% (track). */
|
|
3258
|
+
scrollbar-width: thin;
|
|
3259
|
+
scrollbar-color: color-mix(in srgb, var(--lb-text) 15%, transparent)
|
|
3260
|
+
color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
.lb-volume__tiers::-webkit-scrollbar { width: 4px; }
|
|
3264
|
+
.lb-volume__tiers::-webkit-scrollbar-track {
|
|
3265
|
+
background: color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
3266
|
+
border-radius: 2px;
|
|
3267
|
+
}
|
|
3268
|
+
.lb-volume__tiers::-webkit-scrollbar-thumb {
|
|
3269
|
+
background: color-mix(in srgb, var(--lb-text) 15%, transparent);
|
|
3270
|
+
border-radius: 2px;
|
|
2808
3271
|
}
|
|
2809
3272
|
|
|
2810
3273
|
.lb-volume__tier {
|
|
@@ -2909,6 +3372,259 @@ var BUNDLE_VOLUME_CSS = `/* Lime Bundles \u2014 Volume / Quantity Breaks styles
|
|
|
2909
3372
|
}
|
|
2910
3373
|
|
|
2911
3374
|
|
|
3375
|
+
`;
|
|
3376
|
+
var BUNDLE_DROPDOWN_CSS = `/**
|
|
3377
|
+
* Lime Bundles \u2014 Custom variant-picker dropdown styling.
|
|
3378
|
+
*
|
|
3379
|
+
* Reuses existing CSS variables: no new merchant-configurable surface.
|
|
3380
|
+
* --lb-variant-border-{width,color}, --lb-variant-radius, --lb-variant-chevron
|
|
3381
|
+
* --lb-bg, --lb-text, --lb-primary-color
|
|
3382
|
+
*
|
|
3383
|
+
* Mix-match modal context overrides via .lb-mix-match__modal scope to use
|
|
3384
|
+
* --lb-picker-variant-* and --lb-picker-bg.
|
|
3385
|
+
*/
|
|
3386
|
+
|
|
3387
|
+
/* Hide the native <select> while keeping it form-serializable and focusable
|
|
3388
|
+
programmatically. The .lb-dropdown-state marker is added by JS at bind
|
|
3389
|
+
time, so this rule matches every variant-select class (main widget,
|
|
3390
|
+
mix-match modal, future bundle types). aria-hidden + tabindex=-1
|
|
3391
|
+
(also set in JS) remove it from the accessibility tree. */
|
|
3392
|
+
.lb-dropdown-state {
|
|
3393
|
+
position: absolute !important;
|
|
3394
|
+
width: 1px !important;
|
|
3395
|
+
height: 1px !important;
|
|
3396
|
+
padding: 0 !important;
|
|
3397
|
+
margin: -1px !important;
|
|
3398
|
+
overflow: hidden !important;
|
|
3399
|
+
clip: rect(0 0 0 0) !important;
|
|
3400
|
+
white-space: nowrap !important;
|
|
3401
|
+
border: 0 !important;
|
|
3402
|
+
pointer-events: none !important;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
/* Shell fills its parent column. */
|
|
3406
|
+
.lb-dropdown {
|
|
3407
|
+
position: relative;
|
|
3408
|
+
display: inline-block;
|
|
3409
|
+
width: 100%;
|
|
3410
|
+
max-width: 100%;
|
|
3411
|
+
font-family: inherit;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
/* Trigger styled identically to the closed-state native select */
|
|
3415
|
+
.lb-dropdown-trigger {
|
|
3416
|
+
display: inline-flex;
|
|
3417
|
+
align-items: center;
|
|
3418
|
+
justify-content: space-between;
|
|
3419
|
+
gap: 8px;
|
|
3420
|
+
width: 100%;
|
|
3421
|
+
border: var(--lb-variant-border-width) solid var(--lb-variant-border-color);
|
|
3422
|
+
border-radius: var(--lb-variant-radius);
|
|
3423
|
+
padding: 8px 12px;
|
|
3424
|
+
font-size: 12px;
|
|
3425
|
+
line-height: 16px;
|
|
3426
|
+
color: var(--lb-text);
|
|
3427
|
+
background: var(--lb-bg);
|
|
3428
|
+
font-family: inherit;
|
|
3429
|
+
cursor: pointer;
|
|
3430
|
+
appearance: none;
|
|
3431
|
+
-webkit-appearance: none;
|
|
3432
|
+
text-align: start;
|
|
3433
|
+
transition: border-color 120ms ease;
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
.lb-dropdown-trigger:focus-visible {
|
|
3437
|
+
outline: 2px solid var(--lb-primary-color);
|
|
3438
|
+
outline-offset: 2px;
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
.lb-dropdown-trigger[aria-expanded="true"] {
|
|
3442
|
+
border-color: var(--lb-text);
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
.lb-dropdown-trigger-value {
|
|
3446
|
+
flex: 1 1 auto;
|
|
3447
|
+
white-space: nowrap;
|
|
3448
|
+
overflow: hidden;
|
|
3449
|
+
text-overflow: ellipsis;
|
|
3450
|
+
text-align: start;
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
.lb-dropdown-chevron {
|
|
3454
|
+
flex: 0 0 auto;
|
|
3455
|
+
width: 12px;
|
|
3456
|
+
height: 12px;
|
|
3457
|
+
background: var(--lb-variant-chevron) center / contain no-repeat;
|
|
3458
|
+
transition: transform 120ms ease;
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3461
|
+
.lb-dropdown-trigger[aria-expanded="true"] .lb-dropdown-chevron {
|
|
3462
|
+
transform: rotate(180deg);
|
|
3463
|
+
}
|
|
3464
|
+
|
|
3465
|
+
/* Popover panel \u2014 position: absolute against the .lb-dropdown shell
|
|
3466
|
+
(already position: relative). Top/left/width come from CSS so we
|
|
3467
|
+
never depend on JS having set inline coords by the time the panel
|
|
3468
|
+
becomes visible. JS only sets max-height. */
|
|
3469
|
+
.lb-dropdown-listbox {
|
|
3470
|
+
position: absolute;
|
|
3471
|
+
left: 0;
|
|
3472
|
+
/* Default to below-trigger placement so the panel doesn't overlap the
|
|
3473
|
+
trigger if data-placement is missing for any reason. The explicit
|
|
3474
|
+
[data-placement="down"|"up"] rules below override this. */
|
|
3475
|
+
top: calc(100% + 4px);
|
|
3476
|
+
width: 100%;
|
|
3477
|
+
z-index: 9999;
|
|
3478
|
+
margin: 0;
|
|
3479
|
+
padding: 4px 0;
|
|
3480
|
+
list-style: none;
|
|
3481
|
+
background: var(--lb-bg);
|
|
3482
|
+
color: var(--lb-text);
|
|
3483
|
+
border: var(--lb-variant-border-width) solid var(--lb-variant-border-color);
|
|
3484
|
+
border-radius: var(--lb-variant-radius);
|
|
3485
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
3486
|
+
overflow-y: auto;
|
|
3487
|
+
overflow-x: hidden;
|
|
3488
|
+
/* Custom scrollbar \u2014 text colour at 15% opacity (thumb) and 5% (track). */
|
|
3489
|
+
scrollbar-width: thin;
|
|
3490
|
+
scrollbar-color: color-mix(in srgb, var(--lb-text) 15%, transparent)
|
|
3491
|
+
color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
3492
|
+
animation: lb-dropdown-in-down 120ms ease-out;
|
|
3493
|
+
transform-origin: top center;
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
.lb-dropdown-listbox[data-placement="down"] {
|
|
3497
|
+
top: calc(100% + 4px);
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
.lb-dropdown-listbox[data-placement="up"] {
|
|
3501
|
+
top: auto;
|
|
3502
|
+
bottom: calc(100% + 4px);
|
|
3503
|
+
animation-name: lb-dropdown-in-up;
|
|
3504
|
+
transform-origin: bottom center;
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3507
|
+
/* When portaled out of the .lb-dropdown shell (mix-match modal context:
|
|
3508
|
+
.lb-mix-match__modal applies translateY which would otherwise trap
|
|
3509
|
+
position:fixed), switch to fixed and let JS set viewport coords. */
|
|
3510
|
+
.lb-dropdown-listbox[data-lb-dropdown-portal] {
|
|
3511
|
+
position: fixed;
|
|
3512
|
+
top: auto;
|
|
3513
|
+
left: auto;
|
|
3514
|
+
bottom: auto;
|
|
3515
|
+
width: auto;
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
/* Custom scrollbar \u2014 Webkit/Blink: exact 4px width */
|
|
3519
|
+
.lb-dropdown-listbox::-webkit-scrollbar {
|
|
3520
|
+
width: 4px;
|
|
3521
|
+
}
|
|
3522
|
+
.lb-dropdown-listbox::-webkit-scrollbar-track {
|
|
3523
|
+
background: color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
3524
|
+
border-radius: 2px;
|
|
3525
|
+
}
|
|
3526
|
+
.lb-dropdown-listbox::-webkit-scrollbar-thumb {
|
|
3527
|
+
background: color-mix(in srgb, var(--lb-text) 15%, transparent);
|
|
3528
|
+
border-radius: 2px;
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
/* Options */
|
|
3532
|
+
.lb-dropdown-option {
|
|
3533
|
+
padding: 8px 12px;
|
|
3534
|
+
font-size: 12px;
|
|
3535
|
+
line-height: 16px;
|
|
3536
|
+
cursor: pointer;
|
|
3537
|
+
white-space: nowrap;
|
|
3538
|
+
overflow: hidden;
|
|
3539
|
+
text-overflow: ellipsis;
|
|
3540
|
+
color: var(--lb-text);
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
.lb-dropdown-option[aria-selected="true"] {
|
|
3544
|
+
font-weight: 600;
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3547
|
+
.lb-dropdown-option.is-active,
|
|
3548
|
+
.lb-dropdown-option:hover:not([aria-disabled="true"]) {
|
|
3549
|
+
background: color-mix(in srgb, var(--lb-text) 2%, transparent);
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
.lb-dropdown-option[aria-disabled="true"] {
|
|
3553
|
+
opacity: 0.4;
|
|
3554
|
+
cursor: not-allowed;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
/* Animations */
|
|
3558
|
+
@keyframes lb-dropdown-in-down {
|
|
3559
|
+
from { opacity: 0; transform: translateY(-4px) scale(0.98); }
|
|
3560
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
@keyframes lb-dropdown-in-up {
|
|
3564
|
+
from { opacity: 0; transform: translateY(4px) scale(0.98); }
|
|
3565
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3569
|
+
.lb-dropdown-listbox { animation: none; }
|
|
3570
|
+
.lb-dropdown-chevron { transition: none; }
|
|
3571
|
+
.lb-dropdown-trigger { transition: none; }
|
|
3572
|
+
}
|
|
3573
|
+
|
|
3574
|
+
/* Forced-colors mode (Windows high-contrast) */
|
|
3575
|
+
@media (forced-colors: active) {
|
|
3576
|
+
.lb-dropdown-trigger {
|
|
3577
|
+
border-color: ButtonBorder;
|
|
3578
|
+
color: ButtonText;
|
|
3579
|
+
background: ButtonFace;
|
|
3580
|
+
}
|
|
3581
|
+
.lb-dropdown-listbox {
|
|
3582
|
+
border-color: ButtonBorder;
|
|
3583
|
+
background: Canvas;
|
|
3584
|
+
color: CanvasText;
|
|
3585
|
+
}
|
|
3586
|
+
.lb-dropdown-option.is-active {
|
|
3587
|
+
background: Highlight;
|
|
3588
|
+
color: HighlightText;
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
/* Mix-match modal context \u2014 use picker-scoped variables.
|
|
3593
|
+
No CSS fallbacks: --lb-picker-* are always emitted by bundle-widget.liquid
|
|
3594
|
+
because WidgetConfig.parse() fully hydrates the merchant config.
|
|
3595
|
+
See docs/solutions/ui-bugs/widget-css-single-source-defaults.md. */
|
|
3596
|
+
.lb-mix-match__modal .lb-dropdown-trigger {
|
|
3597
|
+
border-color: var(--lb-picker-variant-border-color);
|
|
3598
|
+
border-width: var(--lb-picker-variant-border-width);
|
|
3599
|
+
border-radius: var(--lb-picker-variant-radius);
|
|
3600
|
+
background: var(--lb-picker-bg);
|
|
3601
|
+
color: var(--lb-picker-text);
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3604
|
+
.lb-mix-match__modal .lb-dropdown-chevron {
|
|
3605
|
+
background-image: var(--lb-picker-variant-chevron);
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
/* Listbox is portaled out of the transformed .lb-mix-match__modal up to
|
|
3609
|
+
its [data-modal-overlay] parent, so picker-scoped rules anchor on the
|
|
3610
|
+
overlay attribute, not the modal class. */
|
|
3611
|
+
[data-modal-overlay] > .lb-dropdown-listbox {
|
|
3612
|
+
border-color: var(--lb-picker-variant-border-color);
|
|
3613
|
+
border-width: var(--lb-picker-variant-border-width);
|
|
3614
|
+
border-radius: var(--lb-picker-variant-radius);
|
|
3615
|
+
background: var(--lb-picker-bg);
|
|
3616
|
+
color: var(--lb-picker-text);
|
|
3617
|
+
scrollbar-color: color-mix(in srgb, var(--lb-picker-text) 15%, transparent)
|
|
3618
|
+
color-mix(in srgb, var(--lb-picker-text) 2%, transparent);
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
[data-modal-overlay] > .lb-dropdown-listbox::-webkit-scrollbar-track {
|
|
3622
|
+
background: color-mix(in srgb, var(--lb-picker-text) 2%, transparent);
|
|
3623
|
+
border-radius: 2px;
|
|
3624
|
+
}
|
|
3625
|
+
[data-modal-overlay] > .lb-dropdown-listbox::-webkit-scrollbar-thumb {
|
|
3626
|
+
background: color-mix(in srgb, var(--lb-picker-text) 15%, transparent);
|
|
3627
|
+
}
|
|
2912
3628
|
`;
|
|
2913
3629
|
var BUNDLE_SKELETON_CSS = `/* Lime Bundles \u2014 web-component loading skeleton (not mirrored to theme assets) */
|
|
2914
3630
|
|
|
@@ -3107,7 +3823,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3107
3823
|
const controller = new AbortController();
|
|
3108
3824
|
this.abortController = controller;
|
|
3109
3825
|
this.renderLoading();
|
|
3110
|
-
const client = (0,
|
|
3826
|
+
const client = (0, import_core7.createStorefrontClient)({
|
|
3111
3827
|
shopDomain: this.shopDomain,
|
|
3112
3828
|
accessToken: this.storefrontToken
|
|
3113
3829
|
});
|
|
@@ -3132,7 +3848,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3132
3848
|
handle
|
|
3133
3849
|
);
|
|
3134
3850
|
}
|
|
3135
|
-
const cssPromise = client.query(
|
|
3851
|
+
const cssPromise = client.query(import_core7.SHOP_CUSTOM_CSS_QUERY, void 0, {
|
|
3136
3852
|
signal: controller.signal
|
|
3137
3853
|
}).catch(() => null);
|
|
3138
3854
|
await bundlePromise;
|
|
@@ -3144,8 +3860,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3144
3860
|
}
|
|
3145
3861
|
const css = await cssPromise;
|
|
3146
3862
|
if (css?.shop?.metafield?.value) {
|
|
3147
|
-
(0,
|
|
3148
|
-
const sanitized = (0,
|
|
3863
|
+
(0, import_core7.injectCustomCss)(this.shopDomain, css.shop.metafield.value);
|
|
3864
|
+
const sanitized = (0, import_core7.sanitizeCustomCss)(css.shop.metafield.value);
|
|
3149
3865
|
if (sanitized.ok) this.shopCustomCss = sanitized.css;
|
|
3150
3866
|
}
|
|
3151
3867
|
await this.applyABVariants();
|
|
@@ -3173,14 +3889,14 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3173
3889
|
this.bundles.map(async (bundle) => {
|
|
3174
3890
|
if (!bundle.abTestId || !bundle.abVariantB) return bundle;
|
|
3175
3891
|
try {
|
|
3176
|
-
const assignment = await (0,
|
|
3892
|
+
const assignment = await (0, import_core7.getABTestAssignment)(
|
|
3177
3893
|
this.appUrl,
|
|
3178
3894
|
this.shopDomain,
|
|
3179
3895
|
bundle.abTestId,
|
|
3180
3896
|
bundle.id
|
|
3181
3897
|
);
|
|
3182
3898
|
if (assignment?.variant === "B") {
|
|
3183
|
-
return (0,
|
|
3899
|
+
return (0, import_core7.applyABVariantB)(bundle);
|
|
3184
3900
|
}
|
|
3185
3901
|
} catch (err) {
|
|
3186
3902
|
console.warn(
|
|
@@ -3195,7 +3911,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3195
3911
|
}
|
|
3196
3912
|
async fetchSingleBundle(client, signal) {
|
|
3197
3913
|
const data = await client.query(
|
|
3198
|
-
|
|
3914
|
+
import_core7.BUNDLE_METAOBJECT_QUERY,
|
|
3199
3915
|
{ id: this.bundleGid },
|
|
3200
3916
|
{ signal }
|
|
3201
3917
|
);
|
|
@@ -3203,7 +3919,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3203
3919
|
this.bundles = [];
|
|
3204
3920
|
return;
|
|
3205
3921
|
}
|
|
3206
|
-
const parsed = (0,
|
|
3922
|
+
const parsed = (0, import_core7.parseMetaobjectBundle)(
|
|
3207
3923
|
data.metaobject.id,
|
|
3208
3924
|
data.metaobject.fields
|
|
3209
3925
|
);
|
|
@@ -3211,7 +3927,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3211
3927
|
}
|
|
3212
3928
|
async fetchProductBundles(client, signal, productHandle) {
|
|
3213
3929
|
const data = await client.query(
|
|
3214
|
-
|
|
3930
|
+
import_core7.BUNDLES_FOR_PRODUCT_QUERY,
|
|
3215
3931
|
{ handle: productHandle },
|
|
3216
3932
|
{ signal }
|
|
3217
3933
|
);
|
|
@@ -3222,7 +3938,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3222
3938
|
const refs = data.product.metafield?.references?.nodes ?? [];
|
|
3223
3939
|
const bundles = [];
|
|
3224
3940
|
for (const ref of refs) {
|
|
3225
|
-
const parsed = (0,
|
|
3941
|
+
const parsed = (0, import_core7.parseMetaobjectBundle)(ref.id, ref.fields);
|
|
3226
3942
|
if (parsed) bundles.push(parsed);
|
|
3227
3943
|
}
|
|
3228
3944
|
this.bundles = bundles;
|
|
@@ -3255,7 +3971,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3255
3971
|
*/
|
|
3256
3972
|
async defaultAddToCart(lines) {
|
|
3257
3973
|
if (typeof window === "undefined") return;
|
|
3258
|
-
const client = (0,
|
|
3974
|
+
const client = (0, import_core7.createStorefrontClient)({
|
|
3259
3975
|
shopDomain: this.shopDomain,
|
|
3260
3976
|
accessToken: this.storefrontToken
|
|
3261
3977
|
});
|
|
@@ -3266,7 +3982,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3266
3982
|
let checkoutUrl = null;
|
|
3267
3983
|
if (existingCartId) {
|
|
3268
3984
|
const res = await client.query(
|
|
3269
|
-
|
|
3985
|
+
import_core7.CART_LINES_ADD_MUTATION,
|
|
3270
3986
|
{ cartId: existingCartId, lines }
|
|
3271
3987
|
);
|
|
3272
3988
|
const payload = res.cartLinesAdd;
|
|
@@ -3278,7 +3994,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3278
3994
|
}
|
|
3279
3995
|
if (!checkoutUrl) {
|
|
3280
3996
|
const res = await client.query(
|
|
3281
|
-
|
|
3997
|
+
import_core7.CART_CREATE_MUTATION,
|
|
3282
3998
|
{ input: { lines } }
|
|
3283
3999
|
);
|
|
3284
4000
|
const payload = res.cartCreate;
|
|
@@ -3324,7 +4040,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3324
4040
|
const price = variant ? parseFloat(variant.price.amount) : 0;
|
|
3325
4041
|
return sum + price * line.quantity;
|
|
3326
4042
|
}, 0);
|
|
3327
|
-
(0,
|
|
4043
|
+
(0, import_core7.reportAddToCart)(
|
|
3328
4044
|
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
3329
4045
|
{
|
|
3330
4046
|
bundleGid: bundle.id,
|
|
@@ -3344,7 +4060,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3344
4060
|
BUNDLE_BASE_CSS,
|
|
3345
4061
|
BUNDLE_FIXED_CSS,
|
|
3346
4062
|
BUNDLE_MIX_MATCH_CSS,
|
|
3347
|
-
BUNDLE_VOLUME_CSS
|
|
4063
|
+
BUNDLE_VOLUME_CSS,
|
|
4064
|
+
BUNDLE_DROPDOWN_CSS
|
|
3348
4065
|
].join("\n");
|
|
3349
4066
|
this.shadow.appendChild(style);
|
|
3350
4067
|
if (this.shopCustomCss) {
|
|
@@ -3360,7 +4077,7 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3360
4077
|
container.setAttribute("aria-label", bundle.title);
|
|
3361
4078
|
container.setAttribute("data-bundle-type", bundle.bundleType);
|
|
3362
4079
|
container.setAttribute("data-bundle-gid", bundle.id);
|
|
3363
|
-
(0,
|
|
4080
|
+
(0, import_core8.applyWidgetConfigVars)(container, bundle.widgetConfig);
|
|
3364
4081
|
this.renderCleanups.push(trackInputMode(container));
|
|
3365
4082
|
const dispatch = (lines) => this.handleAddToCart(bundle, lines);
|
|
3366
4083
|
const registerCleanup = (fn) => this.renderCleanups.push(fn);
|
|
@@ -3396,8 +4113,8 @@ var LimeBundleElement = class extends HTMLElement {
|
|
|
3396
4113
|
}
|
|
3397
4114
|
setupImpressionFor(bundle, element) {
|
|
3398
4115
|
if (!this.analyticsEnabled || !this.appUrl) return;
|
|
3399
|
-
const cleanup = (0,
|
|
3400
|
-
(0,
|
|
4116
|
+
const cleanup = (0, import_core7.observeImpression)(element, () => {
|
|
4117
|
+
(0, import_core7.reportImpression)(
|
|
3401
4118
|
{ shopDomain: this.shopDomain, appUrl: this.appUrl },
|
|
3402
4119
|
{
|
|
3403
4120
|
bundleGid: bundle.id,
|