@magic-spells/cart-progress-bar 0.1.0 → 0.2.1

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 CHANGED
@@ -6,8 +6,8 @@ A beautiful, accessible cart progress bar web component for free shipping thresh
6
6
 
7
7
  ## Features
8
8
 
9
- - 🎯 **Smart Messaging** - Template-based messages with automatic currency formatting
10
- - 🎨 **Highly Customizable** - CSS custom properties for easy theming
9
+ - 🎯 **Smart Messaging** - Template-based messages with flexible placeholder formats
10
+ - 🎨 **Simplified Theming** - Just 5 CSS variables to control all colors and appearance
11
11
  - 📱 **Responsive** - Mobile-optimized with responsive breakpoints
12
12
  - ⚡ **Smooth Animations** - Buttery smooth transitions and completion effects
13
13
  - 🔧 **Easy Integration** - Drop-in web component that works with any framework
@@ -25,14 +25,14 @@ npm install @magic-spells/cart-progress-bar
25
25
  threshold="75.00"
26
26
  current="25.50"
27
27
  message-above="🎉 Congratulations! You've qualified for FREE shipping!"
28
- message-below="Add ${left} more for FREE shipping!">
29
- <p data-content-cart-progress-message>Add ${left} more for FREE shipping!</p>
28
+ message-below="Add ${ amount } more for FREE shipping!">
29
+ <p data-content-cart-progress-message>Add ${ amount } more for FREE shipping!</p>
30
30
  <progress-bar></progress-bar>
31
31
  </cart-progress-bar>
32
32
  ```
33
33
 
34
34
  ```css
35
- @import '@magic-spells/cart-progress-bar/css';
35
+ @import '@magic-spells/cart-progress-bar/css/min';
36
36
  ```
37
37
 
38
38
  ## JavaScript API
@@ -54,21 +54,30 @@ const info = progressBar.getProgress();
54
54
  console.log(info.percent, info.isComplete, info.thresholdAmount);
55
55
 
56
56
  // Update message templates
57
- progressBar.setMessages('Almost there!', 'Only ${left} more to go!');
57
+ progressBar.setMessages('Almost there!', 'Only ${ amount } more to go!');
58
58
  ```
59
59
 
60
60
  ## Cart Integration
61
61
 
62
- The component automatically listens for cart data changes when placed inside a `<cart-panel>` component:
62
+ The component automatically listens for cart data changes when placed inside a `<cart-dialog>` component from the `@magic-spells/cart-panel` package:
63
63
 
64
64
  ```html
65
- <cart-panel>
66
- <cart-progress-bar threshold="75.00" message-below="Add ${left} more for FREE shipping!">
65
+ <cart-dialog>
66
+ <cart-progress-bar threshold="75.00" message-below="Add ${ amount } more for FREE shipping!">
67
67
  </cart-progress-bar>
68
- </cart-panel>
68
+ </cart-dialog>
69
69
  ```
70
70
 
71
- When the cart-panel emits a `cart-dialog:data-changed` event (typically from Shopify cart updates), the progress bar will automatically update with the new cart total.
71
+ When the cart-dialog emits a `cart-dialog:data-changed` event (typically from Shopify cart API updates), the progress bar will automatically update with the calculated cart subtotal.
72
+
73
+ ### Smart Pricing Logic
74
+
75
+ The progress bar uses intelligent pricing calculation:
76
+
77
+ - **Preferred**: Uses `calculated_subtotal` from cart-panel (respects `_ignore_price_in_subtotal` property)
78
+ - **Fallback**: Uses `total_price` for backwards compatibility
79
+ - **Includes**: Bundle items that are hidden in cart but should count toward shipping threshold
80
+ - **Excludes**: Gift items or promotions marked with `_ignore_price_in_subtotal` property
72
81
 
73
82
  ## Attributes
74
83
 
