@magic-spells/cart-progress-bar 0.1.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.
@@ -0,0 +1,131 @@
1
+ cart-progress-bar {
2
+ --cart-progress-bar-height: 12px;
3
+ --cart-progress-bar-border-radius: 6px;
4
+ --cart-progress-bar-bg: #e9ecef;
5
+ --cart-progress-bar-fill-bg: #28a745;
6
+ --cart-progress-bar-complete-bg: #007bff;
7
+ --cart-progress-bar-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
8
+ --cart-progress-bar-transition-duration: 0.3s;
9
+ --cart-progress-message-font-size: 0.875rem;
10
+ --cart-progress-message-line-height: 1.4;
11
+ --cart-progress-message-color: #495057;
12
+ --cart-progress-message-complete-color: #155724;
13
+ --cart-progress-message-margin: 0.5rem;
14
+ --cart-progress-percent: 0%;
15
+ display: block;
16
+ width: 100%;
17
+ max-width: 100%;
18
+ }
19
+ cart-progress-bar p[data-content-cart-progress-message] {
20
+ font-size: var(--cart-progress-message-font-size);
21
+ line-height: var(--cart-progress-message-line-height);
22
+ color: var(--cart-progress-message-color);
23
+ margin: var(--cart-progress-message-margin) 0;
24
+ text-align: center;
25
+ transition: color var(--cart-progress-bar-transition-duration) ease;
26
+ }
27
+ @media (max-width: 768px) {
28
+ cart-progress-bar p[data-content-cart-progress-message] {
29
+ font-size: calc(var(--cart-progress-message-font-size) * 0.9);
30
+ margin: calc(var(--cart-progress-message-margin) * 0.75) 0;
31
+ }
32
+ }
33
+ cart-progress-bar[data-complete=true] p[data-content-cart-progress-message] {
34
+ color: var(--cart-progress-message-complete-color);
35
+ font-weight: 600;
36
+ }
37
+ cart-progress-bar.progress-low {
38
+ --cart-progress-bar-fill-bg: #dc3545;
39
+ }
40
+ cart-progress-bar.progress-medium {
41
+ --cart-progress-bar-fill-bg: #ffc107;
42
+ }
43
+ cart-progress-bar.progress-high {
44
+ --cart-progress-bar-fill-bg: #fd7e14;
45
+ }
46
+ cart-progress-bar.progress-complete {
47
+ --cart-progress-bar-fill-bg: var(--cart-progress-bar-complete-bg);
48
+ }
49
+ cart-progress-bar.progress-complete p[data-content-cart-progress-message] {
50
+ color: var(--cart-progress-message-complete-color);
51
+ }
52
+
53
+ progress-bar {
54
+ display: block;
55
+ width: 100%;
56
+ height: var(--cart-progress-bar-height);
57
+ background-color: var(--cart-progress-bar-bg);
58
+ border-radius: var(--cart-progress-bar-border-radius);
59
+ box-shadow: var(--cart-progress-bar-shadow);
60
+ overflow: hidden;
61
+ position: relative;
62
+ }
63
+ progress-bar .progress-bar-fill {
64
+ height: 100%;
65
+ width: var(--cart-progress-percent);
66
+ background-color: var(--cart-progress-bar-fill-bg);
67
+ border-radius: var(--cart-progress-bar-border-radius);
68
+ transition: width var(--cart-progress-bar-transition-duration) ease, background-color var(--cart-progress-bar-transition-duration) ease;
69
+ position: relative;
70
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.1) 75%, transparent 75%, transparent);
71
+ background-size: 12px 12px;
72
+ }
73
+ progress-bar .progress-bar-fill::after {
74
+ content: "";
75
+ position: absolute;
76
+ top: 0;
77
+ left: -100%;
78
+ width: 100%;
79
+ height: 100%;
80
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
81
+ transition: left 0.5s ease;
82
+ }
83
+ cart-progress-bar[data-complete=true] progress-bar .progress-bar-fill::after, cart-progress-bar.progress-complete progress-bar .progress-bar-fill::after {
84
+ left: 100%;
85
+ }
86
+ progress-bar:focus-visible {
87
+ outline: 2px solid #007bff;
88
+ outline-offset: 2px;
89
+ }
90
+ @media (prefers-contrast: high) {
91
+ progress-bar {
92
+ --cart-progress-bar-bg: #000000;
93
+ --cart-progress-bar-fill-bg: #ffffff;
94
+ border: 1px solid #ffffff;
95
+ }
96
+ }
97
+ @media (prefers-reduced-motion: reduce) {
98
+ progress-bar .progress-bar-fill {
99
+ transition: none;
100
+ }
101
+ progress-bar .progress-bar-fill::after {
102
+ transition: none;
103
+ }
104
+ }
105
+
106
+ @media (max-width: 768px) {
107
+ cart-progress-bar {
108
+ --cart-progress-bar-height: 10px;
109
+ --cart-progress-message-margin: 0.375rem;
110
+ }
111
+ }
112
+ @media (prefers-color-scheme: dark) {
113
+ cart-progress-bar {
114
+ --cart-progress-bar-bg: #343a40;
115
+ --cart-progress-message-color: #e9ecef;
116
+ --cart-progress-message-complete-color: #28a745;
117
+ }
118
+ }
119
+ @media print {
120
+ cart-progress-bar .above-message,
121
+ cart-progress-bar .below-message {
122
+ color: #000000 !important;
123
+ }
124
+ cart-progress-bar progress-bar {
125
+ border: 1px solid #000000;
126
+ }
127
+ cart-progress-bar progress-bar .progress-bar-fill {
128
+ background-color: #000000 !important;
129
+ background-image: none !important;
130
+ }
131
+ }
@@ -0,0 +1,346 @@
1
+ /**
2
+ * ProgressBar helper class for the visual progress bar element
3
+ */
4
+ class ProgressBar extends HTMLElement {
5
+ constructor() {
6
+ super();
7
+ this.#setupProgressBar();
8
+ }
9
+
10
+ #setupProgressBar() {
11
+ this.setAttribute('role', 'progressbar');
12
+ this.setAttribute('aria-valuemin', '0');
13
+ this.setAttribute('aria-valuemax', '100');
14
+ this.setAttribute('aria-valuenow', '0');
15
+
16
+ // Create the visual progress bar
17
+ this.innerHTML = '<div class="progress-bar-fill"></div>';
18
+ }
19
+
20
+ setPercent(percent) {
21
+ const clampedPercent = Math.max(0, Math.min(100, percent));
22
+ this.style.setProperty('--cart-progress-percent', `${clampedPercent}%`);
23
+ this.setAttribute('aria-valuenow', clampedPercent);
24
+ }
25
+ }
26
+
27
+ // Define ProgressBar custom element immediately so it's available for CartProgressBar
28
+ customElements.define('progress-bar', ProgressBar);
29
+
30
+ /**
31
+ * CartProgressBar main component
32
+ */
33
+ class CartProgressBar extends HTMLElement {
34
+ // Private fields
35
+ #minAmount = 0;
36
+ #currentAmount = 0;
37
+ #progressPercent = 0;
38
+ #originalAboveMessage = '';
39
+ #originalBelowMessage = '';
40
+ #progressBar = null;
41
+ #messageElement = null;
42
+
43
+ /**
44
+ * Define which attributes should be observed for changes
45
+ */
46
+ static get observedAttributes() {
47
+ return ['threshold', 'current', 'message-above', 'message-below'];
48
+ }
49
+
50
+ constructor() {
51
+ super();
52
+ this.#init();
53
+ }
54
+
55
+ #init() {
56
+ // Read initial attributes
57
+ this.#minAmount = parseFloat(this.getAttribute('threshold')) || 0;
58
+ this.#currentAmount = parseFloat(this.getAttribute('current')) || 0;
59
+
60
+ // Store original message templates
61
+ this.#originalAboveMessage = this.getAttribute('message-above') || '';
62
+ this.#originalBelowMessage = this.getAttribute('message-below') || '';
63
+ }
64
+
65
+ async connectedCallback() {
66
+ // ensure the child custom element has been registered
67
+ await customElements.whenDefined('progress-bar');
68
+
69
+ if (!customElements.get('progress-bar')) {
70
+ throw new Error('<progress-bar> must be registered before <cart-progress-bar> runs');
71
+ }
72
+
73
+ this.#render();
74
+ this.#updateProgress();
75
+ this.#attachListeners();
76
+ }
77
+
78
+ attributeChangedCallback(name, oldValue, newValue) {
79
+ if (oldValue === newValue) return;
80
+
81
+ switch (name) {
82
+ case 'threshold':
83
+ this.#minAmount = parseFloat(newValue) || 0;
84
+ this.#updateProgress();
85
+ break;
86
+ case 'current':
87
+ this.#currentAmount = parseFloat(newValue) || 0;
88
+ this.#updateProgress();
89
+ break;
90
+ case 'message-above':
91
+ this.#originalAboveMessage = newValue || '';
92
+ this.#updateMessages();
93
+ break;
94
+ case 'message-below':
95
+ this.#originalBelowMessage = newValue || '';
96
+ this.#updateMessages();
97
+ break;
98
+ }
99
+ }
100
+
101
+ #render() {
102
+ // Find or create the message element
103
+ this.#messageElement =
104
+ this.querySelector('[data-content-cart-progress-message]') ||
105
+ this.querySelector('p[data-content-cart-progress-message]');
106
+
107
+ // Find existing progress bar (user can add their own)
108
+ this.#progressBar = this.querySelector('progress-bar');
109
+
110
+ // Create message element if it doesn't exist but we have message templates
111
+ if (!this.#messageElement && (this.#originalAboveMessage || this.#originalBelowMessage)) {
112
+ this.#messageElement = document.createElement('p');
113
+ this.#messageElement.setAttribute('data-content-cart-progress-message', '');
114
+ this.appendChild(this.#messageElement);
115
+ }
116
+
117
+ // Create progress bar if it doesn't exist - add it at the end (below text message)
118
+ if (!this.#progressBar) {
119
+ // Ensure progress-bar is defined before creating
120
+ if (customElements.get('progress-bar')) {
121
+ this.#progressBar = document.createElement('progress-bar');
122
+ this.appendChild(this.#progressBar);
123
+ } else {
124
+ // Fallback: wait for definition
125
+ customElements.whenDefined('progress-bar').then(() => {
126
+ if (!this.#progressBar) {
127
+ this.#progressBar = document.createElement('progress-bar');
128
+ this.appendChild(this.#progressBar);
129
+ this.#updateProgress(); // Update progress after creating
130
+ }
131
+ });
132
+ }
133
+ }
134
+ }
135
+
136
+ #updateProgress() {
137
+ if (this.#minAmount === 0) {
138
+ this.#progressPercent = 100;
139
+ } else {
140
+ this.#progressPercent = Math.min(100, (this.#currentAmount / this.#minAmount) * 100);
141
+ }
142
+
143
+ // Update progress bar
144
+ if (this.#progressBar) {
145
+ this.#progressBar.setPercent(this.#progressPercent);
146
+ }
147
+
148
+ // Update messages
149
+ this.#updateMessages();
150
+
151
+ // Update component state
152
+ this.#updateComponentState();
153
+ }
154
+
155
+ #attachListeners() {
156
+ // Find the nearest cart-panel component
157
+ const cartPanel = this.closest('cart-panel');
158
+
159
+ if (cartPanel) {
160
+ // Listen for cart data changes
161
+ cartPanel.addEventListener('cart-dialog:data-changed', (event) => {
162
+ this.#handleCartDataChange(event);
163
+ });
164
+ }
165
+ }
166
+
167
+ #handleCartDataChange(event) {
168
+ const updatedCart = event.detail;
169
+
170
+ if (updatedCart && typeof updatedCart.total_price !== 'undefined') {
171
+ // Convert from cents to dollars if needed (Shopify typically returns cents)
172
+ const currentAmount = updatedCart.total_price / 100;
173
+ this.setCurrentAmount(currentAmount);
174
+ }
175
+ }
176
+
177
+ #updateMessages() {
178
+ const isComplete = this.#currentAmount >= this.#minAmount;
179
+ const remainingAmount = Math.max(0, this.#minAmount - this.#currentAmount);
180
+
181
+ // Format remaining amount as currency (assuming USD for now)
182
+ const formattedAmount = this.#formatCurrency(remainingAmount);
183
+
184
+ // Update the single message element
185
+ if (this.#messageElement) {
186
+ let messageTemplate;
187
+
188
+ if (isComplete && this.#originalAboveMessage) {
189
+ // Show success message when complete
190
+ messageTemplate = this.#originalAboveMessage;
191
+ } else if (!isComplete) {
192
+ // Show progress message when incomplete
193
+ messageTemplate = this.#originalBelowMessage || this.#originalAboveMessage;
194
+ }
195
+
196
+ if (messageTemplate) {
197
+ const message = messageTemplate.replace(/\$\{left\}/g, formattedAmount);
198
+ this.#messageElement.textContent = message;
199
+ this.#messageElement.style.display = 'block';
200
+ } else {
201
+ // Hide message if no template available for current state
202
+ this.#messageElement.style.display = 'none';
203
+ }
204
+ }
205
+ }
206
+
207
+ #updateComponentState() {
208
+ const isComplete = this.#currentAmount >= this.#minAmount;
209
+
210
+ if (isComplete) {
211
+ this.setAttribute('data-complete', 'true');
212
+ this.removeAttribute('data-incomplete');
213
+ } else {
214
+ this.setAttribute('data-incomplete', 'true');
215
+ this.removeAttribute('data-complete');
216
+ }
217
+
218
+ // Set progress level classes for styling
219
+ this.classList.remove('progress-low', 'progress-medium', 'progress-high', 'progress-complete');
220
+
221
+ if (isComplete) {
222
+ this.classList.add('progress-complete');
223
+ } else if (this.#progressPercent >= 75) {
224
+ this.classList.add('progress-high');
225
+ } else if (this.#progressPercent >= 50) {
226
+ this.classList.add('progress-medium');
227
+ } else {
228
+ this.classList.add('progress-low');
229
+ }
230
+ }
231
+
232
+ #formatCurrency(amount) {
233
+ // Basic currency formatting - could be enhanced with locale/currency options
234
+ return new Intl.NumberFormat('en-US', {
235
+ style: 'currency',
236
+ currency: 'USD',
237
+ minimumFractionDigits: 2,
238
+ maximumFractionDigits: 2,
239
+ }).format(amount);
240
+ }
241
+
242
+ /**
243
+ * Public API: Set the progress percentage directly
244
+ * @param {number} percent - Progress percentage (0-100)
245
+ */
246
+ setPercent(percent) {
247
+ const clampedPercent = Math.max(0, Math.min(100, percent));
248
+ this.#progressPercent = clampedPercent;
249
+
250
+ if (this.#progressBar) {
251
+ this.#progressBar.setPercent(clampedPercent);
252
+ }
253
+
254
+ // Calculate current amount based on percentage
255
+ this.#currentAmount = (clampedPercent / 100) * this.#minAmount;
256
+ this.setAttribute('current', this.#currentAmount.toString());
257
+
258
+ this.#updateMessages();
259
+ this.#updateComponentState();
260
+ }
261
+
262
+ /**
263
+ * Public API: Set the current cart amount
264
+ * @param {number} amount - Current cart amount
265
+ */
266
+ setCurrentAmount(amount) {
267
+ this.#currentAmount = parseFloat(amount) || 0;
268
+ this.setAttribute('current', this.#currentAmount.toString());
269
+ this.#updateProgress();
270
+ }
271
+
272
+ /**
273
+ * Public API: Set the threshold amount for free shipping
274
+ * @param {number} amount - Threshold amount for free shipping
275
+ */
276
+ setThresholdAmount(amount) {
277
+ this.#minAmount = parseFloat(amount) || 0;
278
+ this.setAttribute('threshold', this.#minAmount.toString());
279
+ this.#updateProgress();
280
+ }
281
+
282
+ /**
283
+ * Public API: Set the minimum amount for free shipping (deprecated - use setThresholdAmount)
284
+ * @param {number} amount - Minimum amount threshold
285
+ * @deprecated Use setThresholdAmount instead
286
+ */
287
+ setMinAmount(amount) {
288
+ this.setThresholdAmount(amount);
289
+ }
290
+
291
+ /**
292
+ * Public API: Get current progress information
293
+ */
294
+ getProgress() {
295
+ return {
296
+ currentAmount: this.#currentAmount,
297
+ thresholdAmount: this.#minAmount,
298
+ minAmount: this.#minAmount, // backwards compatibility
299
+ remainingAmount: Math.max(0, this.#minAmount - this.#currentAmount),
300
+ percent: this.#progressPercent,
301
+ isComplete: this.#currentAmount >= this.#minAmount,
302
+ };
303
+ }
304
+
305
+ /**
306
+ * Public API: Update message templates
307
+ * @param {string} aboveMessage - Message template for above the bar
308
+ * @param {string} belowMessage - Message template for below the bar
309
+ */
310
+ setMessages(aboveMessage = null, belowMessage = null) {
311
+ if (aboveMessage !== null) {
312
+ this.#originalAboveMessage = aboveMessage;
313
+ this.setAttribute('message-above', aboveMessage);
314
+ }
315
+
316
+ if (belowMessage !== null) {
317
+ this.#originalBelowMessage = belowMessage;
318
+ this.setAttribute('message-below', belowMessage);
319
+ }
320
+
321
+ this.#updateMessages();
322
+ }
323
+
324
+ // Getters
325
+ get currentAmount() {
326
+ return this.#currentAmount;
327
+ }
328
+ get thresholdAmount() {
329
+ return this.#minAmount;
330
+ }
331
+ get minAmount() {
332
+ return this.#minAmount;
333
+ } // backwards compatibility
334
+ get percent() {
335
+ return this.#progressPercent;
336
+ }
337
+ get isComplete() {
338
+ return this.#currentAmount >= this.#minAmount;
339
+ }
340
+ }
341
+
342
+ // Define CartProgressBar custom element
343
+ customElements.define('cart-progress-bar', CartProgressBar);
344
+
345
+ export { CartProgressBar, ProgressBar };
346
+ //# sourceMappingURL=cart-progress-bar.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cart-progress-bar.esm.js","sources":["../src/cart-progress-bar.js"],"sourcesContent":["import './cart-progress-bar.scss';\n\n/**\n * ProgressBar helper class for the visual progress bar element\n */\nclass ProgressBar extends HTMLElement {\n\tconstructor() {\n\t\tsuper();\n\t\tthis.#setupProgressBar();\n\t}\n\n\t#setupProgressBar() {\n\t\tthis.setAttribute('role', 'progressbar');\n\t\tthis.setAttribute('aria-valuemin', '0');\n\t\tthis.setAttribute('aria-valuemax', '100');\n\t\tthis.setAttribute('aria-valuenow', '0');\n\n\t\t// Create the visual progress bar\n\t\tthis.innerHTML = '<div class=\"progress-bar-fill\"></div>';\n\t}\n\n\tsetPercent(percent) {\n\t\tconst clampedPercent = Math.max(0, Math.min(100, percent));\n\t\tthis.style.setProperty('--cart-progress-percent', `${clampedPercent}%`);\n\t\tthis.setAttribute('aria-valuenow', clampedPercent);\n\t}\n}\n\n// Define ProgressBar custom element immediately so it's available for CartProgressBar\ncustomElements.define('progress-bar', ProgressBar);\n\n/**\n * CartProgressBar main component\n */\nclass CartProgressBar extends HTMLElement {\n\t// Private fields\n\t#minAmount = 0;\n\t#currentAmount = 0;\n\t#progressPercent = 0;\n\t#originalAboveMessage = '';\n\t#originalBelowMessage = '';\n\t#progressBar = null;\n\t#messageElement = null;\n\n\t/**\n\t * Define which attributes should be observed for changes\n\t */\n\tstatic get observedAttributes() {\n\t\treturn ['threshold', 'current', 'message-above', 'message-below'];\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.#init();\n\t}\n\n\t#init() {\n\t\t// Read initial attributes\n\t\tthis.#minAmount = parseFloat(this.getAttribute('threshold')) || 0;\n\t\tthis.#currentAmount = parseFloat(this.getAttribute('current')) || 0;\n\n\t\t// Store original message templates\n\t\tthis.#originalAboveMessage = this.getAttribute('message-above') || '';\n\t\tthis.#originalBelowMessage = this.getAttribute('message-below') || '';\n\t}\n\n\tasync connectedCallback() {\n\t\t// ensure the child custom element has been registered\n\t\tawait customElements.whenDefined('progress-bar');\n\n\t\tif (!customElements.get('progress-bar')) {\n\t\t\tthrow new Error('<progress-bar> must be registered before <cart-progress-bar> runs');\n\t\t}\n\n\t\tthis.#render();\n\t\tthis.#updateProgress();\n\t\tthis.#attachListeners();\n\t}\n\n\tattributeChangedCallback(name, oldValue, newValue) {\n\t\tif (oldValue === newValue) return;\n\n\t\tswitch (name) {\n\t\t\tcase 'threshold':\n\t\t\t\tthis.#minAmount = parseFloat(newValue) || 0;\n\t\t\t\tthis.#updateProgress();\n\t\t\t\tbreak;\n\t\t\tcase 'current':\n\t\t\t\tthis.#currentAmount = parseFloat(newValue) || 0;\n\t\t\t\tthis.#updateProgress();\n\t\t\t\tbreak;\n\t\t\tcase 'message-above':\n\t\t\t\tthis.#originalAboveMessage = newValue || '';\n\t\t\t\tthis.#updateMessages();\n\t\t\t\tbreak;\n\t\t\tcase 'message-below':\n\t\t\t\tthis.#originalBelowMessage = newValue || '';\n\t\t\t\tthis.#updateMessages();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t#render() {\n\t\t// Find or create the message element\n\t\tthis.#messageElement =\n\t\t\tthis.querySelector('[data-content-cart-progress-message]') ||\n\t\t\tthis.querySelector('p[data-content-cart-progress-message]');\n\n\t\t// Find existing progress bar (user can add their own)\n\t\tthis.#progressBar = this.querySelector('progress-bar');\n\n\t\t// Create message element if it doesn't exist but we have message templates\n\t\tif (!this.#messageElement && (this.#originalAboveMessage || this.#originalBelowMessage)) {\n\t\t\tthis.#messageElement = document.createElement('p');\n\t\t\tthis.#messageElement.setAttribute('data-content-cart-progress-message', '');\n\t\t\tthis.appendChild(this.#messageElement);\n\t\t}\n\n\t\t// Create progress bar if it doesn't exist - add it at the end (below text message)\n\t\tif (!this.#progressBar) {\n\t\t\t// Ensure progress-bar is defined before creating\n\t\t\tif (customElements.get('progress-bar')) {\n\t\t\t\tthis.#progressBar = document.createElement('progress-bar');\n\t\t\t\tthis.appendChild(this.#progressBar);\n\t\t\t} else {\n\t\t\t\t// Fallback: wait for definition\n\t\t\t\tcustomElements.whenDefined('progress-bar').then(() => {\n\t\t\t\t\tif (!this.#progressBar) {\n\t\t\t\t\t\tthis.#progressBar = document.createElement('progress-bar');\n\t\t\t\t\t\tthis.appendChild(this.#progressBar);\n\t\t\t\t\t\tthis.#updateProgress(); // Update progress after creating\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t#updateProgress() {\n\t\tif (this.#minAmount === 0) {\n\t\t\tthis.#progressPercent = 100;\n\t\t} else {\n\t\t\tthis.#progressPercent = Math.min(100, (this.#currentAmount / this.#minAmount) * 100);\n\t\t}\n\n\t\t// Update progress bar\n\t\tif (this.#progressBar) {\n\t\t\tthis.#progressBar.setPercent(this.#progressPercent);\n\t\t}\n\n\t\t// Update messages\n\t\tthis.#updateMessages();\n\n\t\t// Update component state\n\t\tthis.#updateComponentState();\n\t}\n\n\t#attachListeners() {\n\t\t// Find the nearest cart-panel component\n\t\tconst cartPanel = this.closest('cart-panel');\n\n\t\tif (cartPanel) {\n\t\t\t// Listen for cart data changes\n\t\t\tcartPanel.addEventListener('cart-dialog:data-changed', (event) => {\n\t\t\t\tthis.#handleCartDataChange(event);\n\t\t\t});\n\t\t}\n\t}\n\n\t#handleCartDataChange(event) {\n\t\tconst updatedCart = event.detail;\n\n\t\tif (updatedCart && typeof updatedCart.total_price !== 'undefined') {\n\t\t\t// Convert from cents to dollars if needed (Shopify typically returns cents)\n\t\t\tconst currentAmount = updatedCart.total_price / 100;\n\t\t\tthis.setCurrentAmount(currentAmount);\n\t\t}\n\t}\n\n\t#updateMessages() {\n\t\tconst isComplete = this.#currentAmount >= this.#minAmount;\n\t\tconst remainingAmount = Math.max(0, this.#minAmount - this.#currentAmount);\n\n\t\t// Format remaining amount as currency (assuming USD for now)\n\t\tconst formattedAmount = this.#formatCurrency(remainingAmount);\n\n\t\t// Update the single message element\n\t\tif (this.#messageElement) {\n\t\t\tlet messageTemplate;\n\n\t\t\tif (isComplete && this.#originalAboveMessage) {\n\t\t\t\t// Show success message when complete\n\t\t\t\tmessageTemplate = this.#originalAboveMessage;\n\t\t\t} else if (!isComplete) {\n\t\t\t\t// Show progress message when incomplete\n\t\t\t\tmessageTemplate = this.#originalBelowMessage || this.#originalAboveMessage;\n\t\t\t}\n\n\t\t\tif (messageTemplate) {\n\t\t\t\tconst message = messageTemplate.replace(/\\$\\{left\\}/g, formattedAmount);\n\t\t\t\tthis.#messageElement.textContent = message;\n\t\t\t\tthis.#messageElement.style.display = 'block';\n\t\t\t} else {\n\t\t\t\t// Hide message if no template available for current state\n\t\t\t\tthis.#messageElement.style.display = 'none';\n\t\t\t}\n\t\t}\n\t}\n\n\t#updateComponentState() {\n\t\tconst isComplete = this.#currentAmount >= this.#minAmount;\n\n\t\tif (isComplete) {\n\t\t\tthis.setAttribute('data-complete', 'true');\n\t\t\tthis.removeAttribute('data-incomplete');\n\t\t} else {\n\t\t\tthis.setAttribute('data-incomplete', 'true');\n\t\t\tthis.removeAttribute('data-complete');\n\t\t}\n\n\t\t// Set progress level classes for styling\n\t\tthis.classList.remove('progress-low', 'progress-medium', 'progress-high', 'progress-complete');\n\n\t\tif (isComplete) {\n\t\t\tthis.classList.add('progress-complete');\n\t\t} else if (this.#progressPercent >= 75) {\n\t\t\tthis.classList.add('progress-high');\n\t\t} else if (this.#progressPercent >= 50) {\n\t\t\tthis.classList.add('progress-medium');\n\t\t} else {\n\t\t\tthis.classList.add('progress-low');\n\t\t}\n\t}\n\n\t#formatCurrency(amount) {\n\t\t// Basic currency formatting - could be enhanced with locale/currency options\n\t\treturn new Intl.NumberFormat('en-US', {\n\t\t\tstyle: 'currency',\n\t\t\tcurrency: 'USD',\n\t\t\tminimumFractionDigits: 2,\n\t\t\tmaximumFractionDigits: 2,\n\t\t}).format(amount);\n\t}\n\n\t/**\n\t * Public API: Set the progress percentage directly\n\t * @param {number} percent - Progress percentage (0-100)\n\t */\n\tsetPercent(percent) {\n\t\tconst clampedPercent = Math.max(0, Math.min(100, percent));\n\t\tthis.#progressPercent = clampedPercent;\n\n\t\tif (this.#progressBar) {\n\t\t\tthis.#progressBar.setPercent(clampedPercent);\n\t\t}\n\n\t\t// Calculate current amount based on percentage\n\t\tthis.#currentAmount = (clampedPercent / 100) * this.#minAmount;\n\t\tthis.setAttribute('current', this.#currentAmount.toString());\n\n\t\tthis.#updateMessages();\n\t\tthis.#updateComponentState();\n\t}\n\n\t/**\n\t * Public API: Set the current cart amount\n\t * @param {number} amount - Current cart amount\n\t */\n\tsetCurrentAmount(amount) {\n\t\tthis.#currentAmount = parseFloat(amount) || 0;\n\t\tthis.setAttribute('current', this.#currentAmount.toString());\n\t\tthis.#updateProgress();\n\t}\n\n\t/**\n\t * Public API: Set the threshold amount for free shipping\n\t * @param {number} amount - Threshold amount for free shipping\n\t */\n\tsetThresholdAmount(amount) {\n\t\tthis.#minAmount = parseFloat(amount) || 0;\n\t\tthis.setAttribute('threshold', this.#minAmount.toString());\n\t\tthis.#updateProgress();\n\t}\n\n\t/**\n\t * Public API: Set the minimum amount for free shipping (deprecated - use setThresholdAmount)\n\t * @param {number} amount - Minimum amount threshold\n\t * @deprecated Use setThresholdAmount instead\n\t */\n\tsetMinAmount(amount) {\n\t\tthis.setThresholdAmount(amount);\n\t}\n\n\t/**\n\t * Public API: Get current progress information\n\t */\n\tgetProgress() {\n\t\treturn {\n\t\t\tcurrentAmount: this.#currentAmount,\n\t\t\tthresholdAmount: this.#minAmount,\n\t\t\tminAmount: this.#minAmount, // backwards compatibility\n\t\t\tremainingAmount: Math.max(0, this.#minAmount - this.#currentAmount),\n\t\t\tpercent: this.#progressPercent,\n\t\t\tisComplete: this.#currentAmount >= this.#minAmount,\n\t\t};\n\t}\n\n\t/**\n\t * Public API: Update message templates\n\t * @param {string} aboveMessage - Message template for above the bar\n\t * @param {string} belowMessage - Message template for below the bar\n\t */\n\tsetMessages(aboveMessage = null, belowMessage = null) {\n\t\tif (aboveMessage !== null) {\n\t\t\tthis.#originalAboveMessage = aboveMessage;\n\t\t\tthis.setAttribute('message-above', aboveMessage);\n\t\t}\n\n\t\tif (belowMessage !== null) {\n\t\t\tthis.#originalBelowMessage = belowMessage;\n\t\t\tthis.setAttribute('message-below', belowMessage);\n\t\t}\n\n\t\tthis.#updateMessages();\n\t}\n\n\t// Getters\n\tget currentAmount() {\n\t\treturn this.#currentAmount;\n\t}\n\tget thresholdAmount() {\n\t\treturn this.#minAmount;\n\t}\n\tget minAmount() {\n\t\treturn this.#minAmount;\n\t} // backwards compatibility\n\tget percent() {\n\t\treturn this.#progressPercent;\n\t}\n\tget isComplete() {\n\t\treturn this.#currentAmount >= this.#minAmount;\n\t}\n}\n\n// Define CartProgressBar custom element\ncustomElements.define('cart-progress-bar', CartProgressBar);\n\n// Export components for external use\nexport { CartProgressBar, ProgressBar };\n"],"names":[],"mappings":"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"}