@zencemarketing/spin-scratch-sdk 0.1.0-alpha.1 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SpinWheel SDK v0.1.0-alpha.1
2
+ * SpinWheel SDK v0.1.0-alpha.2
3
3
  * React subpath declarations
4
4
  *
5
5
  * Import as:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SpinWheel SDK v0.1.0-alpha.1
2
+ * SpinWheel SDK v0.1.0-alpha.2
3
3
  * (c) 2026 – MIT License
4
4
  * A dynamic, configurable Spin & Win wheel and Scratch Card SDK for Vanilla JS & React.
5
5
  */
@@ -28,6 +28,63 @@ import React from 'react';
28
28
  */
29
29
  function buildCSS(config, hexToRGBA) {
30
30
  const t = config.theme || {};
31
+ const isHexColor = value => typeof value === 'string' && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value.trim());
32
+ const parseRgbLike = value => {
33
+ if (typeof value !== 'string') return null;
34
+ const m = value.trim().match(/^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d*\.?\d+)\s*)?\)$/i);
35
+ if (!m) return null;
36
+ const r = Math.min(255, Math.max(0, Number(m[1])));
37
+ const g = Math.min(255, Math.max(0, Number(m[2])));
38
+ const b = Math.min(255, Math.max(0, Number(m[3])));
39
+ if ([r, g, b].some(n => Number.isNaN(n))) return null;
40
+ return {
41
+ r,
42
+ g,
43
+ b
44
+ };
45
+ };
46
+ const parseHex = value => {
47
+ if (!isHexColor(value)) return null;
48
+ const hex = value.trim().slice(1);
49
+ if (hex.length === 3) {
50
+ const r = parseInt(hex[0] + hex[0], 16);
51
+ const g = parseInt(hex[1] + hex[1], 16);
52
+ const b = parseInt(hex[2] + hex[2], 16);
53
+ return {
54
+ r,
55
+ g,
56
+ b
57
+ };
58
+ }
59
+ const r = parseInt(hex.slice(0, 2), 16);
60
+ const g = parseInt(hex.slice(2, 4), 16);
61
+ const b = parseInt(hex.slice(4, 6), 16);
62
+ return {
63
+ r,
64
+ g,
65
+ b
66
+ };
67
+ };
68
+ const toRGBA = (value, alpha) => {
69
+ const rgb = parseHex(value) || parseRgbLike(value);
70
+ if (!rgb) return `rgba(0,0,0,${alpha})`;
71
+ return `rgba(${rgb.r},${rgb.g},${rgb.b},${alpha})`;
72
+ };
73
+ const darkenColor = (value, amount = 0.22) => {
74
+ const rgb = parseHex(value) || parseRgbLike(value);
75
+ if (!rgb) return null;
76
+ const factor = 1 - Math.min(0.9, Math.max(0, amount));
77
+ const r = Math.round(rgb.r * factor);
78
+ const g = Math.round(rgb.g * factor);
79
+ const b = Math.round(rgb.b * factor);
80
+ return `rgb(${r},${g},${b})`;
81
+ };
82
+ const readableTextOn = bg => {
83
+ const rgb = parseHex(bg) || parseRgbLike(bg);
84
+ if (!rgb) return '#1a1a1f';
85
+ const luma = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
86
+ return luma < 0.55 ? '#ffffff' : '#1a1a1f';
87
+ };
31
88
 
32
89
  // Extract theme colors with fallbacks
33
90
  const gold = t.gold || '#e8c547';
