@magic-spells/cart-progress-bar 0.2.1 → 1.0.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.
@@ -10,23 +10,18 @@
10
10
  class ProgressBar extends HTMLElement {
11
11
  constructor() {
12
12
  super();
13
- this.#setupProgressBar();
14
- }
15
-
16
- #setupProgressBar() {
17
- this.setAttribute('role', 'progressbar');
18
- this.setAttribute('aria-valuemin', '0');
19
- this.setAttribute('aria-valuemax', '100');
20
- this.setAttribute('aria-valuenow', '0');
21
-
22
- // Create the visual progress bar
23
- this.innerHTML = '<div class="progress-bar-fill"></div>';
13
+ const _ = this;
14
+ _.setAttribute('role', 'progressbar');
15
+ _.setAttribute('aria-valuemin', '0');
16
+ _.setAttribute('aria-valuemax', '100');
17
+ _.setAttribute('aria-valuenow', '0');
18
+ _.innerHTML = '<div class="progress-bar-fill"></div>';
24
19
  }
25
20
 
26
21
  setPercent(percent) {
27
- const clampedPercent = Math.max(0, Math.min(100, percent));
28
- this.style.setProperty('--cart-progress-percent', `${clampedPercent}%`);
29
- this.setAttribute('aria-valuenow', clampedPercent);
22
+ const p = Math.max(0, Math.min(100, percent));
23
+ this.style.setProperty('--cart-progress-percent', `${p}%`);
24
+ this.setAttribute('aria-valuenow', p);
30
25
  }
31
26
  }
32
27
 
@@ -38,295 +33,230 @@
38
33
  */
39
34
  class CartProgressBar extends HTMLElement {
40
35
  // Private fields
41
- #minAmount = 0;
42
- #currentAmount = 0;
43
- #progressPercent = 0;
44
- #originalAboveMessage = '';
45
- #originalBelowMessage = '';
46
- #progressBar = null;
47
- #messageElement = null;
48
-
49
- /**
50
- * Define which attributes should be observed for changes
51
- */
36
+ #threshold = 0;
37
+ #current = 0;
38
+ #percent = 0;
39
+ #msgAbove = '';
40
+ #msgBelow = '';
41
+ #bar = null;
42
+ #msgEl = null;
43
+ #moneyFmt = null;
44
+ #debounce = null;
45
+
52
46
  static get observedAttributes() {
53
- return ['threshold', 'current', 'message-above', 'message-below'];
47
+ return ['threshold', 'current', 'message-above', 'message-below', 'money-format'];
54
48
  }
55
49
 
56
50
  constructor() {
57
51
  super();
58
- this.#init();
59
- }
60
-
61
- #init() {
62
- // Read initial attributes
63
- this.#minAmount = parseFloat(this.getAttribute('threshold')) || 0;
64
- this.#currentAmount = parseFloat(this.getAttribute('current')) || 0;
65
-
66
- // Store original message templates
67
- this.#originalAboveMessage = this.getAttribute('message-above') || '';
68
- this.#originalBelowMessage = this.getAttribute('message-below') || '';
52
+ const _ = this;
53
+ _.#threshold = parseFloat(_.getAttribute('threshold')) || 0;
54
+ _.#current = parseFloat(_.getAttribute('current')) || 0;
55
+ _.#msgAbove = _.getAttribute('message-above') || '';
56
+ _.#msgBelow = _.getAttribute('message-below') || '';
57
+ _.#moneyFmt = _.getAttribute('money-format');
69
58
  }
70
59
 
71
60
  async connectedCallback() {
72
- // ensure the child custom element has been registered
73
61
  await customElements.whenDefined('progress-bar');
74
-
75
- if (!customElements.get('progress-bar')) {
76
- throw new Error('<progress-bar> must be registered before <cart-progress-bar> runs');
77
- }
78
-
79
62
  this.#render();
80
63
  this.#updateProgress();
81
64
  this.#attachListeners();
82
65
  }
83
66
 
