@magic-spells/cart-panel 0.1.0 → 0.1.2
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 +191 -226
- package/dist/cart-panel.cjs.css +57 -13
- package/dist/cart-panel.cjs.js +194 -14
- package/dist/cart-panel.cjs.js.map +1 -1
- package/dist/cart-panel.css +57 -13
- package/dist/cart-panel.esm.css +57 -13
- package/dist/cart-panel.esm.js +191 -14
- package/dist/cart-panel.esm.js.map +1 -1
- package/dist/cart-panel.js +1261 -950
- 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 +73 -73
- package/package.json +80 -80
- package/src/cart-panel.js +189 -15
- package/src/cart-panel.scss +73 -73
package/package.json
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
2
|
+
"name": "@magic-spells/cart-panel",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Accessible modal shopping cart dialog web component with Shopify integration, focus management, and smooth animations.",
|
|
5
|
+
"author": "Cory Schulz",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/cart-panel.cjs.js",
|
|
9
|
+
"module": "dist/cart-panel.esm.js",
|
|
10
|
+
"unpkg": "dist/cart-panel.min.js",
|
|
11
|
+
"style": "dist/cart-panel.css",
|
|
12
|
+
"sass": "dist/cart-panel.scss",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/cart-panel.esm.js",
|
|
16
|
+
"require": "./dist/cart-panel.cjs.js",
|
|
17
|
+
"default": "./dist/cart-panel.esm.js"
|
|
18
|
+
},
|
|
19
|
+
"./css": "./dist/cart-panel.css",
|
|
20
|
+
"./scss": "./dist/cart-panel.scss"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": true,
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/magic-spells/cart-panel"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/magic-spells/cart-panel#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/magic-spells/cart-panel/issues"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"cart-panel",
|
|
33
|
+
"web-components",
|
|
34
|
+
"e-commerce",
|
|
35
|
+
"shopping-cart",
|
|
36
|
+
"custom-elements",
|
|
37
|
+
"shopify",
|
|
38
|
+
"modal",
|
|
39
|
+
"dialog",
|
|
40
|
+
"accessibility",
|
|
41
|
+
"a11y"
|
|
42
|
+
],
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"src/"
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "rollup -c",
|
|
49
|
+
"lint": "eslint src/ rollup.config.mjs",
|
|
50
|
+
"format": "prettier --write .",
|
|
51
|
+
"prepublishOnly": "npm run build",
|
|
52
|
+
"serve": "rollup -c --watch",
|
|
53
|
+
"dev": "rollup -c --watch"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"registry": "https://registry.npmjs.org/"
|
|
58
|
+
},
|
|
59
|
+
"browserslist": [
|
|
60
|
+
"last 2 versions",
|
|
61
|
+
"not dead",
|
|
62
|
+
"not ie <= 11"
|
|
63
|
+
],
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@eslint/js": "^8.57.0",
|
|
66
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
67
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
68
|
+
"eslint": "^8.0.0",
|
|
69
|
+
"globals": "^13.24.0",
|
|
70
|
+
"prettier": "^3.3.3",
|
|
71
|
+
"rollup": "^3.0.0",
|
|
72
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
73
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
74
|
+
"rollup-plugin-serve": "^1.1.1",
|
|
75
|
+
"sass": "^1.89.2"
|
|
76
|
+
},
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@magic-spells/cart-item": "^0.3.0",
|
|
79
|
+
"@magic-spells/event-emitter": "^0.1.0",
|
|
80
|
+
"@magic-spells/focus-trap": "^1.0.7"
|
|
81
|
+
}
|
|
82
82
|
}
|
package/src/cart-panel.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './cart-panel.scss';
|
|
2
2
|
import '@magic-spells/cart-item';
|
|
3
|
+
import { CartItem } from '@magic-spells/cart-item';
|
|
3
4
|
import '@magic-spells/focus-trap';
|
|
4
5
|
import EventEmitter from '@magic-spells/event-emitter';
|
|
5
6
|
|
|
@@ -12,6 +13,7 @@ class CartDialog extends HTMLElement {
|
|
|
12
13
|
#scrollPosition = 0;
|
|
13
14
|
#currentCart = null;
|
|
14
15
|
#eventEmitter;
|
|
16
|
+
#isInitialRender = true;
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Clean up event listeners when component is removed from DOM
|
|
@@ -109,13 +111,18 @@ class CartDialog extends HTMLElement {
|
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
// Insert focus trap before the cart-panel
|
|
112
115
|
_.contentPanel.parentNode.insertBefore(_.focusTrap, _.contentPanel);
|
|
116
|
+
// Move cart-panel inside the focus trap
|
|
113
117
|
_.focusTrap.appendChild(_.contentPanel);
|
|
114
118
|
|
|
119
|
+
// Setup the trap - this will add focus-trap-start/end elements around the content
|
|
115
120
|
_.focusTrap.setupTrap();
|
|
116
121
|
|
|
117
|
-
// Add modal overlay
|
|
118
|
-
_.
|
|
122
|
+
// Add modal overlay if it doesn't already exist
|
|
123
|
+
if (!_.querySelector('cart-overlay')) {
|
|
124
|
+
_.prepend(document.createElement('cart-overlay'));
|
|
125
|
+
}
|
|
119
126
|
_.#attachListeners();
|
|
120
127
|
_.#bindKeyboard();
|
|
121
128
|
}
|
|
@@ -173,7 +180,7 @@ class CartDialog extends HTMLElement {
|
|
|
173
180
|
|
|
174
181
|
// Handle close buttons
|
|
175
182
|
_.addEventListener('click', (e) => {
|
|
176
|
-
if (!e.target.closest('[data-action
|
|
183
|
+
if (!e.target.closest('[data-action-hide-cart]')) return;
|
|
177
184
|
_.hide();
|
|
178
185
|
});
|
|
179
186
|
|
|
@@ -228,9 +235,9 @@ class CartDialog extends HTMLElement {
|
|
|
228
235
|
this.updateCartItem(cartKey, 0)
|
|
229
236
|
.then((updatedCart) => {
|
|
230
237
|
if (updatedCart && !updatedCart.error) {
|
|
231
|
-
// Success -
|
|
232
|
-
element.destroyYourself();
|
|
238
|
+
// Success - let smart comparison handle the removal animation
|
|
233
239
|
this.#currentCart = updatedCart;
|
|
240
|
+
this.#renderCartItems(updatedCart);
|
|
234
241
|
this.#updateCartItems(updatedCart);
|
|
235
242
|
|
|
236
243
|
// Emit cart updated and data changed events
|
|
@@ -263,8 +270,9 @@ class CartDialog extends HTMLElement {
|
|
|
263
270
|
this.updateCartItem(cartKey, quantity)
|
|
264
271
|
.then((updatedCart) => {
|
|
265
272
|
if (updatedCart && !updatedCart.error) {
|
|
266
|
-
// Success - update cart data
|
|
273
|
+
// Success - update cart data and refresh items
|
|
267
274
|
this.#currentCart = updatedCart;
|
|
275
|
+
this.#renderCartItems(updatedCart);
|
|
268
276
|
this.#updateCartItems(updatedCart);
|
|
269
277
|
element.setState('ready');
|
|
270
278
|
|
|
@@ -285,15 +293,32 @@ class CartDialog extends HTMLElement {
|
|
|
285
293
|
}
|
|
286
294
|
|
|
287
295
|
/**
|
|
288
|
-
* Update cart items
|
|
296
|
+
* Update cart items display based on cart data
|
|
289
297
|
* @private
|
|
290
298
|
*/
|
|
291
299
|
#updateCartItems(cart = null) {
|
|
292
|
-
// Placeholder for cart item updates
|
|
293
|
-
// Could be used to sync cart items with server data
|
|
294
300
|
const cartData = cart || this.#currentCart;
|
|
295
|
-
if (cartData)
|
|
296
|
-
|
|
301
|
+
if (!cartData) return;
|
|
302
|
+
|
|
303
|
+
// Get cart sections
|
|
304
|
+
const hasItemsSection = this.querySelector('[data-cart-has-items]');
|
|
305
|
+
const emptySection = this.querySelector('[data-cart-is-empty]');
|
|
306
|
+
const itemsContainer = this.querySelector('[data-content-cart-items]');
|
|
307
|
+
|
|
308
|
+
if (!hasItemsSection || !emptySection || !itemsContainer) {
|
|
309
|
+
console.warn(
|
|
310
|
+
'Cart sections not found. Expected [data-cart-has-items], [data-cart-is-empty], and [data-content-cart-items]'
|
|
311
|
+
);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Show/hide sections based on item count
|
|
316
|
+
if (cartData.item_count > 0) {
|
|
317
|
+
hasItemsSection.style.display = 'block';
|
|
318
|
+
emptySection.style.display = 'none';
|
|
319
|
+
} else {
|
|
320
|
+
hasItemsSection.style.display = 'none';
|
|
321
|
+
emptySection.style.display = 'block';
|
|
297
322
|
}
|
|
298
323
|
}
|
|
299
324
|
|
|
@@ -349,19 +374,157 @@ class CartDialog extends HTMLElement {
|
|
|
349
374
|
* @returns {Promise<Object>} Cart data object
|
|
350
375
|
*/
|
|
351
376
|
refreshCart() {
|
|
377
|
+
console.log('Refreshing cart...');
|
|
352
378
|
return this.getCart().then((cartData) => {
|
|
379
|
+
console.log('Cart data received:', cartData);
|
|
353
380
|
if (cartData && !cartData.error) {
|
|
354
381
|
this.#currentCart = cartData;
|
|
382
|
+
this.#renderCartItems(cartData);
|
|
355
383
|
this.#updateCartItems(cartData);
|
|
356
384
|
|
|
357
385
|
// Emit cart refreshed and data changed events
|
|
358
386
|
this.#emit('cart-dialog:refreshed', { cart: cartData });
|
|
359
387
|
this.#emit('cart-dialog:data-changed', cartData);
|
|
388
|
+
} else {
|
|
389
|
+
console.warn('Cart data has error or is null:', cartData);
|
|
360
390
|
}
|
|
361
391
|
return cartData;
|
|
362
392
|
});
|
|
363
393
|
}
|
|
364
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Remove items from DOM that are no longer in cart data
|
|
397
|
+
* @private
|
|
398
|
+
*/
|
|
399
|
+
#removeItemsFromDOM(itemsContainer, newKeysSet) {
|
|
400
|
+
const currentItems = Array.from(itemsContainer.querySelectorAll('cart-item'));
|
|
401
|
+
const itemsToRemove = currentItems.filter((item) => !newKeysSet.has(item.getAttribute('key')));
|
|
402
|
+
|
|
403
|
+
console.log(
|
|
404
|
+
`Removing ${itemsToRemove.length} items:`,
|
|
405
|
+
itemsToRemove.map((item) => item.getAttribute('key'))
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
itemsToRemove.forEach((item) => {
|
|
409
|
+
item.destroyYourself();
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Add new items to DOM with animation delay
|
|
415
|
+
* @private
|
|
416
|
+
*/
|
|
417
|
+
#addItemsToDOM(itemsContainer, itemsToAdd, newKeys) {
|
|
418
|
+
console.log(
|
|
419
|
+
`Adding ${itemsToAdd.length} items:`,
|
|
420
|
+
itemsToAdd.map((item) => item.key || item.id)
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
// Delay adding new items by 300ms to let cart slide open first
|
|
424
|
+
setTimeout(() => {
|
|
425
|
+
itemsToAdd.forEach((itemData) => {
|
|
426
|
+
const cartItem = CartItem.createAnimated(itemData);
|
|
427
|
+
const targetIndex = newKeys.indexOf(itemData.key || itemData.id);
|
|
428
|
+
|
|
429
|
+
// Find the correct position to insert the new item
|
|
430
|
+
if (targetIndex === 0) {
|
|
431
|
+
// Insert at the beginning
|
|
432
|
+
itemsContainer.insertBefore(cartItem, itemsContainer.firstChild);
|
|
433
|
+
} else {
|
|
434
|
+
// Find the item that should come before this one
|
|
435
|
+
let insertAfter = null;
|
|
436
|
+
for (let i = targetIndex - 1; i >= 0; i--) {
|
|
437
|
+
const prevKey = newKeys[i];
|
|
438
|
+
const prevItem = itemsContainer.querySelector(`cart-item[key="${prevKey}"]`);
|
|
439
|
+
if (prevItem) {
|
|
440
|
+
insertAfter = prevItem;
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (insertAfter) {
|
|
446
|
+
insertAfter.insertAdjacentElement('afterend', cartItem);
|
|
447
|
+
} else {
|
|
448
|
+
itemsContainer.appendChild(cartItem);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}, 100);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Render cart items from Shopify cart data with smart comparison
|
|
457
|
+
* @private
|
|
458
|
+
*/
|
|
459
|
+
#renderCartItems(cartData) {
|
|
460
|
+
const itemsContainer = this.querySelector('[data-content-cart-items]');
|
|
461
|
+
|
|
462
|
+
if (!itemsContainer || !cartData || !cartData.items) {
|
|
463
|
+
console.warn('Cannot render cart items:', {
|
|
464
|
+
itemsContainer: !!itemsContainer,
|
|
465
|
+
cartData: !!cartData,
|
|
466
|
+
items: cartData?.items?.length,
|
|
467
|
+
});
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Handle initial render - load all items without animation
|
|
472
|
+
if (this.#isInitialRender) {
|
|
473
|
+
console.log('Initial cart render:', cartData.items.length, 'items');
|
|
474
|
+
|
|
475
|
+
// Clear existing items
|
|
476
|
+
itemsContainer.innerHTML = '';
|
|
477
|
+
|
|
478
|
+
// Create cart-item elements without animation
|
|
479
|
+
cartData.items.forEach((itemData) => {
|
|
480
|
+
const cartItem = new CartItem(itemData); // No animation
|
|
481
|
+
itemsContainer.appendChild(cartItem);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
this.#isInitialRender = false;
|
|
485
|
+
console.log('Initial render complete, container children:', itemsContainer.children.length);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
console.log('Smart rendering cart items:', cartData.items.length, 'items');
|
|
490
|
+
|
|
491
|
+
// Get current DOM items and their keys
|
|
492
|
+
const currentItems = Array.from(itemsContainer.querySelectorAll('cart-item'));
|
|
493
|
+
const currentKeys = new Set(currentItems.map((item) => item.getAttribute('key')));
|
|
494
|
+
|
|
495
|
+
// Get new cart data keys in order
|
|
496
|
+
const newKeys = cartData.items.map((item) => item.key || item.id);
|
|
497
|
+
const newKeysSet = new Set(newKeys);
|
|
498
|
+
|
|
499
|
+
// Step 1: Remove items that are no longer in cart data
|
|
500
|
+
this.#removeItemsFromDOM(itemsContainer, newKeysSet);
|
|
501
|
+
|
|
502
|
+
// Step 2: Add new items that weren't in DOM (with animation delay)
|
|
503
|
+
const itemsToAdd = cartData.items.filter(
|
|
504
|
+
(itemData) => !currentKeys.has(itemData.key || itemData.id)
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
this.#addItemsToDOM(itemsContainer, itemsToAdd, newKeys);
|
|
508
|
+
|
|
509
|
+
console.log('Smart rendering complete, container children:', itemsContainer.children.length);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Set the template function for cart items
|
|
514
|
+
* @param {Function} templateFn - Function that takes item data and returns HTML string
|
|
515
|
+
*/
|
|
516
|
+
setCartItemTemplate(templateFn) {
|
|
517
|
+
CartItem.setTemplate(templateFn);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Set the processing template function for cart items
|
|
522
|
+
* @param {Function} templateFn - Function that returns HTML string for processing state
|
|
523
|
+
*/
|
|
524
|
+
setCartItemProcessingTemplate(templateFn) {
|
|
525
|
+
CartItem.setProcessingTemplate(templateFn);
|
|
526
|
+
}
|
|
527
|
+
|
|
365
528
|
/**
|
|
366
529
|
* Shows the cart dialog and traps focus within it
|
|
367
530
|
* @param {HTMLElement} [triggerEl=null] - The element that triggered the cart dialog
|
|
@@ -462,9 +625,20 @@ class CartPanel extends HTMLElement {
|
|
|
462
625
|
}
|
|
463
626
|
}
|
|
464
627
|
|
|
465
|
-
customElements.
|
|
466
|
-
customElements.define('cart-
|
|
467
|
-
|
|
628
|
+
if (!customElements.get('cart-dialog')) {
|
|
629
|
+
customElements.define('cart-dialog', CartDialog);
|
|
630
|
+
}
|
|
631
|
+
if (!customElements.get('cart-overlay')) {
|
|
632
|
+
customElements.define('cart-overlay', CartOverlay);
|
|
633
|
+
}
|
|
634
|
+
if (!customElements.get('cart-panel')) {
|
|
635
|
+
customElements.define('cart-panel', CartPanel);
|
|
636
|
+
}
|
|
468
637
|
|
|
469
|
-
export { CartDialog, CartOverlay, CartPanel };
|
|
638
|
+
export { CartDialog, CartOverlay, CartPanel, CartItem };
|
|
470
639
|
export default CartDialog;
|
|
640
|
+
|
|
641
|
+
// Make CartItem available globally for Shopify themes
|
|
642
|
+
if (typeof window !== 'undefined') {
|
|
643
|
+
window.CartItem = CartItem;
|
|
644
|
+
}
|
package/src/cart-panel.scss
CHANGED
|
@@ -25,93 +25,93 @@ $cart-transition-timing: cubic-bezier(0.4, 0, 0.2, 1) !default;
|
|
|
25
25
|
|
|
26
26
|
// Define CSS Custom Properties using SCSS values
|
|
27
27
|
:root {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
// Layout
|
|
29
|
+
--cart-dialog-z-index: #{$cart-dialog-z-index};
|
|
30
|
+
--cart-overlay-z-index: #{$cart-overlay-z-index};
|
|
31
|
+
--cart-panel-z-index: #{$cart-panel-z-index};
|
|
32
|
+
--cart-panel-width: #{$cart-panel-width};
|
|
33
|
+
|
|
34
|
+
// Overlay
|
|
35
|
+
--cart-overlay-background: #{$cart-overlay-background};
|
|
36
|
+
--cart-overlay-backdrop-filter: #{$cart-overlay-backdrop-filter};
|
|
37
|
+
|
|
38
|
+
// Panel
|
|
39
|
+
--cart-panel-background: #{$cart-panel-background};
|
|
40
|
+
--cart-panel-shadow: #{$cart-panel-shadow};
|
|
41
|
+
--cart-panel-border-radius: #{$cart-panel-border-radius};
|
|
42
|
+
|
|
43
|
+
// Animation
|
|
44
|
+
--cart-transition-duration: #{$cart-transition-duration};
|
|
45
|
+
--cart-transition-timing: #{$cart-transition-timing};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Cart Dialog - Main container
|
|
49
49
|
cart-dialog {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
display: contents;
|
|
51
|
+
|
|
52
|
+
&[aria-hidden='false'] {
|
|
53
|
+
cart-overlay,
|
|
54
|
+
cart-panel {
|
|
55
|
+
pointer-events: auto;
|
|
56
|
+
opacity: 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
cart-panel {
|
|
60
|
+
transform: translateX(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// Cart Overlay - Backdrop
|
|
66
66
|
cart-overlay {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
position: fixed;
|
|
68
|
+
top: 0;
|
|
69
|
+
left: 0;
|
|
70
|
+
width: 100vw;
|
|
71
|
+
height: 100vh;
|
|
72
|
+
opacity: 0;
|
|
73
|
+
pointer-events: none;
|
|
74
|
+
z-index: var(--cart-overlay-z-index);
|
|
75
|
+
background-color: var(--cart-overlay-background);
|
|
76
|
+
backdrop-filter: var(--cart-overlay-backdrop-filter);
|
|
77
|
+
transition:
|
|
78
|
+
opacity var(--cart-transition-duration) var(--cart-transition-timing),
|
|
79
|
+
backdrop-filter var(--cart-transition-duration) var(--cart-transition-timing);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
// Cart Panel - Sliding content area
|
|
83
83
|
cart-panel {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
position: fixed;
|
|
85
|
+
top: 0;
|
|
86
|
+
right: 0;
|
|
87
|
+
width: var(--cart-panel-width);
|
|
88
|
+
height: 100vh;
|
|
89
|
+
opacity: 0;
|
|
90
|
+
transform: translateX(100%);
|
|
91
|
+
pointer-events: none;
|
|
92
|
+
z-index: var(--cart-panel-z-index);
|
|
93
|
+
background: var(--cart-panel-background);
|
|
94
|
+
box-shadow: var(--cart-panel-shadow);
|
|
95
|
+
border-radius: var(--cart-panel-border-radius);
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
transition:
|
|
98
|
+
opacity var(--cart-transition-duration) var(--cart-transition-timing),
|
|
99
|
+
transform var(--cart-transition-duration) var(--cart-transition-timing);
|
|
100
|
+
|
|
101
|
+
// When explicitly hidden, remove from layout
|
|
102
|
+
&.hidden {
|
|
103
|
+
display: none;
|
|
104
|
+
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// Body scroll lock when cart is open
|
|
108
108
|
body.overflow-hidden {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
overflow: hidden;
|
|
110
|
+
position: fixed;
|
|
111
|
+
width: 100%;
|
|
112
|
+
height: 100%;
|
|
113
|
+
left: 0;
|
|
114
|
+
right: 0;
|
|
115
|
+
margin: 0;
|
|
116
|
+
// The top property will be set dynamically by the component
|
|
117
117
|
}
|