@@ -37,11 +94,16 @@ function buildCSS(config, hexToRGBA) {
37
94
  const textMuted = t.textMuted || '#9ca3af';
38
95
 
39
96
  // Configurable colors
40
- const titleColor = config.titleColor || goldLight;
97
+ const hasCustomTitleColor = config.titleColor !== null && config.titleColor !== undefined;
98
+ const titleSpinColor = hasCustomTitleColor ? config.titleColor : goldLight;
99
+ const titleWinColor = hasCustomTitleColor ? config.titleColor : goldDark;
41
100
  const subtitleColor = config.subtitleColor || textMuted;
42
101
  const ringColor = config.ringColor || gold;
43
102
  const pointerColor = config.pointerColor || gold;
44
- const buttonBaseColor = config.buttonColor || gold;
103
+ const hasCustomButtonColor = config.buttonColor !== null && config.buttonColor !== undefined;
104
+ const buttonBaseColor = hasCustomButtonColor ? config.buttonColor : gold;
105
+ const buttonTextColor = hasCustomButtonColor ? readableTextOn(buttonBaseColor) : '#1a1a1f';
106
+ const buttonEdgeColor = hasCustomButtonColor ? darkenColor(buttonBaseColor) || 'rgba(0,0,0,0.25)' : goldDark;
45
107
  const redeemBtnTop = config.winCardRedeemButtonColorTop || '#15803d';
46
108
  const redeemBtnBottom = config.winCardRedeemButtonColorBottom || '#166534';
47
109
  const redeemBtnText = config.winCardRedeemButtonTextColor || '#ffffff';
@@ -55,7 +117,7 @@ function buildCSS(config, hexToRGBA) {
55
117
  // Computed values
56
118
  hexToRGBA(gold, 0.4);
57
119
  const ringGlow = hexToRGBA(ringColor, 0.4);
58
- const buttonGlow = hexToRGBA(buttonBaseColor, 0.4);
120
+ const buttonGlow = toRGBA(buttonBaseColor, 0.4);
59
121
 
60
122
  // Background styles
61
123
  const bgStyle = config.backgroundColor ? `background-color:${config.backgroundColor};` : '';
@@ -66,9 +128,10 @@ function buildCSS(config, hexToRGBA) {
66
128
  const ringAnimationCSS = ringAnimation ? `animation:sw-ring-pulse 3s ease-in-out infinite;` : '';
67
129
 
68
130
  // Button shadow and animation
69
- const buttonBoxShadow = buttonShadow ? `box-shadow:0 4px 0 ${goldDark}, 0 6px 20px ${buttonGlow}, inset 0 1px 0 rgba(255,255,255,.3);` : `box-shadow:0 4px 0 ${goldDark}, inset 0 1px 0 rgba(255,255,255,.3);`;
70
- const buttonHoverStyle = buttonAnimation ? `.sw-spin-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 0 ${goldDark},0 8px 28px ${buttonGlow},inset 0 1px 0 rgba(255,255,255,.3)}` : `.sw-spin-btn:hover:not(:disabled){filter:brightness(1.05)}`;
71
- const buttonActiveStyle = buttonAnimation ? `.sw-spin-btn:active:not(:disabled){transform:translateY(2px);box-shadow:0 2px 0 ${goldDark},0 4px 15px ${buttonGlow},inset 0 1px 0 rgba(255,255,255,.2)}` : `.sw-spin-btn:active:not(:disabled){transform:translateY(1px)}`;
131
+ const buttonBoxShadow = buttonShadow ? `box-shadow:0 4px 0 ${buttonEdgeColor}, 0 6px 20px ${buttonGlow}, inset 0 1px 0 rgba(255,255,255,.3);` : `box-shadow:inset 0 1px 0 rgba(255,255,255,.25);`;
132
+ const buttonHoverStyle = buttonAnimation ? buttonShadow ? `.sw-spin-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 0 ${buttonEdgeColor},0 8px 28px ${buttonGlow},inset 0 1px 0 rgba(255,255,255,.3)}` : `.sw-spin-btn:hover:not(:disabled){transform:translateY(-2px);filter:brightness(1.05)}` : `.sw-spin-btn:hover:not(:disabled){filter:brightness(1.05)}`;
133
+ const buttonActiveStyle = buttonAnimation ? buttonShadow ? `.sw-spin-btn:active:not(:disabled){transform:translateY(2px);box-shadow:0 2px 0 ${buttonEdgeColor},0 4px 15px ${buttonGlow},inset 0 1px 0 rgba(255,255,255,.2)}` : `.sw-spin-btn:active:not(:disabled){transform:translateY(1px);filter:brightness(0.98)}` : `.sw-spin-btn:active:not(:disabled){transform:translateY(1px)}`;
134
+ const buttonBackground = hasCustomButtonColor ? `background:${buttonBaseColor};` : `background:linear-gradient(180deg,${goldLight},${goldDark});`;
72
135
  return `
73
136
  /* === SpinWheel SDK v2.1 === */
74
137
  @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;800&family=Outfit:wght@300;500;600;700&display=swap');
@@ -89,10 +152,10 @@ function buildCSS(config, hexToRGBA) {
89
152
  font-size:clamp(2rem,6vw,3.5rem); font-weight:800; letter-spacing:.02em;
90
153
  }
91
154
  .sw-title .sw-spin-text {
92
- color:${titleColor};
93
- text-shadow:0 0 30px ${hexToRGBA(titleColor, 0.4)}, 0 0 60px ${hexToRGBA(titleColor, 0.2)};
155
+ color:${titleSpinColor};
156
+ text-shadow:0 0 30px ${toRGBA(titleSpinColor, 0.4)}, 0 0 60px ${toRGBA(titleSpinColor, 0.2)};
94
157
  }
95
- .sw-title .sw-win-text { color:${goldDark}; }
158
+ .sw-title .sw-win-text { color:${titleWinColor}; }
96
159
  .sw-subtitle { margin-top:.5rem; color:${subtitleColor}; font-size:1rem; font-weight:300; }
97
160
 
98
161
  /* ── wheel ── */
@@ -174,7 +237,7 @@ ${ringAnimation ? `
174
237
  .sw-spin-btn {
175
238
  font-family:'Outfit',sans-serif; font-size:1.25rem; font-weight:700;
176
239
  letter-spacing:.15em; padding:1rem 3rem; border:none; border-radius:12px;
177
- background:linear-gradient(180deg,${goldLight},${goldDark}); color:#1a1a1f;
240
+ ${buttonBackground} color:${buttonTextColor};
178
241
  cursor:pointer;
179
242
  ${buttonBoxShadow}
180
243
  transition:transform .15s ease, box-shadow .2s ease, filter .2s ease;
@@ -1426,7 +1489,7 @@ class SpinWheel {
1426
1489
  static Instance = SpinWheelInstance;
1427
1490
 
1428
1491
  /** Current SDK version – kept in sync with package.json via build banner */
1429
- static VERSION = '0.1.0-alpha.1';
1492
+ static VERSION = '0.1.0-alpha.2';
1430
1493
 
1431
1494
  /** Export defaults for reference */
1432
1495
  static DEFAULTS = DEFAULTS$1;
@@ -1655,7 +1718,8 @@ function buildScratchCSS(config, hexToRGBA) {
1655
1718
 
1656
1719
  // Background configs
1657
1720
  const cardBg = config.cardBackground || `linear-gradient(180deg, #faf8fc 0%, #f0ebf5 100%)`;
1658
- const scratchZoneBg = config.scratchZoneBackground || `linear-gradient(145deg, ${purpleDark} 0%, ${purpleMid} 50%, #5a3a7a 100%)`;
1721
+ const hasCustomScratchZoneBg = config.scratchZoneBackground !== null && config.scratchZoneBackground !== undefined;
1722
+ const scratchZoneBg = hasCustomScratchZoneBg ? config.scratchZoneBackground : `linear-gradient(145deg, ${purpleDark} 0%, ${purpleMid} 50%, #5a3a7a 100%)`;
1659
1723
  const modalBtnBg = config.modalButtonColor || `linear-gradient(145deg, ${purpleMid} 0%, ${purpleDark} 100%)`;
1660
1724
 
1661
1725
  // Computed values
@@ -1765,9 +1829,7 @@ function buildScratchCSS(config, hexToRGBA) {
1765
1829
  align-items:center;
1766
1830
  justify-content:center;
1767
1831
  padding:20px;
1768
- background:
1769
- radial-gradient(circle at 30% 30%, rgba(255,255,255,0.08) 0%, transparent 45%),
1770
- linear-gradient(145deg, ${purpleDark} 0%, ${purpleMid} 100%);
1832
+ background:${hasCustomScratchZoneBg ? scratchZoneBg : `radial-gradient(circle at 30% 30%, rgba(255,255,255,0.08) 0%, transparent 45%), linear-gradient(145deg, ${purpleDark} 0%, ${purpleMid} 100%)`};
1771
1833
  }
1772
1834
 
1773
1835
  .sc-prize-content::before {
@@ -3392,7 +3454,7 @@ const ScratchCard = {
3392
3454
  /** The underlying class – useful for `instanceof` checks or subclassing. */
3393
3455
  Instance: ScratchCardInstance,
3394
3456
  /** Current SDK version */
3395
- VERSION: '0.1.0-alpha.1',
3457
+ VERSION: '0.1.0-alpha.2',
3396
3458
  /** Export defaults for reference */
3397
3459
  DEFAULTS: DEFAULTS
3398
3460
  };