@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.js
CHANGED
|
@@ -21,6 +21,383 @@ import {
|
|
|
21
21
|
resolveBundleQty
|
|
22
22
|
} from "@lime-bundles/core";
|
|
23
23
|
|
|
24
|
+
// src/dropdown/bind-dropdown.ts
|
|
25
|
+
import { dropdown } from "@lime-bundles/core";
|
|
26
|
+
var { computePosition, emptyTypeAheadState, handleKey, pushTypeAheadChar } = dropdown;
|
|
27
|
+
var ITEM_HEIGHT_PX = 32;
|
|
28
|
+
var LIST_PAD_Y = 8;
|
|
29
|
+
var MAX_VISIBLE_ITEMS = 8;
|
|
30
|
+
var openInstances = [];
|
|
31
|
+
function closeOutsideEvent(event) {
|
|
32
|
+
const path = event.composedPath();
|
|
33
|
+
for (let i = openInstances.length - 1; i >= 0; i--) {
|
|
34
|
+
const inst = openInstances[i];
|
|
35
|
+
if (!path.includes(inst.shell) && !path.includes(inst.listbox)) {
|
|
36
|
+
inst.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function onDocResize() {
|
|
41
|
+
for (let i = openInstances.length - 1; i >= 0; i--) openInstances[i].close();
|
|
42
|
+
}
|
|
43
|
+
var docListenersAttached = false;
|
|
44
|
+
function attachDocumentListeners() {
|
|
45
|
+
if (docListenersAttached) return;
|
|
46
|
+
document.addEventListener("pointerdown", closeOutsideEvent, true);
|
|
47
|
+
window.addEventListener("scroll", closeOutsideEvent, true);
|
|
48
|
+
window.addEventListener("resize", onDocResize);
|
|
49
|
+
docListenersAttached = true;
|
|
50
|
+
}
|
|
51
|
+
function detachDocumentListeners() {
|
|
52
|
+
if (!docListenersAttached || openInstances.length > 0) return;
|
|
53
|
+
document.removeEventListener("pointerdown", closeOutsideEvent, true);
|
|
54
|
+
window.removeEventListener("scroll", closeOutsideEvent, true);
|
|
55
|
+
window.removeEventListener("resize", onDocResize);
|
|
56
|
+
docListenersAttached = false;
|
|
57
|
+
}
|
|
58
|
+
function readOptions(select) {
|
|
59
|
+
const out = [];
|
|
60
|
+
for (let i = 0; i < select.options.length; i++) {
|
|
61
|
+
const o = select.options[i];
|
|
62
|
+
out.push({ disabled: o.disabled, label: o.textContent || o.value });
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function firstEnabled(opts) {
|
|
67
|
+
for (let i = 0; i < opts.length; i++) if (!opts[i].disabled) return i;
|
|
68
|
+
return -1;
|
|
69
|
+
}
|
|
70
|
+
var VARIANT_SELECT_CLASSES = [
|
|
71
|
+
"lb-bundle-variant-select",
|
|
72
|
+
"lb-mix-match__variant-select"
|
|
73
|
+
];
|
|
74
|
+
var BIND_SELECTOR = VARIANT_SELECT_CLASSES.map(
|
|
75
|
+
(c) => `select.${c}:not(.lb-dropdown-state)`
|
|
76
|
+
).join(", ");
|
|
77
|
+
function bindDropdown(select) {
|
|
78
|
+
const slot = select;
|
|
79
|
+
if (select.classList.contains("lb-dropdown-state")) {
|
|
80
|
+
return slot.__lbDropdownInstance ?? null;
|
|
81
|
+
}
|
|
82
|
+
const doc = select.ownerDocument;
|
|
83
|
+
const rootNode = select.getRootNode();
|
|
84
|
+
const labelText = select.getAttribute("aria-label") ?? "";
|
|
85
|
+
const idBase = `lb-dd-${Math.random().toString(36).slice(2, 9)}`;
|
|
86
|
+
select.classList.add("lb-dropdown-state");
|
|
87
|
+
select.setAttribute("aria-hidden", "true");
|
|
88
|
+
select.setAttribute("tabindex", "-1");
|
|
89
|
+
const shell = doc.createElement("div");
|
|
90
|
+
shell.className = "lb-dropdown";
|
|
91
|
+
shell.setAttribute("data-lb-dropdown", "");
|
|
92
|
+
const trigger = doc.createElement("button");
|
|
93
|
+
trigger.type = "button";
|
|
94
|
+
trigger.className = "lb-dropdown-trigger";
|
|
95
|
+
trigger.setAttribute("role", "combobox");
|
|
96
|
+
trigger.setAttribute("aria-haspopup", "listbox");
|
|
97
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
98
|
+
const listboxId = `${idBase}-listbox`;
|
|
99
|
+
trigger.setAttribute("aria-controls", listboxId);
|
|
100
|
+
if (labelText) trigger.setAttribute("aria-label", labelText);
|
|
101
|
+
const triggerLabel = doc.createElement("span");
|
|
102
|
+
triggerLabel.className = "lb-dropdown-trigger-value";
|
|
103
|
+
const chevron = doc.createElement("span");
|
|
104
|
+
chevron.className = "lb-dropdown-chevron";
|
|
105
|
+
chevron.setAttribute("aria-hidden", "true");
|
|
106
|
+
trigger.appendChild(triggerLabel);
|
|
107
|
+
trigger.appendChild(chevron);
|
|
108
|
+
const listbox = doc.createElement("ul");
|
|
109
|
+
listbox.id = listboxId;
|
|
110
|
+
listbox.className = "lb-dropdown-listbox";
|
|
111
|
+
listbox.setAttribute("role", "listbox");
|
|
112
|
+
if (labelText) listbox.setAttribute("aria-label", labelText);
|
|
113
|
+
listbox.hidden = true;
|
|
114
|
+
shell.appendChild(trigger);
|
|
115
|
+
select.parentNode?.insertBefore(shell, select.nextSibling);
|
|
116
|
+
const modalOverlay = select.closest("[data-modal-overlay]");
|
|
117
|
+
if (modalOverlay) {
|
|
118
|
+
modalOverlay.appendChild(listbox);
|
|
119
|
+
listbox.setAttribute("data-lb-dropdown-portal", "");
|
|
120
|
+
} else {
|
|
121
|
+
shell.appendChild(listbox);
|
|
122
|
+
}
|
|
123
|
+
let isOpen = false;
|
|
124
|
+
let activeIndex = -1;
|
|
125
|
+
let typeAhead = emptyTypeAheadState();
|
|
126
|
+
let optionEls = [];
|
|
127
|
+
let instance;
|
|
128
|
+
function syncFromSelect() {
|
|
129
|
+
const opts = readOptions(select);
|
|
130
|
+
const idx = select.selectedIndex;
|
|
131
|
+
triggerLabel.textContent = idx >= 0 && opts[idx] ? opts[idx].label : "";
|
|
132
|
+
while (listbox.firstChild) listbox.removeChild(listbox.firstChild);
|
|
133
|
+
optionEls = [];
|
|
134
|
+
for (let i = 0; i < opts.length; i++) {
|
|
135
|
+
const li = doc.createElement("li");
|
|
136
|
+
li.id = `${idBase}-opt-${i}`;
|
|
137
|
+
li.className = "lb-dropdown-option";
|
|
138
|
+
li.setAttribute("role", "option");
|
|
139
|
+
li.setAttribute("aria-selected", i === idx ? "true" : "false");
|
|
140
|
+
if (opts[i].disabled) li.setAttribute("aria-disabled", "true");
|
|
141
|
+
li.setAttribute("data-value", select.options[i].value);
|
|
142
|
+
li.setAttribute("data-index", String(i));
|
|
143
|
+
li.textContent = opts[i].label;
|
|
144
|
+
listbox.appendChild(li);
|
|
145
|
+
optionEls.push(li);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function setActive(newIndex) {
|
|
149
|
+
if (activeIndex >= 0 && optionEls[activeIndex]) {
|
|
150
|
+
optionEls[activeIndex].classList.remove("is-active");
|
|
151
|
+
}
|
|
152
|
+
activeIndex = newIndex;
|
|
153
|
+
if (newIndex >= 0 && optionEls[newIndex]) {
|
|
154
|
+
const li = optionEls[newIndex];
|
|
155
|
+
li.classList.add("is-active");
|
|
156
|
+
trigger.setAttribute("aria-activedescendant", li.id);
|
|
157
|
+
const liTop = li.offsetTop;
|
|
158
|
+
const liBottom = liTop + li.offsetHeight;
|
|
159
|
+
const visTop = listbox.scrollTop;
|
|
160
|
+
const visBottom = visTop + listbox.clientHeight;
|
|
161
|
+
if (liTop < visTop) {
|
|
162
|
+
listbox.scrollTop = liTop;
|
|
163
|
+
} else if (liBottom > visBottom) {
|
|
164
|
+
listbox.scrollTop = liBottom - listbox.clientHeight;
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
trigger.setAttribute("aria-activedescendant", "");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function position() {
|
|
171
|
+
const rect = trigger.getBoundingClientRect();
|
|
172
|
+
if (rect.width === 0) return false;
|
|
173
|
+
const visibleCount = Math.min(optionEls.length || 1, MAX_VISIBLE_ITEMS);
|
|
174
|
+
const desiredHeight = visibleCount * ITEM_HEIGHT_PX + LIST_PAD_Y;
|
|
175
|
+
const result = computePosition({
|
|
176
|
+
trigger: {
|
|
177
|
+
top: rect.top,
|
|
178
|
+
bottom: rect.bottom,
|
|
179
|
+
left: rect.left,
|
|
180
|
+
width: rect.width
|
|
181
|
+
},
|
|
182
|
+
viewportHeight: window.innerHeight,
|
|
183
|
+
desiredHeight
|
|
184
|
+
});
|
|
185
|
+
listbox.setAttribute("data-placement", result.placement);
|
|
186
|
+
listbox.style.maxHeight = `${result.maxHeight}px`;
|
|
187
|
+
if (listbox.hasAttribute("data-lb-dropdown-portal")) {
|
|
188
|
+
listbox.style.top = `${result.offsetTop}px`;
|
|
189
|
+
listbox.style.left = `${result.offsetLeft}px`;
|
|
190
|
+
listbox.style.width = `${result.width}px`;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
function open() {
|
|
195
|
+
if (isOpen) return;
|
|
196
|
+
for (let i = openInstances.length - 1; i >= 0; i--) {
|
|
197
|
+
if (openInstances[i] !== instance) openInstances[i].close();
|
|
198
|
+
}
|
|
199
|
+
isOpen = true;
|
|
200
|
+
listbox.hidden = false;
|
|
201
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
202
|
+
if (!position()) {
|
|
203
|
+
requestAnimationFrame(() => position());
|
|
204
|
+
}
|
|
205
|
+
const opts = readOptions(select);
|
|
206
|
+
const selIdx = select.selectedIndex;
|
|
207
|
+
if (selIdx >= 0 && opts[selIdx] && !opts[selIdx].disabled) {
|
|
208
|
+
setActive(selIdx);
|
|
209
|
+
} else {
|
|
210
|
+
setActive(firstEnabled(opts));
|
|
211
|
+
}
|
|
212
|
+
openInstances.push(instance);
|
|
213
|
+
if (openInstances.length === 1) attachDocumentListeners();
|
|
214
|
+
}
|
|
215
|
+
function close(restoreFocus) {
|
|
216
|
+
if (!isOpen) return;
|
|
217
|
+
isOpen = false;
|
|
218
|
+
listbox.hidden = true;
|
|
219
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
220
|
+
trigger.setAttribute("aria-activedescendant", "");
|
|
221
|
+
if (activeIndex >= 0 && optionEls[activeIndex]) {
|
|
222
|
+
optionEls[activeIndex].classList.remove("is-active");
|
|
223
|
+
}
|
|
224
|
+
activeIndex = -1;
|
|
225
|
+
const idx = openInstances.indexOf(instance);
|
|
226
|
+
if (idx >= 0) openInstances.splice(idx, 1);
|
|
227
|
+
if (openInstances.length === 0) detachDocumentListeners();
|
|
228
|
+
if (restoreFocus) trigger.focus();
|
|
229
|
+
}
|
|
230
|
+
function commit(index) {
|
|
231
|
+
const opt = select.options[index];
|
|
232
|
+
if (!opt || opt.disabled) return;
|
|
233
|
+
if (select.value !== opt.value) {
|
|
234
|
+
select.value = opt.value;
|
|
235
|
+
const event = new Event("change", { bubbles: true });
|
|
236
|
+
select.dispatchEvent(event);
|
|
237
|
+
}
|
|
238
|
+
syncFromSelect();
|
|
239
|
+
close(true);
|
|
240
|
+
}
|
|
241
|
+
function applyAction(action) {
|
|
242
|
+
switch (action.type) {
|
|
243
|
+
case "open":
|
|
244
|
+
open();
|
|
245
|
+
if (action.activeIndex >= 0) setActive(action.activeIndex);
|
|
246
|
+
return;
|
|
247
|
+
case "close":
|
|
248
|
+
close(action.restoreFocus);
|
|
249
|
+
return;
|
|
250
|
+
case "move-active":
|
|
251
|
+
setActive(action.activeIndex);
|
|
252
|
+
return;
|
|
253
|
+
case "commit":
|
|
254
|
+
commit(action.index);
|
|
255
|
+
return;
|
|
256
|
+
case "type-ahead": {
|
|
257
|
+
const opts = readOptions(select);
|
|
258
|
+
const result = pushTypeAheadChar(
|
|
259
|
+
typeAhead,
|
|
260
|
+
action.char,
|
|
261
|
+
Date.now(),
|
|
262
|
+
opts
|
|
263
|
+
);
|
|
264
|
+
typeAhead = result.newState;
|
|
265
|
+
if (result.matchedIndex !== null) {
|
|
266
|
+
if (!isOpen) open();
|
|
267
|
+
setActive(result.matchedIndex);
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
case "passthrough":
|
|
272
|
+
return;
|
|
273
|
+
default: {
|
|
274
|
+
const _exhaustive = action;
|
|
275
|
+
void _exhaustive;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function onKeydown(event) {
|
|
280
|
+
const opts = readOptions(select);
|
|
281
|
+
const action = handleKey(
|
|
282
|
+
{
|
|
283
|
+
key: event.key,
|
|
284
|
+
ctrlKey: event.ctrlKey,
|
|
285
|
+
metaKey: event.metaKey,
|
|
286
|
+
altKey: event.altKey,
|
|
287
|
+
shiftKey: event.shiftKey
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
isOpen,
|
|
291
|
+
activeIndex,
|
|
292
|
+
selectedIndex: select.selectedIndex,
|
|
293
|
+
options: opts
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
if (action.preventDefault) event.preventDefault();
|
|
297
|
+
applyAction(action);
|
|
298
|
+
}
|
|
299
|
+
function onTriggerClick(event) {
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
if (isOpen) close(false);
|
|
302
|
+
else open();
|
|
303
|
+
}
|
|
304
|
+
function onListboxClick(event) {
|
|
305
|
+
let target = event.target;
|
|
306
|
+
while (target && target !== listbox) {
|
|
307
|
+
if (target.classList?.contains("lb-dropdown-option")) {
|
|
308
|
+
const idx = parseInt(target.getAttribute("data-index") ?? "", 10);
|
|
309
|
+
if (!Number.isNaN(idx)) {
|
|
310
|
+
commit(idx);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
target = target.parentElement;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function onListboxMousemove(event) {
|
|
318
|
+
let target = event.target;
|
|
319
|
+
while (target && target !== listbox) {
|
|
320
|
+
if (target.classList?.contains("lb-dropdown-option")) {
|
|
321
|
+
if (target.getAttribute("aria-disabled") === "true") return;
|
|
322
|
+
const idx = parseInt(target.getAttribute("data-index") ?? "", 10);
|
|
323
|
+
if (!Number.isNaN(idx) && idx !== activeIndex) setActive(idx);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
target = target.parentElement;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function onShellFocusout() {
|
|
330
|
+
setTimeout(() => {
|
|
331
|
+
if (!isOpen) return;
|
|
332
|
+
const active = rootNode.activeElement ?? doc.activeElement;
|
|
333
|
+
if (!shell.contains(active)) close(false);
|
|
334
|
+
}, 0);
|
|
335
|
+
}
|
|
336
|
+
function onSelectChange() {
|
|
337
|
+
syncFromSelect();
|
|
338
|
+
}
|
|
339
|
+
const observer = new MutationObserver(() => {
|
|
340
|
+
syncFromSelect();
|
|
341
|
+
});
|
|
342
|
+
observer.observe(select, {
|
|
343
|
+
childList: true,
|
|
344
|
+
subtree: true,
|
|
345
|
+
attributes: true,
|
|
346
|
+
attributeFilter: ["disabled", "value", "selected"]
|
|
347
|
+
});
|
|
348
|
+
const onListboxMousedown = (event) => event.preventDefault();
|
|
349
|
+
trigger.addEventListener("click", onTriggerClick);
|
|
350
|
+
trigger.addEventListener("keydown", onKeydown);
|
|
351
|
+
shell.addEventListener("focusout", onShellFocusout);
|
|
352
|
+
listbox.addEventListener("mousedown", onListboxMousedown);
|
|
353
|
+
listbox.addEventListener("click", onListboxClick);
|
|
354
|
+
listbox.addEventListener("mousemove", onListboxMousemove);
|
|
355
|
+
select.addEventListener("change", onSelectChange);
|
|
356
|
+
function destroy() {
|
|
357
|
+
if (isOpen) close(false);
|
|
358
|
+
observer.disconnect();
|
|
359
|
+
trigger.removeEventListener("click", onTriggerClick);
|
|
360
|
+
trigger.removeEventListener("keydown", onKeydown);
|
|
361
|
+
shell.removeEventListener("focusout", onShellFocusout);
|
|
362
|
+
listbox.removeEventListener("mousedown", onListboxMousedown);
|
|
363
|
+
listbox.removeEventListener("click", onListboxClick);
|
|
364
|
+
listbox.removeEventListener("mousemove", onListboxMousemove);
|
|
365
|
+
select.removeEventListener("change", onSelectChange);
|
|
366
|
+
if (shell.parentNode) shell.parentNode.removeChild(shell);
|
|
367
|
+
if (listbox.parentNode) listbox.parentNode.removeChild(listbox);
|
|
368
|
+
select.classList.remove("lb-dropdown-state");
|
|
369
|
+
select.removeAttribute("aria-hidden");
|
|
370
|
+
select.removeAttribute("tabindex");
|
|
371
|
+
delete slot.__lbDropdownInstance;
|
|
372
|
+
}
|
|
373
|
+
instance = {
|
|
374
|
+
shell,
|
|
375
|
+
listbox,
|
|
376
|
+
select,
|
|
377
|
+
close: () => close(false),
|
|
378
|
+
destroy
|
|
379
|
+
};
|
|
380
|
+
slot.__lbDropdownInstance = instance;
|
|
381
|
+
syncFromSelect();
|
|
382
|
+
return instance;
|
|
383
|
+
}
|
|
384
|
+
function bindAllDropdowns(root) {
|
|
385
|
+
const selects = root.querySelectorAll(BIND_SELECTOR);
|
|
386
|
+
const instances = [];
|
|
387
|
+
selects.forEach((sel) => {
|
|
388
|
+
const inst = bindDropdown(sel);
|
|
389
|
+
if (inst) instances.push(inst);
|
|
390
|
+
});
|
|
391
|
+
return instances;
|
|
392
|
+
}
|
|
393
|
+
function unbindAllDropdowns(root) {
|
|
394
|
+
const bound = root.querySelectorAll("select.lb-dropdown-state");
|
|
395
|
+
bound.forEach((sel) => {
|
|
396
|
+
const inst = sel.__lbDropdownInstance;
|
|
397
|
+
if (inst) inst.destroy();
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
24
401
|
// src/renderers/pricing.ts
|
|
25
402
|
import {
|
|
26
403
|
parseCents,
|
|
@@ -192,6 +569,8 @@ 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) => {
|
|
@@ -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
|
-
|
|
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 = transformImageUrl(initialThumbImage.url, {
|
|
293
674
|
width: THUMB_PX,
|
|
294
675
|
height: 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 = THUMB_PX;
|
|
680
|
+
thumbImg.height = THUMB_PX;
|
|
681
|
+
thumbImg.loading = "lazy";
|
|
682
|
+
thumb.appendChild(thumbImg);
|
|
302
683
|
} else {
|
|
303
684
|
thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG);
|
|
304
685
|
}
|
|
@@ -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 = transformImageUrl(nextImage.url, {
|
|
749
|
+
width: THUMB_PX,
|
|
750
|
+
height: 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) {
|
|
@@ -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,7 +1027,7 @@ 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,
|
|
1030
|
+
imageUrl: firstVariant.image?.url ?? firstEligible.product.featuredImage?.url ?? null,
|
|
640
1031
|
priceCents: parseCents(firstVariant.price.amount),
|
|
641
1032
|
compareCents: firstVariant.compareAtPrice ? parseCents(firstVariant.compareAtPrice.amount) : null,
|
|
642
1033
|
unitPriceLabel: formatUnitPrice(
|
|
@@ -655,7 +1046,7 @@ 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,
|
|
1049
|
+
imageUrl: variant.image?.url ?? product.featuredImage?.url ?? null,
|
|
659
1050
|
priceCents: parseCents(variant.price.amount),
|
|
660
1051
|
compareCents: variant.compareAtPrice ? parseCents(variant.compareAtPrice.amount) : null,
|
|
661
1052
|
unitPriceLabel: formatUnitPrice(
|
|
@@ -1030,18 +1421,21 @@ 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
|
-
|
|
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 = transformImageUrl(initialThumbImage.url, {
|
|
1036
1430
|
width: THUMB_PX,
|
|
1037
1431
|
height: 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 = THUMB_PX;
|
|
1436
|
+
thumbImg.height = THUMB_PX;
|
|
1437
|
+
thumbImg.loading = "lazy";
|
|
1438
|
+
thumb.appendChild(thumbImg);
|
|
1045
1439
|
} else {
|
|
1046
1440
|
thumb.insertAdjacentHTML("beforeend", PLACEHOLDER_THUMB_SVG2);
|
|
1047
1441
|
}
|
|
@@ -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 = transformImageUrl(nextImage.url, {
|
|
1545
|
+
width: THUMB_PX,
|
|
1546
|
+
height: 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
|
};
|
|
@@ -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() {
|
|
@@ -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
|
|
|
@@ -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) {
|