@magic-spells/gift-with-purchase 1.0.0 → 2.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A powerful, e-commerce web component for automatic gift-with-purchase threshold promotions. Seamlessly integrates with Shopify and automatically manages gift items in the cart based on spending thresholds.
4
4
 
5
- [**Live Demo**](https://magic-spells.github.io/gift-with-purchase/demo/)
5
+ [**Live Demo**](https://magic-spells.github.io/cart/)
6
6
 
7
7
  ## Features
8
8
 
@@ -11,7 +11,7 @@ A powerful, e-commerce web component for automatic gift-with-purchase threshold
11
11
  - 📱 **Cart Panel Sync** - Automatically syncs with cart-panel components using `calculated_subtotal`
12
12
  - 🎨 **Highly Customizable** - CSS custom properties and swappable content elements
13
13
  - ⚡ **Event-Driven** - Custom events for gift addition, removal, and errors
14
- - 🔧 **Flexible Content** - Data attributes for dynamic image, title, and variant updates
14
+ - 🔧 **Flexible Content** - Your own markup inside the element; the component only writes the `[data-content-gwp-message]` element
15
15
  - 📱 **Responsive** - Mobile-optimized with responsive design
16
16
 
17
17
  ## Installation
@@ -20,12 +20,36 @@ A powerful, e-commerce web component for automatic gift-with-purchase threshold
20
20
  npm install @magic-spells/gift-with-purchase
21
21
  ```
22
22
 
23
+ The package is ESM-only. Import it once, anywhere in your bundle, to register the custom element:
24
+
25
+ ```javascript
26
+ import '@magic-spells/gift-with-purchase';
27
+ ```
28
+
29
+ The CSS is shipped as a separate file rather than injected, so load it too:
30
+
31
+ ```css
32
+ /* unminified */
33
+ @import '@magic-spells/gift-with-purchase/css';
34
+
35
+ /* or minified */
36
+ @import '@magic-spells/gift-with-purchase/css/min';
37
+ ```
38
+
39
+ Without a bundler, use the UMD build (exposes the `GiftWithPurchase` global):
40
+
41
+ ```html
42
+ <link
43
+ rel="stylesheet"
44
+ href="https://unpkg.com/@magic-spells/gift-with-purchase/dist/gift-with-purchase.min.css" />
45
+ <script src="https://unpkg.com/@magic-spells/gift-with-purchase/dist/gift-with-purchase.min.js"></script>
46
+ ```
47
+
23
48
  ## Basic Usage
24
49
 
25
50
  ```html
26
51
  <gift-with-purchase
27
52
  threshold="75.00"
28
- current="45.00"
29
53
  variant-id="12345678"
30
54
  money-format="${{amount}}"
31
55
  message-above="🎉 Congratulations! You've qualified for your FREE gift!"
@@ -41,10 +65,6 @@ npm install @magic-spells/gift-with-purchase
41
65
  </gift-with-purchase>
42
66
  ```
43
67
 
44
- ```css
45
- @import '@magic-spells/gift-with-purchase/css';
46
- ```
47
-
48
68
  ## Cart Integration
49
69
 
50
70
  The component automatically listens for cart data changes when placed inside a `<cart-panel>` component from the `@magic-spells/cart-panel` package:
@@ -108,7 +128,7 @@ console.log(gwp.isDisabled); // boolean - promo ended OR product unavaila
108
128
  | Attribute | Description | Example |
109
129
  | --------------- | -------------------------------------------------------------------- | ------------------------------------------------------------ |
110
130
  | `threshold` | Spending threshold to unlock the gift (auto-converts for multi-currency) | `"75.00"` |
111
- | `current` | Current cart amount (typically set automatically via cart-panel) | `"45.00"` |
131
+ | `current` | Optional starting amount. The component tracks the live cart total internally from `cart-panel:data-changed` and never writes this attribute back, so don't template it from Liquid | `"45.00"` |
112
132
  | `variant-id` | Shopify variant ID for the gift product | `"12345678"` |
113
133
  | `promo-ended` | Disables the promo and hides the component | `"true"` |
114
134
  | `product-available` | Whether the gift product is available (disables if false) | `"true"` |
@@ -235,7 +255,7 @@ gwp.addEventListener('gwp:removed', (event) => {
235
255
  // Error occurred during add/remove
236
256
  gwp.addEventListener('gwp:error', (event) => {
237
257
  console.error('Error:', event.detail.error);
238
- console.log('Action:', event.detail.action); // 'add' or 'remove'
258
+ console.log('Action:', event.detail.action); // 'add', 'remove', or 'trim'
239
259
  });
240
260
  ```
241
261
 
@@ -250,7 +270,7 @@ gift-with-purchase {
250
270
  --gwp-bg-active: #e8f5e8;
251
271
  --gwp-border-active: #28a745;
252
272
  --gwp-text-active: #155724;
253
- --gwp-image-size: 80px;
273
+ --gwp-gap: 1.5rem;
254
274
  }
255
275
  ```
256
276
 
@@ -278,7 +298,9 @@ The component automatically applies a `state` attribute based on its current con
278
298
  - `state="ended"` - Promo ended (component hidden)
279
299
  - `state="disabled"` - Gift unavailable (component hidden)
280
300
 
281
- Note: `ended` and `disabled` both hide the component while still removing any existing gift items.
301
+ Note: `ended` and `disabled` both hide the component while still removing the gift line for **this**
302
+ component's `variant-id`. Another tier's gift is left alone, so disabling one tier never clears
303
+ another's.
282
304
 
283
305
  ## Shopify Integration Details
284
306
 
@@ -287,8 +309,8 @@ Note: `ended` and `disabled` both hide the component while still removing any ex
287
309
  The component uses Shopify's Cart API endpoints:
288
310
 
289
311
  - `POST /cart/add.js` - Adds the gift to cart
290
- - `GET /cart.js` - Gets current cart state
291
- - `POST /cart/change.js` - Removes gift from cart
312
+ - `GET /cart.js` - Gets current cart state (only when the parent cart-panel cannot supply it)
313
+ - `POST /cart/change.js` - Removes the gift line, and trims a doubled gift line back to `quantity: 1`
292
314
 
293
315
  ### Line Item Properties
294
316
 
@@ -383,9 +405,9 @@ In your Shopify cart template, you can identify and handle gift items:
383
405
  /* Compact mobile style */
384
406
  @media (max-width: 768px) {
385
407
  gift-with-purchase {
386
- --gwp-image-size: 40px;
387
408
  --gwp-padding: 0.5rem;
388
409
  --gwp-gap: 0.5rem;
410
+ --gwp-border-radius: 4px;
389
411
  }
390
412
  }
391
413
  ```
@@ -397,9 +419,9 @@ In your Shopify cart template, you can identify and handle gift items:
397
419
  - Safari 14+
398
420
  - All modern browsers with Custom Elements support
399
421
 
400
- ## TypeScript Support
422
+ ## State Shape
401
423
 
402
- Type definitions are included in the package:
424
+ `getState()` returns:
403
425
 
404
426
  ```typescript
405
427
  interface GiftWithPurchaseState {
@@ -420,6 +442,24 @@ interface GiftWithPurchaseState {
420
442
  // Style your content and message elements with any CSS classes
421
443
  ```
422
444
 
445
+ ## Development
446
+
447
+ ```bash
448
+ npm run dev # build to demo/dist/ in watch mode and serve demo/ on http://localhost:3000
449
+ npm run build # build the published dist/ (ESM, minified UMD, CSS, minified CSS)
450
+ npm run lint # ESLint over src/ and scripts/
451
+ ```
452
+
453
+ The build is a plain Node script (`scripts/build.mjs`) driving Vite's JS API — there is no
454
+ `vite.config.js`. It emits exactly four files into `dist/`:
455
+
456
+ | File | Format |
457
+ | ----------------------------- | --------------------------------------- |
458
+ | `gift-with-purchase.esm.js` | ES module (unminified) |
459
+ | `gift-with-purchase.min.js` | UMD, minified, global `GiftWithPurchase` |
460
+ | `gift-with-purchase.css` | Stylesheet |
461
+ | `gift-with-purchase.min.css` | Stylesheet, minified |
462
+
423
463
  ## Contributing
424
464
 
425
465
  Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
@@ -8,39 +8,42 @@ gift-with-purchase {
8
8
  --gwp-border-added: #155724;
9
9
  --gwp-text-active: #155724;
10
10
  --gwp-text-added: #155724;
11
- display: block;
12
11
  border: 2px solid var(--gwp-border-active);
13
12
  border-radius: var(--gwp-border-radius);
14
13
  padding: var(--gwp-padding);
15
14
  background-color: var(--gwp-bg-active);
16
15
  color: var(--gwp-text-active);
16
+ display: block;
17
17
  }
18
+
18
19
  gift-with-purchase .gwp-product {
19
- display: flex;
20
20
  align-items: flex-start;
21
21
  gap: var(--gwp-gap);
22
+ display: flex;
22
23
  }
24
+
23
25
  gift-with-purchase [data-gwp-image] {
24
26
  flex-shrink: 0;
25
27
  }
28
+
26
29
  gift-with-purchase .gwp-content {
27
30
  flex: 1;
28
31
  min-width: 0;
29
32
  }
30
- gift-with-purchase[state=active] {
33
+
34
+ gift-with-purchase[state="active"] {
31
35
  background-color: var(--gwp-bg-active);
32
36
  border-color: var(--gwp-border-active);
33
37
  color: var(--gwp-text-active);
34
38
  }
35
- gift-with-purchase[state=added] {
39
+
40
+ gift-with-purchase[state="added"] {
36
41
  background-color: var(--gwp-bg-added);
37
42
  border-color: var(--gwp-border-added);
38
43
  color: var(--gwp-text-added);
39
44
  }
40
- gift-with-purchase[state=ended] {
41
- display: none;
42
- }
43
- gift-with-purchase[state=disabled] {
45
+
46
+ gift-with-purchase[state="ended"], gift-with-purchase[state="disabled"] {
44
47
  display: none;
45
48
  }
46
- /*# sourceMappingURL=gift-with-purchase.cjs.css.map */
49
+ /*$vite$:1*/