@@ -77,7 +86,7 @@ When the cart-panel emits a `cart-dialog:data-changed` event (typically from Sho
77
86
  | `threshold` | Threshold amount for free shipping | `"75.00"` |
78
87
  | `current` | Current cart amount | `"25.50"` |
79
88
  | `message-above` | Success message when threshold is reached | `"🎉 FREE shipping unlocked!"` |
80
- | `message-below` | Message template shown below the bar | `"Add ${left} more!"` |
89
+ | `message-below` | Message template shown below the bar | `"Add ${ amount } more!"` |
81
90
 
82
91
  ## Customization
83
92
 
@@ -85,58 +94,87 @@ Use CSS custom properties to customize the appearance:
85
94
 
86
95
  ```css
87
96
  cart-progress-bar {
97
+ /* Core color customization */
98
+ --cart-progress-section-bg: #f8f9fa;
99
+ --cart-progress-section-color: #333;
100
+ --cart-progress-bar-bg: #e9ecef;
101
+ --cart-progress-bar-fill-before: #ff6b6b;
102
+ --cart-progress-bar-fill-after: #28a745;
103
+
104
+ /* Structure (optional) */
88
105
  --cart-progress-bar-height: 16px;
89
- --cart-progress-bar-fill-bg: #ff6b6b;
90
106
  --cart-progress-bar-border-radius: 8px;
91
- --cart-progress-message-font-size: 1rem;
92
- --cart-progress-message-color: #333;
93
107
  }
94
108
  ```
95
109
 
96
110
  ## Available CSS Custom Properties
97
111
 
98
- | Property | Description | Default |
99
- | ----------------------------------- | -------------------------- | ---------- |
100
- | `--cart-progress-bar-height` | Height of the progress bar | `12px` |
101
- | `--cart-progress-bar-border-radius` | Border radius | `6px` |
102
- | `--cart-progress-bar-bg` | Background color | `#e9ecef` |
103
- | `--cart-progress-bar-fill-bg` | Fill color | `#28a745` |
104
- | `--cart-progress-bar-complete-bg` | Color when complete | `#007bff` |
105
- | `--cart-progress-message-font-size` | Message font size | `0.875rem` |
106
- | `--cart-progress-message-color` | Message text color | `#495057` |
112
+ ### Core Color Variables
113
+
114
+ | Property | Description | Default |
115
+ | --------------------------------- | ------------------------------------ | ------------- |
116
+ | `--cart-progress-section-bg` | Background color of entire component | `transparent` |
117
+ | `--cart-progress-section-color` | Text/foreground color | `#495057` |
118
+ | `--cart-progress-bar-bg` | Background of progress bar track | `#e9ecef` |
119
+ | `--cart-progress-bar-fill-before` | Fill color before reaching threshold | `#28a745` |
120
+ | `--cart-progress-bar-fill-after` | Fill color after reaching threshold | `#007bff` |
121
+
122
+ ### Structure Variables (Optional)
123
+
124
+ | Property | Description | Default |
125
+ | --------------------------------------- | --------------------------------- | ------- |
126
+ | `--cart-progress-bar-height` | Height of the progress bar | `12px` |
127
+ | `--cart-progress-bar-border-radius` | Border radius | `6px` |
128
+ | `--cart-progress-bar-shadow` | Box shadow for progress bar | `inset 0 1px 2px rgba(0, 0, 0, 0.1)` |
129
+ | `--cart-progress-bar-transition-duration` | Animation transition duration | `0.3s` |
107
130
 
108
131
  ## Message Templates
109
132
 
110
- Use `${left}` in your message templates for automatic currency formatting:
133
+ Use placeholder formats in your message templates and include the currency symbol:
111
134
 
112
135
  ```html
113
136
  <cart-progress-bar
114
137
  message-above="🎉 FREE shipping unlocked!"
115
- message-below="You need ${left} more for free shipping!">
116
- <p data-content-cart-progress-message>You need ${left} more for free shipping!</p>
138
+ message-below="You need ${ amount } more for free shipping!">
139
+ <p data-content-cart-progress-message>You need ${ amount } more for free shipping!</p>
117
140
  </cart-progress-bar>
118
141
  ```
119
142
 
143
+ ### Supported Placeholder Formats
144
+
145
+ - `{ amount }` - spaces around amount
146
+ - `{amount}` - no spaces
147
+ - `[amount]` - square brackets (with or without spaces)
148
+
149
+ ### Examples
150
+
151
+ ```html
152
+ <!-- Dollar amounts -->
153
+ <cart-progress-bar message-below="Add ${ amount } more for free shipping!">
154
+
155
+ <!-- Euro amounts -->
156
+ <cart-progress-bar message-below="Only €{amount} left to unlock free delivery!">
157
+
158
+ <!-- With square brackets -->
159
+ <cart-progress-bar message-below="Just £[amount] more to go!">
160
+ ```
161
+
120
162
  The component automatically:
121
163
 
122
- - Shows `message-below` when incomplete (with `${left}` replaced)
123
- - Shows `message-above` when threshold is reached (success message)
124
- - Formats the amount as currency (USD by default)
164
+ - Shows `message-below` when incomplete (with placeholder replaced with remaining amount)
165
+ - Shows `message-above` when threshold is reached (success message)
166
+ - Formats amounts as minimal decimal numbers (removes .00 for whole amounts)
125
167
  - Updates messages when amounts change
168
+ - Switches between before/after progress bar colors based on completion status
126
169
 
127
- ## States and Classes
128
-
129
- The component automatically adds CSS classes based on progress:
170
+ ## States and Attributes
130
171
 
131
- - `.progress-low` - 0-49% progress
132
- - `.progress-medium` - 50-74% progress
133
- - `.progress-high` - 75-99% progress
134
- - `.progress-complete` - 100% progress
172
+ The component automatically sets attributes based on completion status:
135
173
 
136
- And data attributes:
174
+ - `complete="true"` - When threshold is reached
175
+ - `complete="false"` - When threshold is not reached
137
176
 
138
- - `data-complete="true"` - When threshold is reached
139
- - `data-incomplete="true"` - When threshold is not reached
177
+ These attributes are used internally to switch between the "before" and "after" progress bar colors.
140
178
 
141
179
  ## Browser Support
142
180
 
@@ -156,11 +156,11 @@ class CartProgressBar extends HTMLElement {
156
156
 
157
157
  #attachListeners() {
158
158
  // Find the nearest cart-panel component
159
- const cartPanel = this.closest('cart-panel');
159
+ const cartDialog = this.closest('cart-dialog');
160
160
 
161
- if (cartPanel) {
161
+ if (cartDialog) {
162
162
  // Listen for cart data changes
163
- cartPanel.addEventListener('cart-dialog:data-changed', (event) => {
163
+ cartDialog.addEventListener('cart-dialog:data-changed', (event) => {
164
164
  this.#handleCartDataChange(event);
165
165
  });
166
166
  }
@@ -169,9 +169,19 @@ class CartProgressBar extends HTMLElement {
169
169
  #handleCartDataChange(event) {
170
170
  const updatedCart = event.detail;
171
171
 
172
- if (updatedCart && typeof updatedCart.total_price !== 'undefined') {
173
- // Convert from cents to dollars if needed (Shopify typically returns cents)
174
- const currentAmount = updatedCart.total_price / 100;
172
+ if (updatedCart) {
173
+ // Use calculated_subtotal if available (handles _ignore_price_in_subtotal logic)
174
+ // Otherwise fall back to total_price for backwards compatibility
175
+ let currentAmount = 0;
176
+
177
+ if (typeof updatedCart.calculated_subtotal !== 'undefined') {
178
+ // calculated_subtotal is already in dollars, no conversion needed
179
+ currentAmount = updatedCart.calculated_subtotal / 100;
180
+ } else if (typeof updatedCart.total_price !== 'undefined') {
181
+ // Convert from cents to dollars if needed (Shopify typically returns cents)
182
+ currentAmount = updatedCart.total_price / 100;
183
+ }
184
+
175
185
  this.setCurrentAmount(currentAmount);
176
186
  }
177
187
  }
@@ -180,8 +190,8 @@ class CartProgressBar extends HTMLElement {
180
190
  const isComplete = this.#currentAmount >= this.#minAmount;
181
191
  const remainingAmount = Math.max(0, this.#minAmount - this.#currentAmount);
182
192
 
183
- // Format remaining amount as currency (assuming USD for now)
184
- const formattedAmount = this.#formatCurrency(remainingAmount);
193
+ // Format amount with minimal formatting
194
+ const formattedAmount = remainingAmount.toFixed(2).replace('.00', '');
185
195
 
186
196
  // Update the single message element
187
197
  if (this.#messageElement) {
@@ -196,7 +206,10 @@ class CartProgressBar extends HTMLElement {
196
206
  }
197
207
 
198
208
  if (messageTemplate) {
199
- const message = messageTemplate.replace(/\$\{left\}/g, formattedAmount);
209
+ // Support multiple placeholder formats: {amount}, { amount }, [amount]
210
+ const message = messageTemplate
211
+ .replace(/\{\s*amount\s*\}/g, formattedAmount)
212
+ .replace(/\[\s*amount\s*\]/g, formattedAmount);
200
213
  this.#messageElement.textContent = message;
201
214
  this.#messageElement.style.display = 'block';
202
215
  } else {
@@ -208,38 +221,9 @@ class CartProgressBar extends HTMLElement {
208
221
 
209
222
  #updateComponentState() {
210
223
  const isComplete = this.#currentAmount >= this.#minAmount;
211
-
212
- if (isComplete) {
213
- this.setAttribute('data-complete', 'true');
214
- this.removeAttribute('data-incomplete');
215
- } else {
216
- this.setAttribute('data-incomplete', 'true');
217
- this.removeAttribute('data-complete');
218
- }
219
-
220
- // Set progress level classes for styling
221
- this.classList.remove('progress-low', 'progress-medium', 'progress-high', 'progress-complete');
222
-
223
- if (isComplete) {
224
- this.classList.add('progress-complete');
225
- } else if (this.#progressPercent >= 75) {
226
- this.classList.add('progress-high');
227
- } else if (this.#progressPercent >= 50) {
228
- this.classList.add('progress-medium');
229
- } else {
230
- this.classList.add('progress-low');
231
- }
224
+ this.setAttribute('complete', isComplete.toString());
232
225
  }
233
226
 
234
- #formatCurrency(amount) {
235
- // Basic currency formatting - could be enhanced with locale/currency options
236
- return new Intl.NumberFormat('en-US', {
237
- style: 'currency',
238
- currency: 'USD',
239
- minimumFractionDigits: 2,
240
- maximumFractionDigits: 2,
241
- }).format(amount);
242
- }
243
227
 
244
228
  /**
245
229
  * Public API: Set the progress percentage directly
@@ -1 +1 @@
1
- {"version":3,"file":"cart-progress-bar.cjs.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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"}
1
+ {"version":3,"file":"cart-progress-bar.cjs.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,53 +1,33 @@
1
1
  cart-progress-bar {
2
2
  --cart-progress-bar-height: 12px;
3
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
4
  --cart-progress-bar-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
8
5
  --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;
6
+ --cart-progress-section-bg: transparent;
7
+ --cart-progress-section-color: #495057;
8
+ --cart-progress-bar-bg: #e9ecef;
9
+ --cart-progress-bar-fill-before: #28a745;
10
+ --cart-progress-bar-fill-after: #007bff;
14
11
  --cart-progress-percent: 0%;
12
+ --cart-progress-bar-fill-current: var(--cart-progress-bar-fill-before);
15
13
  display: block;
16
14
  width: 100%;
17
15
  max-width: 100%;
16
+ background-color: var(--cart-progress-section-bg);
17
+ color: var(--cart-progress-section-color);
18
18
  }
19
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
- }
20
+ color: inherit;
21
+ transition: opacity var(--cart-progress-bar-transition-duration) ease;
32
22
  }
33
- cart-progress-bar[data-complete=true] p[data-content-cart-progress-message] {
34
- color: var(--cart-progress-message-complete-color);
23
+ cart-progress-bar[complete=true] p[data-content-cart-progress-message] {
35
24
  font-weight: 600;
36
25
  }
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);
26
+ cart-progress-bar[complete=false] {
27
+ --cart-progress-bar-fill-current: var(--cart-progress-bar-fill-before);
48
28
  }
49
- cart-progress-bar.progress-complete p[data-content-cart-progress-message] {
50
- color: var(--cart-progress-message-complete-color);
29
+ cart-progress-bar[complete=true] {
30
+ --cart-progress-bar-fill-current: var(--cart-progress-bar-fill-after);
51
31
  }
52
32
 
53
33
  progress-bar {
@@ -63,7 +43,7 @@ progress-bar {
63
43
  progress-bar .progress-bar-fill {
64
44
  height: 100%;
65
45
  width: var(--cart-progress-percent);
66
- background-color: var(--cart-progress-bar-fill-bg);
46
+ background-color: var(--cart-progress-bar-fill-current);
67
47
  border-radius: var(--cart-progress-bar-border-radius);
68
48
  transition: width var(--cart-progress-bar-transition-duration) ease, background-color var(--cart-progress-bar-transition-duration) ease;
69
49
  position: relative;
@@ -80,52 +60,10 @@ progress-bar .progress-bar-fill::after {
80
60
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
81
61
  transition: left 0.5s ease;
82
62
  }
83
- cart-progress-bar[data-complete=true] progress-bar .progress-bar-fill::after, cart-progress-bar.progress-complete progress-bar .progress-bar-fill::after {
63
+ cart-progress-bar[complete=true] progress-bar .progress-bar-fill::after {
84
64
  left: 100%;
85
65
  }
86
66
  progress-bar:focus-visible {
87
67
  outline: 2px solid #007bff;
88
68
  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
69
  }
@@ -154,11 +154,11 @@ class CartProgressBar extends HTMLElement {
154
154
 
155
155
  #attachListeners() {
156
156
  // Find the nearest cart-panel component
157
- const cartPanel = this.closest('cart-panel');
157
+ const cartDialog = this.closest('cart-dialog');
158
158
 
159
- if (cartPanel) {
159
+ if (cartDialog) {
160
160
  // Listen for cart data changes
161
- cartPanel.addEventListener('cart-dialog:data-changed', (event) => {
161
+ cartDialog.addEventListener('cart-dialog:data-changed', (event) => {
162
162
  this.#handleCartDataChange(event);
163
163
  });
164
164
  }
@@ -167,9 +167,19 @@ class CartProgressBar extends HTMLElement {
167
167
  #handleCartDataChange(event) {
168
168
  const updatedCart = event.detail;
169
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;
170
+ if (updatedCart) {
171
+ // Use calculated_subtotal if available (handles _ignore_price_in_subtotal logic)
172
+ // Otherwise fall back to total_price for backwards compatibility
173
+ let currentAmount = 0;
174
+
175
+ if (typeof updatedCart.calculated_subtotal !== 'undefined') {
176
+ // calculated_subtotal is already in dollars, no conversion needed
177
+ currentAmount = updatedCart.calculated_subtotal / 100;
178
+ } else if (typeof updatedCart.total_price !== 'undefined') {
179
+ // Convert from cents to dollars if needed (Shopify typically returns cents)
180
+ currentAmount = updatedCart.total_price / 100;
181
+ }
182
+
173
183
  this.setCurrentAmount(currentAmount);
174
184
  }
175
185
  }
@@ -178,8 +188,8 @@ class CartProgressBar extends HTMLElement {
178
188
  const isComplete = this.#currentAmount >= this.#minAmount;
179
189
  const remainingAmount = Math.max(0, this.#minAmount - this.#currentAmount);
180
190
 
181
- // Format remaining amount as currency (assuming USD for now)
182
- const formattedAmount = this.#formatCurrency(remainingAmount);
191
+ // Format amount with minimal formatting
192
+ const formattedAmount = remainingAmount.toFixed(2).replace('.00', '');
183
193
 
184
194
  // Update the single message element
185
195
  if (this.#messageElement) {
@@ -194,7 +204,10 @@ class CartProgressBar extends HTMLElement {
194
204
  }
195
205
 
196
206
  if (messageTemplate) {
197
- const message = messageTemplate.replace(/\$\{left\}/g, formattedAmount);
207
+ // Support multiple placeholder formats: {amount}, { amount }, [amount]
208
+ const message = messageTemplate
209
+ .replace(/\{\s*amount\s*\}/g, formattedAmount)
210
+ .replace(/\[\s*amount\s*\]/g, formattedAmount);
198
211
  this.#messageElement.textContent = message;
199
212
  this.#messageElement.style.display = 'block';
200
213
  } else {
@@ -206,38 +219,9 @@ class CartProgressBar extends HTMLElement {
206
219
 
207
220
  #updateComponentState() {
208
221
  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
- }
222
+ this.setAttribute('complete', isComplete.toString());
230
223
  }
231
224
 
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
225
 
242
226
  /**
243
227
  * Public API: Set the progress percentage directly