84
- attributeChangedCallback(name, oldValue, newValue) {
85
- if (oldValue === newValue) return;
67
+ disconnectedCallback() {
68
+ if (this.#debounce) clearTimeout(this.#debounce);
69
+ }
70
+
71
+ attributeChangedCallback(name, oldVal, newVal) {
72
+ if (oldVal === newVal) return;
73
+ const _ = this;
86
74
 
87
75
  switch (name) {
88
76
  case 'threshold':
89
- this.#minAmount = parseFloat(newValue) || 0;
90
- this.#updateProgress();
77
+ _.#threshold = parseFloat(newVal) || 0;
78
+ _.#updateProgress();
91
79
  break;
92
80
  case 'current':
93
- this.#currentAmount = parseFloat(newValue) || 0;
94
- this.#updateProgress();
81
+ _.#current = parseFloat(newVal) || 0;
82
+ _.#updateProgress();
95
83
  break;
96
84
  case 'message-above':
97
- this.#originalAboveMessage = newValue || '';
98
- this.#updateMessages();
85
+ _.#msgAbove = newVal || '';
86
+ _.#updateMessages();
99
87
  break;
100
88
  case 'message-below':
101
- this.#originalBelowMessage = newValue || '';
102
- this.#updateMessages();
89
+ _.#msgBelow = newVal || '';
90
+ _.#updateMessages();
91
+ break;
92
+ case 'money-format':
93
+ _.#moneyFmt = newVal;
94
+ _.#updateMessages();
103
95
  break;
104
96
  }
105
97
  }
106
98
 
107
99
  #render() {
108
- // Find or create the message element
109
- this.#messageElement =
110
- this.querySelector('[data-content-cart-progress-message]') ||
111
- this.querySelector('p[data-content-cart-progress-message]');
112
-
113
- // Find existing progress bar (user can add their own)
114
- this.#progressBar = this.querySelector('progress-bar');
115
-
116
- // Create message element if it doesn't exist but we have message templates
117
- if (!this.#messageElement && (this.#originalAboveMessage || this.#originalBelowMessage)) {
118
- this.#messageElement = document.createElement('p');
119
- this.#messageElement.setAttribute('data-content-cart-progress-message', '');
120
- this.appendChild(this.#messageElement);
100
+ const _ = this;
101
+ // Find existing elements or create them
102
+ _.#msgEl = _.querySelector('[data-content-cart-progress-message]');
103
+ _.#bar = _.querySelector('progress-bar');
104
+
105
+ // Create message element if needed
106
+ if (!_.#msgEl && (_.#msgAbove || _.#msgBelow)) {
107
+ _.#msgEl = document.createElement('p');
108
+ _.#msgEl.setAttribute('data-content-cart-progress-message', '');
109
+ _.appendChild(_.#msgEl);
121
110
  }
122
111
 
123
- // Create progress bar if it doesn't exist - add it at the end (below text message)
124
- if (!this.#progressBar) {
125
- // Ensure progress-bar is defined before creating
126
- if (customElements.get('progress-bar')) {
127
- this.#progressBar = document.createElement('progress-bar');
128
- this.appendChild(this.#progressBar);
129
- } else {
130
- // Fallback: wait for definition
131
- customElements.whenDefined('progress-bar').then(() => {
132
- if (!this.#progressBar) {
133
- this.#progressBar = document.createElement('progress-bar');
134
- this.appendChild(this.#progressBar);
135
- this.#updateProgress(); // Update progress after creating
136
- }
137
- });
138
- }
112
+ // Create progress bar if needed
113
+ if (!_.#bar) {
114
+ _.#bar = document.createElement('progress-bar');
115
+ _.appendChild(_.#bar);
139
116
  }
140
117
  }
141
118
 
142
119
  #updateProgress() {
143
- if (this.#minAmount === 0) {
144
- this.#progressPercent = 100;
145
- } else {
146
- this.#progressPercent = Math.min(100, (this.#currentAmount / this.#minAmount) * 100);
147
- }
148
-
149
- // Update progress bar
150
- if (this.#progressBar) {
151
- this.#progressBar.setPercent(this.#progressPercent);
152
- }
153
-
154
- // Update messages
155
- this.#updateMessages();
156
-
157
- // Update component state
158
- this.#updateComponentState();
120
+ const _ = this;
121
+ const converted = _.#converted();
122
+ _.#percent = converted === 0 ? 100 : Math.min(100, (_.#current / converted) * 100);
123
+ if (_.#bar) _.#bar.setPercent(_.#percent);
124
+ _.#updateState(converted);
159
125
  }
160
126
 
161
127
  #attachListeners() {
162
- // Find the nearest cart-panel component
163
- const cartDialog = this.closest('cart-dialog');
164
-
165
- if (cartDialog) {
166
- // Listen for cart data changes
167
- cartDialog.addEventListener('cart-dialog:data-changed', (event) => {
168
- this.#handleCartDataChange(event);
169
- });
128
+ const _ = this;
129
+ const panel = _.closest('cart-panel');
130
+ if (panel) {
131
+ panel.addEventListener('cart-panel:data-changed', (e) => _.#onCartChange(e));
170
132
  }
171
133
  }
172
134
 
173
- #handleCartDataChange(event) {
174
- const updatedCart = event.detail;
175
-
176
- if (updatedCart) {
177
- // Use calculated_subtotal if available (handles _ignore_price_in_subtotal logic)
178
- // Otherwise fall back to total_price for backwards compatibility
179
- let currentAmount = 0;
180
-
181
- if (typeof updatedCart.calculated_subtotal !== 'undefined') {
182
- // calculated_subtotal is already in dollars, no conversion needed
183
- currentAmount = updatedCart.calculated_subtotal / 100;
184
- } else if (typeof updatedCart.total_price !== 'undefined') {
185
- // Convert from cents to dollars if needed (Shopify typically returns cents)
186
- currentAmount = updatedCart.total_price / 100;
187
- }
188
-
189
- this.setCurrentAmount(currentAmount);
190
- }
135
+ #onCartChange(event) {
136
+ const _ = this;
137
+ const cart = event.detail;
138
+ if (!cart) return;
139
+
140
+ if (_.#debounce) clearTimeout(_.#debounce);
141
+ _.#debounce = setTimeout(() => {
142
+ _.#debounce = null;
143
+ // Use calculated_subtotal if available, else total_price (both in cents)
144
+ const amt = (cart.calculated_subtotal ?? cart.total_price ?? 0) / 100;
145
+ _.setCurrentAmount(amt);
146
+ }, 100);
191
147
  }
192
148
 
193
- #updateMessages() {
194
- const isComplete = this.#currentAmount >= this.#minAmount;
195
- const remainingAmount = Math.max(0, this.#minAmount - this.#currentAmount);
196
-
197
- // Format amount with minimal formatting
198
- const formattedAmount = remainingAmount.toFixed(2).replace('.00', '');
199
-
200
- // Update the single message element
201
- if (this.#messageElement) {
202
- let messageTemplate;
203
-
204
- if (isComplete && this.#originalAboveMessage) {
205
- // Show success message when complete
206
- messageTemplate = this.#originalAboveMessage;
207
- } else if (!isComplete) {
208
- // Show progress message when incomplete
209
- messageTemplate = this.#originalBelowMessage || this.#originalAboveMessage;
210
- }
211
-
212
- if (messageTemplate) {
213
- // Support multiple placeholder formats: {amount}, { amount }, [amount]
214
- const message = messageTemplate
215
- .replace(/\{\s*amount\s*\}/g, formattedAmount)
216
- .replace(/\[\s*amount\s*\]/g, formattedAmount);
217
- this.#messageElement.textContent = message;
218
- this.#messageElement.style.display = 'block';
149
+ #updateState(converted) {
150
+ const _ = this;
151
+ const complete = _.#current >= converted;
152
+ const remaining = Math.max(0, converted - _.#current);
153
+ const formatted = _.#fmtMoney(remaining);
154
+
155
+ // Update message
156
+ if (_.#msgEl) {
157
+ let tpl = complete ? _.#msgAbove : (_.#msgBelow || _.#msgAbove);
158
+ if (tpl) {
159
+ _.#msgEl.textContent = tpl.replace(/\[\s*amount\s*\]/g, formatted);
160
+ _.#msgEl.style.display = 'block';
219
161
  } else {
220
- // Hide message if no template available for current state
221
- this.#messageElement.style.display = 'none';
162
+ _.#msgEl.style.display = 'none';
222
163
  }
223
164
  }
224
- }
225
165
 
226
- #updateComponentState() {
227
- const isComplete = this.#currentAmount >= this.#minAmount;
228
- this.setAttribute('complete', isComplete.toString());
166
+ // Update complete attribute
167
+ _.setAttribute('complete', complete.toString());
229
168
  }
230
169
 
170
+ #fmtMoney(amt) {
171
+ const fmt = this.#moneyFmt;
172
+ if (!fmt) return amt.toFixed(2).replace(/\.00$/, '');
231
173
 
232
- /**
233
- * Public API: Set the progress percentage directly
234
- * @param {number} percent - Progress percentage (0-100)
235
- */
236
- setPercent(percent) {
237
- const clampedPercent = Math.max(0, Math.min(100, percent));
238
- this.#progressPercent = clampedPercent;
174
+ const fixed = amt.toFixed(2);
175
+ const noDecimals = Math.round(amt).toString();
176
+ const withComma = fixed.replace('.', ',');
177
+ const noDecWithComma = noDecimals.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
239
178
 
240
- if (this.#progressBar) {
241
- this.#progressBar.setPercent(clampedPercent);
242
- }
179
+ return fmt
180
+ .replace(/\{\{\s*amount_no_decimals_with_comma_separator\s*\}\}/g, noDecWithComma)
181
+ .replace(/\{\{\s*amount_with_comma_separator\s*\}\}/g, withComma)
182
+ .replace(/\{\{\s*amount_no_decimals\s*\}\}/g, noDecimals)
183
+ .replace(/\{\{\s*amount\s*\}\}/g, fixed);
184
+ }
185
+
186
+ #converted() {
187
+ const rate = parseFloat(window.Shopify?.currency?.rate) || 1;
188
+ return this.#threshold * rate;
189
+ }
243
190
 
244
- // Calculate current amount based on percentage
245
- this.#currentAmount = (clampedPercent / 100) * this.#minAmount;
246
- this.setAttribute('current', this.#currentAmount.toString());
191
+ #updateMessages() {
192
+ this.#updateState(this.#converted());
193
+ }
247
194
 
248
- this.#updateMessages();
249
- this.#updateComponentState();
195
+ // Public API
196
+ setPercent(pct) {
197
+ const _ = this;
198
+ const p = Math.max(0, Math.min(100, pct));
199
+ _.#percent = p;
200
+ if (_.#bar) _.#bar.setPercent(p);
201
+ // Use converted threshold for multi-currency consistency
202
+ _.#current = (p / 100) * _.#converted();
203
+ _.setAttribute('current', _.#current.toString());
204
+ _.#updateState(_.#converted());
250
205
  }
251
206
 
252
- /**
253
- * Public API: Set the current cart amount
254
- * @param {number} amount - Current cart amount
255
- */
256
- setCurrentAmount(amount) {
257
- this.#currentAmount = parseFloat(amount) || 0;
258
- this.setAttribute('current', this.#currentAmount.toString());
259
- this.#updateProgress();
207
+ setCurrentAmount(amt) {
208
+ const _ = this;
209
+ _.#current = parseFloat(amt) || 0;
210
+ _.setAttribute('current', _.#current.toString());
211
+ _.#updateProgress();
260
212
  }
261
213
 
262
- /**
263
- * Public API: Set the threshold amount for free shipping
264
- * @param {number} amount - Threshold amount for free shipping
265
- */
266
- setThresholdAmount(amount) {
267
- this.#minAmount = parseFloat(amount) || 0;
268
- this.setAttribute('threshold', this.#minAmount.toString());
269
- this.#updateProgress();
214
+ setThresholdAmount(amt) {
215
+ const _ = this;
216
+ _.#threshold = parseFloat(amt) || 0;
217
+ _.setAttribute('threshold', _.#threshold.toString());
218
+ _.#updateProgress();
270
219
  }
271
220
 
272
- /**
273
- * Public API: Set the minimum amount for free shipping (deprecated - use setThresholdAmount)
274
- * @param {number} amount - Minimum amount threshold
275
- * @deprecated Use setThresholdAmount instead
276
- */
277
- setMinAmount(amount) {
278
- this.setThresholdAmount(amount);
221
+ /** @deprecated Use setThresholdAmount */
222
+ setMinAmount(amt) {
223
+ this.setThresholdAmount(amt);
279
224
  }
280
225
 
281
- /**
282
- * Public API: Get current progress information
283
- */
284
226
  getProgress() {
227
+ const _ = this;
228
+ const converted = _.#converted();
285
229
  return {
286
- currentAmount: this.#currentAmount,
287
- thresholdAmount: this.#minAmount,
288
- minAmount: this.#minAmount, // backwards compatibility
289
- remainingAmount: Math.max(0, this.#minAmount - this.#currentAmount),
290
- percent: this.#progressPercent,
291
- isComplete: this.#currentAmount >= this.#minAmount,
230
+ currentAmount: _.#current,
231
+ thresholdAmount: _.#threshold,
232
+ convertedThreshold: converted,
233
+ minAmount: _.#threshold,
234
+ remainingAmount: Math.max(0, converted - _.#current),
235
+ percent: _.#percent,
236
+ isComplete: _.#current >= converted,
237
+ currencyRate: parseFloat(window.Shopify?.currency?.rate) || 1,
292
238
  };
293
239
  }
294
240
 
295
- /**
296
- * Public API: Update message templates
297
- * @param {string} aboveMessage - Message template for above the bar
298
- * @param {string} belowMessage - Message template for below the bar
299
- */
300
- setMessages(aboveMessage = null, belowMessage = null) {
301
- if (aboveMessage !== null) {
302
- this.#originalAboveMessage = aboveMessage;
303
- this.setAttribute('message-above', aboveMessage);
241
+ setMessages(above = null, below = null) {
242
+ const _ = this;
243
+ if (above !== null) {
244
+ _.#msgAbove = above;
245
+ _.setAttribute('message-above', above);
304
246
  }
305
-
306
- if (belowMessage !== null) {
307
- this.#originalBelowMessage = belowMessage;
308
- this.setAttribute('message-below', belowMessage);
247
+ if (below !== null) {
248
+ _.#msgBelow = below;
249
+ _.setAttribute('message-below', below);
309
250
  }
310
-
311
- this.#updateMessages();
251
+ _.#updateMessages();
312
252
  }
313
253
 
314
- // Getters
315
- get currentAmount() {
316
- return this.#currentAmount;
317
- }
318
- get thresholdAmount() {
319
- return this.#minAmount;
320
- }
321
- get minAmount() {
322
- return this.#minAmount;
323
- } // backwards compatibility
324
- get percent() {
325
- return this.#progressPercent;
326
- }
327
- get isComplete() {
328
- return this.#currentAmount >= this.#minAmount;
329
- }
254
+ // Getters (with backwards compatibility)
255
+ get currentAmount() { return this.#current; }
256
+ get thresholdAmount() { return this.#threshold; }
257
+ get minAmount() { return this.#threshold; }
258
+ get percent() { return this.#percent; }
259
+ get isComplete() { return this.#current >= this.#converted(); }
330
260
  }
331
261
 
332
262
  // Define CartProgressBar custom element
@@ -1 +1 @@
1
- {"version":3,"file":"cart-progress-bar.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 cartDialog = this.closest('cart-dialog');\n\n\t\tif (cartDialog) {\n\t\t\t// Listen for cart data changes\n\t\t\tcartDialog.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) {\n\t\t\t// Use calculated_subtotal if available (handles _ignore_price_in_subtotal logic)\n\t\t\t// Otherwise fall back to total_price for backwards compatibility\n\t\t\tlet currentAmount = 0;\n\n\t\t\tif (typeof updatedCart.calculated_subtotal !== 'undefined') {\n\t\t\t\t// calculated_subtotal is already in dollars, no conversion needed\n\t\t\t\tcurrentAmount = updatedCart.calculated_subtotal / 100;\n\t\t\t} else if (typeof updatedCart.total_price !== 'undefined') {\n\t\t\t\t// Convert from cents to dollars if needed (Shopify typically returns cents)\n\t\t\t\tcurrentAmount = updatedCart.total_price / 100;\n\t\t\t}\n\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 amount with minimal formatting\n\t\tconst formattedAmount = remainingAmount.toFixed(2).replace('.00', '');\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\t// Support multiple placeholder formats: {amount}, { amount }, [amount]\n\t\t\t\tconst message = messageTemplate\n\t\t\t\t\t.replace(/\\{\\s*amount\\s*\\}/g, formattedAmount)\n\t\t\t\t\t.replace(/\\[\\s*amount\\s*\\]/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\t\tthis.setAttribute('complete', isComplete.toString());\n\t}\n\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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"}
1
+ {"version":3,"file":"cart-progress-bar.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\tconst _ = this;\n\t\t_.setAttribute('role', 'progressbar');\n\t\t_.setAttribute('aria-valuemin', '0');\n\t\t_.setAttribute('aria-valuemax', '100');\n\t\t_.setAttribute('aria-valuenow', '0');\n\t\t_.innerHTML = '<div class=\"progress-bar-fill\"></div>';\n\t}\n\n\tsetPercent(percent) {\n\t\tconst p = Math.max(0, Math.min(100, percent));\n\t\tthis.style.setProperty('--cart-progress-percent', `${p}%`);\n\t\tthis.setAttribute('aria-valuenow', p);\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#threshold = 0;\n\t#current = 0;\n\t#percent = 0;\n\t#msgAbove = '';\n\t#msgBelow = '';\n\t#bar = null;\n\t#msgEl = null;\n\t#moneyFmt = null;\n\t#debounce = null;\n\n\tstatic get observedAttributes() {\n\t\treturn ['threshold', 'current', 'message-above', 'message-below', 'money-format'];\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\t\t_.#threshold = parseFloat(_.getAttribute('threshold')) || 0;\n\t\t_.#current = parseFloat(_.getAttribute('current')) || 0;\n\t\t_.#msgAbove = _.getAttribute('message-above') || '';\n\t\t_.#msgBelow = _.getAttribute('message-below') || '';\n\t\t_.#moneyFmt = _.getAttribute('money-format');\n\t}\n\n\tasync connectedCallback() {\n\t\tawait customElements.whenDefined('progress-bar');\n\t\tthis.#render();\n\t\tthis.#updateProgress();\n\t\tthis.#attachListeners();\n\t}\n\n\tdisconnectedCallback() {\n\t\tif (this.#debounce) clearTimeout(this.#debounce);\n\t}\n\n\tattributeChangedCallback(name, oldVal, newVal) {\n\t\tif (oldVal === newVal) return;\n\t\tconst _ = this;\n\n\t\tswitch (name) {\n\t\t\tcase 'threshold':\n\t\t\t\t_.#threshold = parseFloat(newVal) || 0;\n\t\t\t\t_.#updateProgress();\n\t\t\t\tbreak;\n\t\t\tcase 'current':\n\t\t\t\t_.#current = parseFloat(newVal) || 0;\n\t\t\t\t_.#updateProgress();\n\t\t\t\tbreak;\n\t\t\tcase 'message-above':\n\t\t\t\t_.#msgAbove = newVal || '';\n\t\t\t\t_.#updateMessages();\n\t\t\t\tbreak;\n\t\t\tcase 'message-below':\n\t\t\t\t_.#msgBelow = newVal || '';\n\t\t\t\t_.#updateMessages();\n\t\t\t\tbreak;\n\t\t\tcase 'money-format':\n\t\t\t\t_.#moneyFmt = newVal;\n\t\t\t\t_.#updateMessages();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t#render() {\n\t\tconst _ = this;\n\t\t// Find existing elements or create them\n\t\t_.#msgEl = _.querySelector('[data-content-cart-progress-message]');\n\t\t_.#bar = _.querySelector('progress-bar');\n\n\t\t// Create message element if needed\n\t\tif (!_.#msgEl && (_.#msgAbove || _.#msgBelow)) {\n\t\t\t_.#msgEl = document.createElement('p');\n\t\t\t_.#msgEl.setAttribute('data-content-cart-progress-message', '');\n\t\t\t_.appendChild(_.#msgEl);\n\t\t}\n\n\t\t// Create progress bar if needed\n\t\tif (!_.#bar) {\n\t\t\t_.#bar = document.createElement('progress-bar');\n\t\t\t_.appendChild(_.#bar);\n\t\t}\n\t}\n\n\t#updateProgress() {\n\t\tconst _ = this;\n\t\tconst converted = _.#converted();\n\t\t_.#percent = converted === 0 ? 100 : Math.min(100, (_.#current / converted) * 100);\n\t\tif (_.#bar) _.#bar.setPercent(_.#percent);\n\t\t_.#updateState(converted);\n\t}\n\n\t#attachListeners() {\n\t\tconst _ = this;\n\t\tconst panel = _.closest('cart-panel');\n\t\tif (panel) {\n\t\t\tpanel.addEventListener('cart-panel:data-changed', (e) => _.#onCartChange(e));\n\t\t}\n\t}\n\n\t#onCartChange(event) {\n\t\tconst _ = this;\n\t\tconst cart = event.detail;\n\t\tif (!cart) return;\n\n\t\tif (_.#debounce) clearTimeout(_.#debounce);\n\t\t_.#debounce = setTimeout(() => {\n\t\t\t_.#debounce = null;\n\t\t\t// Use calculated_subtotal if available, else total_price (both in cents)\n\t\t\tconst amt = (cart.calculated_subtotal ?? cart.total_price ?? 0) / 100;\n\t\t\t_.setCurrentAmount(amt);\n\t\t}, 100);\n\t}\n\n\t#updateState(converted) {\n\t\tconst _ = this;\n\t\tconst complete = _.#current >= converted;\n\t\tconst remaining = Math.max(0, converted - _.#current);\n\t\tconst formatted = _.#fmtMoney(remaining);\n\n\t\t// Update message\n\t\tif (_.#msgEl) {\n\t\t\tlet tpl = complete ? _.#msgAbove : (_.#msgBelow || _.#msgAbove);\n\t\t\tif (tpl) {\n\t\t\t\t_.#msgEl.textContent = tpl.replace(/\\[\\s*amount\\s*\\]/g, formatted);\n\t\t\t\t_.#msgEl.style.display = 'block';\n\t\t\t} else {\n\t\t\t\t_.#msgEl.style.display = 'none';\n\t\t\t}\n\t\t}\n\n\t\t// Update complete attribute\n\t\t_.setAttribute('complete', complete.toString());\n\t}\n\n\t#fmtMoney(amt) {\n\t\tconst fmt = this.#moneyFmt;\n\t\tif (!fmt) return amt.toFixed(2).replace(/\\.00$/, '');\n\n\t\tconst fixed = amt.toFixed(2);\n\t\tconst noDecimals = Math.round(amt).toString();\n\t\tconst withComma = fixed.replace('.', ',');\n\t\tconst noDecWithComma = noDecimals.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n\n\t\treturn fmt\n\t\t\t.replace(/\\{\\{\\s*amount_no_decimals_with_comma_separator\\s*\\}\\}/g, noDecWithComma)\n\t\t\t.replace(/\\{\\{\\s*amount_with_comma_separator\\s*\\}\\}/g, withComma)\n\t\t\t.replace(/\\{\\{\\s*amount_no_decimals\\s*\\}\\}/g, noDecimals)\n\t\t\t.replace(/\\{\\{\\s*amount\\s*\\}\\}/g, fixed);\n\t}\n\n\t#converted() {\n\t\tconst rate = parseFloat(window.Shopify?.currency?.rate) || 1;\n\t\treturn this.#threshold * rate;\n\t}\n\n\t#updateMessages() {\n\t\tthis.#updateState(this.#converted());\n\t}\n\n\t// Public API\n\tsetPercent(pct) {\n\t\tconst _ = this;\n\t\tconst p = Math.max(0, Math.min(100, pct));\n\t\t_.#percent = p;\n\t\tif (_.#bar) _.#bar.setPercent(p);\n\t\t// Use converted threshold for multi-currency consistency\n\t\t_.#current = (p / 100) * _.#converted();\n\t\t_.setAttribute('current', _.#current.toString());\n\t\t_.#updateState(_.#converted());\n\t}\n\n\tsetCurrentAmount(amt) {\n\t\tconst _ = this;\n\t\t_.#current = parseFloat(amt) || 0;\n\t\t_.setAttribute('current', _.#current.toString());\n\t\t_.#updateProgress();\n\t}\n\n\tsetThresholdAmount(amt) {\n\t\tconst _ = this;\n\t\t_.#threshold = parseFloat(amt) || 0;\n\t\t_.setAttribute('threshold', _.#threshold.toString());\n\t\t_.#updateProgress();\n\t}\n\n\t/** @deprecated Use setThresholdAmount */\n\tsetMinAmount(amt) {\n\t\tthis.setThresholdAmount(amt);\n\t}\n\n\tgetProgress() {\n\t\tconst _ = this;\n\t\tconst converted = _.#converted();\n\t\treturn {\n\t\t\tcurrentAmount: _.#current,\n\t\t\tthresholdAmount: _.#threshold,\n\t\t\tconvertedThreshold: converted,\n\t\t\tminAmount: _.#threshold,\n\t\t\tremainingAmount: Math.max(0, converted - _.#current),\n\t\t\tpercent: _.#percent,\n\t\t\tisComplete: _.#current >= converted,\n\t\t\tcurrencyRate: parseFloat(window.Shopify?.currency?.rate) || 1,\n\t\t};\n\t}\n\n\tsetMessages(above = null, below = null) {\n\t\tconst _ = this;\n\t\tif (above !== null) {\n\t\t\t_.#msgAbove = above;\n\t\t\t_.setAttribute('message-above', above);\n\t\t}\n\t\tif (below !== null) {\n\t\t\t_.#msgBelow = below;\n\t\t\t_.setAttribute('message-below', below);\n\t\t}\n\t\t_.#updateMessages();\n\t}\n\n\t// Getters (with backwards compatibility)\n\tget currentAmount() { return this.#current; }\n\tget thresholdAmount() { return this.#threshold; }\n\tget minAmount() { return this.#threshold; }\n\tget percent() { return this.#percent; }\n\tget isComplete() { return this.#current >= this.#converted(); }\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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"}
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).CartProgressBar={})}(this,function(e){"use strict";class ProgressBar extends HTMLElement{constructor(){super(),this.#e()}#e(){this.setAttribute("role","progressbar"),this.setAttribute("aria-valuemin","0"),this.setAttribute("aria-valuemax","100"),this.setAttribute("aria-valuenow","0"),this.innerHTML='<div class="progress-bar-fill"></div>'}setPercent(e){const t=Math.max(0,Math.min(100,e));this.style.setProperty("--cart-progress-percent",`${t}%`),this.setAttribute("aria-valuenow",t)}}customElements.define("progress-bar",ProgressBar);class CartProgressBar extends HTMLElement{#t=0;#s=0;#r=0;#i="";#n="";#a=null;#o=null;static get observedAttributes(){return["threshold","current","message-above","message-below"]}constructor(){super(),this.#h()}#h(){this.#t=parseFloat(this.getAttribute("threshold"))||0,this.#s=parseFloat(this.getAttribute("current"))||0,this.#i=this.getAttribute("message-above")||"",this.#n=this.getAttribute("message-below")||""}async connectedCallback(){if(await customElements.whenDefined("progress-bar"),!customElements.get("progress-bar"))throw new Error("<progress-bar> must be registered before <cart-progress-bar> runs");this.#u(),this.#g(),this.#m()}attributeChangedCallback(e,t,s){if(t!==s)switch(e){case"threshold":this.#t=parseFloat(s)||0,this.#g();break;case"current":this.#s=parseFloat(s)||0,this.#g();break;case"message-above":this.#i=s||"",this.#l();break;case"message-below":this.#n=s||"",this.#l()}}#u(){this.#o=this.querySelector("[data-content-cart-progress-message]")||this.querySelector("p[data-content-cart-progress-message]"),this.#a=this.querySelector("progress-bar"),this.#o||!this.#i&&!this.#n||(this.#o=document.createElement("p"),this.#o.setAttribute("data-content-cart-progress-message",""),this.appendChild(this.#o)),this.#a||(customElements.get("progress-bar")?(this.#a=document.createElement("progress-bar"),this.appendChild(this.#a)):customElements.whenDefined("progress-bar").then(()=>{this.#a||(this.#a=document.createElement("progress-bar"),this.appendChild(this.#a),this.#g())}))}#g(){0===this.#t?this.#r=100:this.#r=Math.min(100,this.#s/this.#t*100),this.#a&&this.#a.setPercent(this.#r),this.#l(),this.#c()}#m(){const e=this.closest("cart-dialog");e&&e.addEventListener("cart-dialog:data-changed",e=>{this.#p(e)})}#p(e){const t=e.detail;if(t){let e=0;void 0!==t.calculated_subtotal?e=t.calculated_subtotal/100:void 0!==t.total_price&&(e=t.total_price/100),this.setCurrentAmount(e)}}#l(){const e=this.#s>=this.#t,t=Math.max(0,this.#t-this.#s).toFixed(2).replace(".00","");if(this.#o){let s;if(e&&this.#i?s=this.#i:e||(s=this.#n||this.#i),s){const e=s.replace(/\{\s*amount\s*\}/g,t).replace(/\[\s*amount\s*\]/g,t);this.#o.textContent=e,this.#o.style.display="block"}else this.#o.style.display="none"}}#c(){const e=this.#s>=this.#t;this.setAttribute("complete",e.toString())}setPercent(e){const t=Math.max(0,Math.min(100,e));this.#r=t,this.#a&&this.#a.setPercent(t),this.#s=t/100*this.#t,this.setAttribute("current",this.#s.toString()),this.#l(),this.#c()}setCurrentAmount(e){this.#s=parseFloat(e)||0,this.setAttribute("current",this.#s.toString()),this.#g()}setThresholdAmount(e){this.#t=parseFloat(e)||0,this.setAttribute("threshold",this.#t.toString()),this.#g()}setMinAmount(e){this.setThresholdAmount(e)}getProgress(){return{currentAmount:this.#s,thresholdAmount:this.#t,minAmount:this.#t,remainingAmount:Math.max(0,this.#t-this.#s),percent:this.#r,isComplete:this.#s>=this.#t}}setMessages(e=null,t=null){null!==e&&(this.#i=e,this.setAttribute("message-above",e)),null!==t&&(this.#n=t,this.setAttribute("message-below",t)),this.#l()}get currentAmount(){return this.#s}get thresholdAmount(){return this.#t}get minAmount(){return this.#t}get percent(){return this.#r}get isComplete(){return this.#s>=this.#t}}customElements.define("cart-progress-bar",CartProgressBar),e.CartProgressBar=CartProgressBar,e.ProgressBar=ProgressBar});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).CartProgressBar={})}(this,function(e){"use strict";class ProgressBar extends HTMLElement{constructor(){super();const e=this;e.setAttribute("role","progressbar"),e.setAttribute("aria-valuemin","0"),e.setAttribute("aria-valuemax","100"),e.setAttribute("aria-valuenow","0"),e.innerHTML='<div class="progress-bar-fill"></div>'}setPercent(e){const t=Math.max(0,Math.min(100,e));this.style.setProperty("--cart-progress-percent",`${t}%`),this.setAttribute("aria-valuenow",t)}}customElements.define("progress-bar",ProgressBar);class CartProgressBar extends HTMLElement{#e=0;#t=0;#r=0;#s="";#a="";#o=null;#n=null;#c=null;#u=null;static get observedAttributes(){return["threshold","current","message-above","message-below","money-format"]}constructor(){super();const e=this;e.#e=parseFloat(e.getAttribute("threshold"))||0,e.#t=parseFloat(e.getAttribute("current"))||0,e.#s=e.getAttribute("message-above")||"",e.#a=e.getAttribute("message-below")||"",e.#c=e.getAttribute("money-format")}async connectedCallback(){await customElements.whenDefined("progress-bar"),this.#l(),this.#i(),this.#m()}disconnectedCallback(){this.#u&&clearTimeout(this.#u)}attributeChangedCallback(e,t,r){if(t===r)return;const s=this;switch(e){case"threshold":s.#e=parseFloat(r)||0,s.#i();break;case"current":s.#t=parseFloat(r)||0,s.#i();break;case"message-above":s.#s=r||"",s.#d();break;case"message-below":s.#a=r||"",s.#d();break;case"money-format":s.#c=r,s.#d()}}#l(){const e=this;e.#n=e.querySelector("[data-content-cart-progress-message]"),e.#o=e.querySelector("progress-bar"),e.#n||!e.#s&&!e.#a||(e.#n=document.createElement("p"),e.#n.setAttribute("data-content-cart-progress-message",""),e.appendChild(e.#n)),e.#o||(e.#o=document.createElement("progress-bar"),e.appendChild(e.#o))}#i(){const e=this,t=e.#g();e.#r=0===t?100:Math.min(100,e.#t/t*100),e.#o&&e.#o.setPercent(e.#r),e.#h(t)}#m(){const e=this,t=e.closest("cart-panel");t&&t.addEventListener("cart-panel:data-changed",t=>e.#p(t))}#p(e){const t=this,r=e.detail;r&&(t.#u&&clearTimeout(t.#u),t.#u=setTimeout(()=>{t.#u=null;const e=(r.calculated_subtotal??r.total_price??0)/100;t.setCurrentAmount(e)},100))}#h(e){const t=this,r=t.#t>=e,s=Math.max(0,e-t.#t),a=t.#b(s);if(t.#n){let e=r?t.#s:t.#a||t.#s;e?(t.#n.textContent=e.replace(/\[\s*amount\s*\]/g,a),t.#n.style.display="block"):t.#n.style.display="none"}t.setAttribute("complete",r.toString())}#b(e){const t=this.#c;if(!t)return e.toFixed(2).replace(/\.00$/,"");const r=e.toFixed(2),s=Math.round(e).toString(),a=r.replace(".",","),o=s.replace(/\B(?=(\d{3})+(?!\d))/g,",");return t.replace(/\{\{\s*amount_no_decimals_with_comma_separator\s*\}\}/g,o).replace(/\{\{\s*amount_with_comma_separator\s*\}\}/g,a).replace(/\{\{\s*amount_no_decimals\s*\}\}/g,s).replace(/\{\{\s*amount\s*\}\}/g,r)}#g(){const e=parseFloat(window.Shopify?.currency?.rate)||1;return this.#e*e}#d(){this.#h(this.#g())}setPercent(e){const t=this,r=Math.max(0,Math.min(100,e));t.#r=r,t.#o&&t.#o.setPercent(r),t.#t=r/100*t.#g(),t.setAttribute("current",t.#t.toString()),t.#h(t.#g())}setCurrentAmount(e){const t=this;t.#t=parseFloat(e)||0,t.setAttribute("current",t.#t.toString()),t.#i()}setThresholdAmount(e){const t=this;t.#e=parseFloat(e)||0,t.setAttribute("threshold",t.#e.toString()),t.#i()}setMinAmount(e){this.setThresholdAmount(e)}getProgress(){const e=this,t=e.#g();return{currentAmount:e.#t,thresholdAmount:e.#e,convertedThreshold:t,minAmount:e.#e,remainingAmount:Math.max(0,t-e.#t),percent:e.#r,isComplete:e.#t>=t,currencyRate:parseFloat(window.Shopify?.currency?.rate)||1}}setMessages(e=null,t=null){const r=this;null!==e&&(r.#s=e,r.setAttribute("message-above",e)),null!==t&&(r.#a=t,r.setAttribute("message-below",t)),r.#d()}get currentAmount(){return this.#t}get thresholdAmount(){return this.#e}get minAmount(){return this.#e}get percent(){return this.#r}get isComplete(){return this.#t>=this.#g()}}customElements.define("cart-progress-bar",CartProgressBar),e.CartProgressBar=CartProgressBar,e.ProgressBar=ProgressBar});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magic-spells/cart-progress-bar",
3
- "version": "0.2.1",
3
+ "version": "1.0.0",
4
4
  "description": "Cart progress bar web component for free shipping thresholds.",
5
5
  "author": "Cory Schulz",
6
6
  "license": "MIT",
@@ -60,11 +60,11 @@
60
60
  "not ie <= 11"
61
61
  ],
62
62
  "devDependencies": {
63
- "@eslint/js": "^8.57.0",
63
+ "@eslint/js": "^9.38.0",
64
64
  "@rollup/plugin-node-resolve": "^15.2.3",
65
65
  "@rollup/plugin-terser": "^0.4.4",
66
- "eslint": "^8.0.0",
67
- "globals": "^13.24.0",
66
+ "eslint": "^9.38.0",
67
+ "globals": "^15.15.0",
68
68
  "prettier": "^3.3.3",
69
69
  "rollup": "^3.0.0",
70
70
  "rollup-plugin-copy": "^3.5.0",