@magic-spells/cart-panel 0.1.2 → 0.2.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/README.md +381 -190
- package/dist/cart-panel.cjs.css +2 -9
- package/dist/cart-panel.cjs.js +185 -77
- package/dist/cart-panel.cjs.js.map +1 -1
- package/dist/cart-panel.css +2 -9
- package/dist/cart-panel.esm.css +2 -9
- package/dist/cart-panel.esm.js +185 -77
- package/dist/cart-panel.esm.js.map +1 -1
- package/dist/cart-panel.js +1637 -1254
- package/dist/cart-panel.js.map +1 -1
- package/dist/cart-panel.min.css +1 -1
- package/dist/cart-panel.min.js +1 -1
- package/dist/cart-panel.scss +2 -12
- package/package.json +2 -2
- package/src/cart-panel.js +185 -78
- package/src/cart-panel.scss +2 -12
package/dist/cart-panel.esm.js
CHANGED
|
@@ -9,7 +9,6 @@ import EventEmitter from '@magic-spells/event-emitter';
|
|
|
9
9
|
*/
|
|
10
10
|
class CartDialog extends HTMLElement {
|
|
11
11
|
#handleTransitionEnd;
|
|
12
|
-
#scrollPosition = 0;
|
|
13
12
|
#currentCart = null;
|
|
14
13
|
#eventEmitter;
|
|
15
14
|
#isInitialRender = true;
|
|
@@ -32,31 +31,21 @@ class CartDialog extends HTMLElement {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
|
-
*
|
|
34
|
+
* Locks body scrolling
|
|
36
35
|
* @private
|
|
37
36
|
*/
|
|
38
37
|
#lockScroll() {
|
|
39
|
-
|
|
40
|
-
// Save current scroll position
|
|
41
|
-
_.#scrollPosition = window.pageYOffset;
|
|
42
|
-
|
|
43
|
-
// Apply fixed position to body
|
|
38
|
+
// Apply overflow hidden to body
|
|
44
39
|
document.body.classList.add('overflow-hidden');
|
|
45
|
-
document.body.style.top = `-${_.#scrollPosition}px`;
|
|
46
40
|
}
|
|
47
41
|
|
|
48
42
|
/**
|
|
49
|
-
* Restores
|
|
43
|
+
* Restores body scrolling when cart dialog is closed
|
|
50
44
|
* @private
|
|
51
45
|
*/
|
|
52
46
|
#restoreScroll() {
|
|
53
|
-
|
|
54
|
-
// Remove fixed positioning
|
|
47
|
+
// Remove overflow hidden from body
|
|
55
48
|
document.body.classList.remove('overflow-hidden');
|
|
56
|
-
document.body.style.removeProperty('top');
|
|
57
|
-
|
|
58
|
-
// Restore scroll position
|
|
59
|
-
window.scrollTo(0, _.#scrollPosition);
|
|
60
49
|
}
|
|
61
50
|
|
|
62
51
|
/**
|
|
@@ -97,7 +86,18 @@ class CartDialog extends HTMLElement {
|
|
|
97
86
|
return;
|
|
98
87
|
}
|
|
99
88
|
|
|
100
|
-
|
|
89
|
+
// Check if focus-trap already exists, if not create one
|
|
90
|
+
_.focusTrap = _.contentPanel.querySelector('focus-trap');
|
|
91
|
+
if (!_.focusTrap) {
|
|
92
|
+
_.focusTrap = document.createElement('focus-trap');
|
|
93
|
+
|
|
94
|
+
// Move all existing cart-panel content into the focus trap
|
|
95
|
+
const existingContent = Array.from(_.contentPanel.childNodes);
|
|
96
|
+
existingContent.forEach((child) => _.focusTrap.appendChild(child));
|
|
97
|
+
|
|
98
|
+
// Insert focus trap inside the cart-panel
|
|
99
|
+
_.contentPanel.appendChild(_.focusTrap);
|
|
100
|
+
}
|
|
101
101
|
|
|
102
102
|
// Ensure we have labelledby and describedby references
|
|
103
103
|
if (!_.getAttribute('aria-labelledby')) {
|
|
@@ -110,20 +110,15 @@ class CartDialog extends HTMLElement {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
// Insert focus trap before the cart-panel
|
|
114
|
-
_.contentPanel.parentNode.insertBefore(_.focusTrap, _.contentPanel);
|
|
115
|
-
// Move cart-panel inside the focus trap
|
|
116
|
-
_.focusTrap.appendChild(_.contentPanel);
|
|
117
|
-
|
|
118
|
-
// Setup the trap - this will add focus-trap-start/end elements around the content
|
|
119
|
-
_.focusTrap.setupTrap();
|
|
120
|
-
|
|
121
113
|
// Add modal overlay if it doesn't already exist
|
|
122
114
|
if (!_.querySelector('cart-overlay')) {
|
|
123
115
|
_.prepend(document.createElement('cart-overlay'));
|
|
124
116
|
}
|
|
125
117
|
_.#attachListeners();
|
|
126
118
|
_.#bindKeyboard();
|
|
119
|
+
|
|
120
|
+
// Load cart data immediately after component initialization
|
|
121
|
+
_.refreshCart();
|
|
127
122
|
}
|
|
128
123
|
|
|
129
124
|
/**
|
|
@@ -156,6 +151,14 @@ class CartDialog extends HTMLElement {
|
|
|
156
151
|
*/
|
|
157
152
|
#emit(eventName, data = null) {
|
|
158
153
|
this.#eventEmitter.emit(eventName, data);
|
|
154
|
+
|
|
155
|
+
// Also emit as native DOM events for better compatibility
|
|
156
|
+
this.dispatchEvent(
|
|
157
|
+
new CustomEvent(eventName, {
|
|
158
|
+
detail: data,
|
|
159
|
+
bubbles: true,
|
|
160
|
+
})
|
|
161
|
+
);
|
|
159
162
|
}
|
|
160
163
|
|
|
161
164
|
/**
|
|
@@ -237,11 +240,12 @@ class CartDialog extends HTMLElement {
|
|
|
237
240
|
// Success - let smart comparison handle the removal animation
|
|
238
241
|
this.#currentCart = updatedCart;
|
|
239
242
|
this.#renderCartItems(updatedCart);
|
|
240
|
-
this.#
|
|
243
|
+
this.#renderCartPanel(updatedCart);
|
|
241
244
|
|
|
242
245
|
// Emit cart updated and data changed events
|
|
243
|
-
this.#
|
|
244
|
-
this.#emit('cart-dialog:
|
|
246
|
+
const cartWithCalculatedFields = this.#addCalculatedFields(updatedCart);
|
|
247
|
+
this.#emit('cart-dialog:updated', { cart: cartWithCalculatedFields });
|
|
248
|
+
this.#emit('cart-dialog:data-changed', cartWithCalculatedFields);
|
|
245
249
|
} else {
|
|
246
250
|
// Error - reset to ready state
|
|
247
251
|
element.setState('ready');
|
|
@@ -272,12 +276,13 @@ class CartDialog extends HTMLElement {
|
|
|
272
276
|
// Success - update cart data and refresh items
|
|
273
277
|
this.#currentCart = updatedCart;
|
|
274
278
|
this.#renderCartItems(updatedCart);
|
|
275
|
-
this.#
|
|
279
|
+
this.#renderCartPanel(updatedCart);
|
|
276
280
|
element.setState('ready');
|
|
277
281
|
|
|
278
282
|
// Emit cart updated and data changed events
|
|
279
|
-
this.#
|
|
280
|
-
this.#emit('cart-dialog:
|
|
283
|
+
const cartWithCalculatedFields = this.#addCalculatedFields(updatedCart);
|
|
284
|
+
this.#emit('cart-dialog:updated', { cart: cartWithCalculatedFields });
|
|
285
|
+
this.#emit('cart-dialog:data-changed', cartWithCalculatedFields);
|
|
281
286
|
} else {
|
|
282
287
|
// Error - reset to ready state
|
|
283
288
|
element.setState('ready');
|
|
@@ -291,11 +296,52 @@ class CartDialog extends HTMLElement {
|
|
|
291
296
|
});
|
|
292
297
|
}
|
|
293
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Update cart count elements across the site
|
|
301
|
+
* @private
|
|
302
|
+
*/
|
|
303
|
+
#renderCartCount(cartData) {
|
|
304
|
+
if (!cartData) return;
|
|
305
|
+
|
|
306
|
+
// Calculate visible item count (excluding _hide_in_cart items)
|
|
307
|
+
const visibleItems = this.#getVisibleCartItems(cartData);
|
|
308
|
+
const visibleItemCount = visibleItems.reduce((total, item) => total + item.quantity, 0);
|
|
309
|
+
|
|
310
|
+
// Update all cart count elements across the site
|
|
311
|
+
const cartCountElements = document.querySelectorAll('[data-content-cart-count]');
|
|
312
|
+
cartCountElements.forEach((element) => {
|
|
313
|
+
element.textContent = visibleItemCount;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Update cart subtotal elements across the site
|
|
319
|
+
* @private
|
|
320
|
+
*/
|
|
321
|
+
#renderCartSubtotal(cartData) {
|
|
322
|
+
if (!cartData) return;
|
|
323
|
+
|
|
324
|
+
// Calculate subtotal from all items except those marked to ignore pricing
|
|
325
|
+
const pricedItems = cartData.items.filter(item => {
|
|
326
|
+
const ignorePrice = item.properties?._ignore_price_in_subtotal;
|
|
327
|
+
return !ignorePrice;
|
|
328
|
+
});
|
|
329
|
+
const subtotal = pricedItems.reduce((total, item) => total + (item.line_price || 0), 0);
|
|
330
|
+
|
|
331
|
+
// Update all cart subtotal elements across the site
|
|
332
|
+
const cartSubtotalElements = document.querySelectorAll('[data-content-cart-subtotal]');
|
|
333
|
+
cartSubtotalElements.forEach((element) => {
|
|
334
|
+
// Format as currency (assuming cents, convert to dollars)
|
|
335
|
+
const formatted = (subtotal / 100).toFixed(2);
|
|
336
|
+
element.textContent = `$${formatted}`;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
294
340
|
/**
|
|
295
341
|
* Update cart items display based on cart data
|
|
296
342
|
* @private
|
|
297
343
|
*/
|
|
298
|
-
#
|
|
344
|
+
#renderCartPanel(cart = null) {
|
|
299
345
|
const cartData = cart || this.#currentCart;
|
|
300
346
|
if (!cartData) return;
|
|
301
347
|
|
|
@@ -311,14 +357,22 @@ class CartDialog extends HTMLElement {
|
|
|
311
357
|
return;
|
|
312
358
|
}
|
|
313
359
|
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
360
|
+
// Check visible item count for showing/hiding sections
|
|
361
|
+
const visibleItems = this.#getVisibleCartItems(cartData);
|
|
362
|
+
const hasVisibleItems = visibleItems.length > 0;
|
|
363
|
+
|
|
364
|
+
// Show/hide sections based on visible item count
|
|
365
|
+
if (hasVisibleItems) {
|
|
366
|
+
hasItemsSection.style.display = '';
|
|
317
367
|
emptySection.style.display = 'none';
|
|
318
368
|
} else {
|
|
319
369
|
hasItemsSection.style.display = 'none';
|
|
320
|
-
emptySection.style.display = '
|
|
370
|
+
emptySection.style.display = '';
|
|
321
371
|
}
|
|
372
|
+
|
|
373
|
+
// Update cart count and subtotal across the site
|
|
374
|
+
this.#renderCartCount(cartData);
|
|
375
|
+
this.#renderCartSubtotal(cartData);
|
|
322
376
|
}
|
|
323
377
|
|
|
324
378
|
/**
|
|
@@ -370,20 +424,37 @@ class CartDialog extends HTMLElement {
|
|
|
370
424
|
|
|
371
425
|
/**
|
|
372
426
|
* Refresh cart data from server and update components
|
|
427
|
+
* @param {Object} [cartObj=null] - Optional cart object to use instead of fetching
|
|
373
428
|
* @returns {Promise<Object>} Cart data object
|
|
374
429
|
*/
|
|
375
|
-
refreshCart() {
|
|
376
|
-
|
|
430
|
+
refreshCart(cartObj = null) {
|
|
431
|
+
// If cart object is provided, use it directly
|
|
432
|
+
if (cartObj && !cartObj.error) {
|
|
433
|
+
// console.log('Using provided cart data:', cartObj);
|
|
434
|
+
this.#currentCart = cartObj;
|
|
435
|
+
this.#renderCartItems(cartObj);
|
|
436
|
+
this.#renderCartPanel(cartObj);
|
|
437
|
+
|
|
438
|
+
// Emit cart refreshed and data changed events
|
|
439
|
+
const cartWithCalculatedFields = this.#addCalculatedFields(cartObj);
|
|
440
|
+
this.#emit('cart-dialog:refreshed', { cart: cartWithCalculatedFields });
|
|
441
|
+
this.#emit('cart-dialog:data-changed', cartWithCalculatedFields);
|
|
442
|
+
|
|
443
|
+
return Promise.resolve(cartObj);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Otherwise fetch from server
|
|
377
447
|
return this.getCart().then((cartData) => {
|
|
378
|
-
console.log('Cart data received:', cartData);
|
|
448
|
+
// console.log('Cart data received:', cartData);
|
|
379
449
|
if (cartData && !cartData.error) {
|
|
380
450
|
this.#currentCart = cartData;
|
|
381
451
|
this.#renderCartItems(cartData);
|
|
382
|
-
this.#
|
|
452
|
+
this.#renderCartPanel(cartData);
|
|
383
453
|
|
|
384
454
|
// Emit cart refreshed and data changed events
|
|
385
|
-
this.#
|
|
386
|
-
this.#emit('cart-dialog:
|
|
455
|
+
const cartWithCalculatedFields = this.#addCalculatedFields(cartData);
|
|
456
|
+
this.#emit('cart-dialog:refreshed', { cart: cartWithCalculatedFields });
|
|
457
|
+
this.#emit('cart-dialog:data-changed', cartWithCalculatedFields);
|
|
387
458
|
} else {
|
|
388
459
|
console.warn('Cart data has error or is null:', cartData);
|
|
389
460
|
}
|
|
@@ -397,14 +468,11 @@ class CartDialog extends HTMLElement {
|
|
|
397
468
|
*/
|
|
398
469
|
#removeItemsFromDOM(itemsContainer, newKeysSet) {
|
|
399
470
|
const currentItems = Array.from(itemsContainer.querySelectorAll('cart-item'));
|
|
400
|
-
const itemsToRemove = currentItems.filter((item) => !newKeysSet.has(item.getAttribute('key')));
|
|
401
471
|
|
|
402
|
-
|
|
403
|
-
`Removing ${itemsToRemove.length} items:`,
|
|
404
|
-
itemsToRemove.map((item) => item.getAttribute('key'))
|
|
405
|
-
);
|
|
472
|
+
const itemsToRemove = currentItems.filter((item) => !newKeysSet.has(item.getAttribute('key')));
|
|
406
473
|
|
|
407
474
|
itemsToRemove.forEach((item) => {
|
|
475
|
+
console.log('destroy yourself', item);
|
|
408
476
|
item.destroyYourself();
|
|
409
477
|
});
|
|
410
478
|
}
|
|
@@ -414,11 +482,6 @@ class CartDialog extends HTMLElement {
|
|
|
414
482
|
* @private
|
|
415
483
|
*/
|
|
416
484
|
#addItemsToDOM(itemsContainer, itemsToAdd, newKeys) {
|
|
417
|
-
console.log(
|
|
418
|
-
`Adding ${itemsToAdd.length} items:`,
|
|
419
|
-
itemsToAdd.map((item) => item.key || item.id)
|
|
420
|
-
);
|
|
421
|
-
|
|
422
485
|
// Delay adding new items by 300ms to let cart slide open first
|
|
423
486
|
setTimeout(() => {
|
|
424
487
|
itemsToAdd.forEach((itemData) => {
|
|
@@ -451,6 +514,41 @@ class CartDialog extends HTMLElement {
|
|
|
451
514
|
}, 100);
|
|
452
515
|
}
|
|
453
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Filter cart items to exclude those with _hide_in_cart property
|
|
519
|
+
* @private
|
|
520
|
+
*/
|
|
521
|
+
#getVisibleCartItems(cartData) {
|
|
522
|
+
if (!cartData || !cartData.items) return [];
|
|
523
|
+
return cartData.items.filter((item) => {
|
|
524
|
+
// Check for _hide_in_cart in various possible locations
|
|
525
|
+
const hidden = item.properties?._hide_in_cart;
|
|
526
|
+
|
|
527
|
+
return !hidden;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Add calculated fields to cart object for events
|
|
533
|
+
* @private
|
|
534
|
+
*/
|
|
535
|
+
#addCalculatedFields(cartData) {
|
|
536
|
+
if (!cartData) return cartData;
|
|
537
|
+
|
|
538
|
+
const visibleItems = this.#getVisibleCartItems(cartData);
|
|
539
|
+
const calculated_count = visibleItems.reduce((total, item) => total + item.quantity, 0);
|
|
540
|
+
const calculated_subtotal = visibleItems.reduce(
|
|
541
|
+
(total, item) => total + (item.line_price || 0),
|
|
542
|
+
0
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
...cartData,
|
|
547
|
+
calculated_count,
|
|
548
|
+
calculated_subtotal,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
454
552
|
/**
|
|
455
553
|
* Render cart items from Shopify cart data with smart comparison
|
|
456
554
|
* @private
|
|
@@ -467,53 +565,53 @@ class CartDialog extends HTMLElement {
|
|
|
467
565
|
return;
|
|
468
566
|
}
|
|
469
567
|
|
|
568
|
+
// Filter out items with _hide_in_cart property
|
|
569
|
+
const visibleItems = this.#getVisibleCartItems(cartData);
|
|
570
|
+
|
|
470
571
|
// Handle initial render - load all items without animation
|
|
471
572
|
if (this.#isInitialRender) {
|
|
472
|
-
console.log('Initial cart render:',
|
|
573
|
+
// console.log('Initial cart render:', visibleItems.length, 'visible items');
|
|
473
574
|
|
|
474
575
|
// Clear existing items
|
|
475
576
|
itemsContainer.innerHTML = '';
|
|
476
577
|
|
|
477
578
|
// Create cart-item elements without animation
|
|
478
|
-
|
|
579
|
+
visibleItems.forEach((itemData) => {
|
|
479
580
|
const cartItem = new CartItem(itemData); // No animation
|
|
581
|
+
// const cartItem = document.createElement('cart-item');
|
|
582
|
+
// cartItem.setData(itemData);
|
|
480
583
|
itemsContainer.appendChild(cartItem);
|
|
481
584
|
});
|
|
482
585
|
|
|
483
586
|
this.#isInitialRender = false;
|
|
484
|
-
|
|
587
|
+
|
|
485
588
|
return;
|
|
486
589
|
}
|
|
487
590
|
|
|
488
|
-
console.log('Smart rendering cart items:', cartData.items.length, 'items');
|
|
489
|
-
|
|
490
591
|
// Get current DOM items and their keys
|
|
491
592
|
const currentItems = Array.from(itemsContainer.querySelectorAll('cart-item'));
|
|
492
593
|
const currentKeys = new Set(currentItems.map((item) => item.getAttribute('key')));
|
|
493
594
|
|
|
494
|
-
// Get new cart data keys in order
|
|
495
|
-
const newKeys =
|
|
595
|
+
// Get new cart data keys in order (only visible items)
|
|
596
|
+
const newKeys = visibleItems.map((item) => item.key || item.id);
|
|
496
597
|
const newKeysSet = new Set(newKeys);
|
|
497
598
|
|
|
498
599
|
// Step 1: Remove items that are no longer in cart data
|
|
499
600
|
this.#removeItemsFromDOM(itemsContainer, newKeysSet);
|
|
500
601
|
|
|
501
602
|
// Step 2: Add new items that weren't in DOM (with animation delay)
|
|
502
|
-
const itemsToAdd =
|
|
603
|
+
const itemsToAdd = visibleItems.filter(
|
|
503
604
|
(itemData) => !currentKeys.has(itemData.key || itemData.id)
|
|
504
605
|
);
|
|
505
|
-
|
|
506
606
|
this.#addItemsToDOM(itemsContainer, itemsToAdd, newKeys);
|
|
507
|
-
|
|
508
|
-
console.log('Smart rendering complete, container children:', itemsContainer.children.length);
|
|
509
607
|
}
|
|
510
608
|
|
|
511
609
|
/**
|
|
512
610
|
* Set the template function for cart items
|
|
513
611
|
* @param {Function} templateFn - Function that takes item data and returns HTML string
|
|
514
612
|
*/
|
|
515
|
-
setCartItemTemplate(templateFn) {
|
|
516
|
-
CartItem.setTemplate(templateFn);
|
|
613
|
+
setCartItemTemplate(templateName, templateFn) {
|
|
614
|
+
CartItem.setTemplate(templateName, templateFn);
|
|
517
615
|
}
|
|
518
616
|
|
|
519
617
|
/**
|
|
@@ -529,10 +627,13 @@ class CartDialog extends HTMLElement {
|
|
|
529
627
|
* @param {HTMLElement} [triggerEl=null] - The element that triggered the cart dialog
|
|
530
628
|
* @fires CartDialog#show - Fired when the cart dialog has been shown
|
|
531
629
|
*/
|
|
532
|
-
show(triggerEl = null) {
|
|
630
|
+
show(triggerEl = null, cartObj) {
|
|
533
631
|
const _ = this;
|
|
534
632
|
_.triggerEl = triggerEl || false;
|
|
535
633
|
|
|
634
|
+
// Lock body scrolling
|
|
635
|
+
_.#lockScroll();
|
|
636
|
+
|
|
536
637
|
// Remove the hidden class first to ensure content is rendered
|
|
537
638
|
_.contentPanel.classList.remove('hidden');
|
|
538
639
|
|
|
@@ -540,17 +641,16 @@ class CartDialog extends HTMLElement {
|
|
|
540
641
|
requestAnimationFrame(() => {
|
|
541
642
|
// Update ARIA states
|
|
542
643
|
_.setAttribute('aria-hidden', 'false');
|
|
644
|
+
|
|
543
645
|
if (_.triggerEl) {
|
|
544
646
|
_.triggerEl.setAttribute('aria-expanded', 'true');
|
|
545
647
|
}
|
|
546
648
|
|
|
547
|
-
// Lock body scrolling and save scroll position
|
|
548
|
-
_.#lockScroll();
|
|
549
|
-
|
|
550
649
|
// Focus management
|
|
551
650
|
const firstFocusable = _.querySelector(
|
|
552
651
|
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
553
652
|
);
|
|
653
|
+
|
|
554
654
|
if (firstFocusable) {
|
|
555
655
|
requestAnimationFrame(() => {
|
|
556
656
|
firstFocusable.focus();
|
|
@@ -558,7 +658,7 @@ class CartDialog extends HTMLElement {
|
|
|
558
658
|
}
|
|
559
659
|
|
|
560
660
|
// Refresh cart data when showing
|
|
561
|
-
_.refreshCart();
|
|
661
|
+
_.refreshCart(cartObj);
|
|
562
662
|
|
|
563
663
|
// Emit show event - cart dialog is now visible
|
|
564
664
|
_.#emit('cart-dialog:show', { triggerElement: _.triggerEl });
|
|
@@ -573,23 +673,31 @@ class CartDialog extends HTMLElement {
|
|
|
573
673
|
hide() {
|
|
574
674
|
const _ = this;
|
|
575
675
|
|
|
576
|
-
// Restore body scroll and scroll position
|
|
577
|
-
_.#restoreScroll();
|
|
578
|
-
|
|
579
676
|
// Update ARIA states
|
|
580
677
|
if (_.triggerEl) {
|
|
581
678
|
// remove focus from modal panel first
|
|
582
679
|
_.triggerEl.focus();
|
|
583
680
|
// mark trigger as no longer expanded
|
|
584
681
|
_.triggerEl.setAttribute('aria-expanded', 'false');
|
|
682
|
+
} else {
|
|
683
|
+
// If no trigger element, blur any focused element inside the panel
|
|
684
|
+
const activeElement = document.activeElement;
|
|
685
|
+
if (activeElement && _.contains(activeElement)) {
|
|
686
|
+
activeElement.blur();
|
|
687
|
+
}
|
|
585
688
|
}
|
|
586
689
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
690
|
+
requestAnimationFrame(() => {
|
|
691
|
+
// Set aria-hidden to start transition
|
|
692
|
+
// The transitionend event handler will add display:none when complete
|
|
693
|
+
_.setAttribute('aria-hidden', 'true');
|
|
590
694
|
|
|
591
|
-
|
|
592
|
-
|
|
695
|
+
// Emit hide event - cart dialog is now starting to hide
|
|
696
|
+
_.#emit('cart-dialog:hide', { triggerElement: _.triggerEl });
|
|
697
|
+
|
|
698
|
+
// Restore body scroll
|
|
699
|
+
_.#restoreScroll();
|
|
700
|
+
});
|
|
593
701
|
}
|
|
594
702
|
}
|
|
595
703
|
|