@zencemarketing/spin-scratch-sdk 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +716 -0
- package/dist/react.cjs.js +3588 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.d.ts +91 -0
- package/dist/react.esm.mjs +3579 -0
- package/dist/react.esm.mjs.map +1 -0
- package/dist/spin-wheel-sdk.cjs.js +3584 -0
- package/dist/spin-wheel-sdk.cjs.js.map +1 -0
- package/dist/spin-wheel-sdk.d.ts +513 -0
- package/dist/spin-wheel-sdk.esm.mjs +3577 -0
- package/dist/spin-wheel-sdk.esm.mjs.map +1 -0
- package/dist/spin-wheel-sdk.umd.js +3685 -0
- package/dist/spin-wheel-sdk.umd.js.map +1 -0
- package/dist/spin-wheel-sdk.umd.min.js +2 -0
- package/dist/spin-wheel-sdk.umd.min.js.map +1 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
# SpinWheel SDK + ScratchCard SDK
|
|
2
|
+
|
|
3
|
+
A dynamic, configurable **Spin & Win** wheel and **Scratch Card** SDK for **Vanilla JS** and **React** (with full **TypeScript** support).
|
|
4
|
+
|
|
5
|
+
Package name: `@zencemarketing/spin-scratch-sdk`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Who is this for?
|
|
10
|
+
|
|
11
|
+
If you are a client developer, you generally only need to:
|
|
12
|
+
|
|
13
|
+
1. Install the package
|
|
14
|
+
2. Render a container (`<div id="..." />`)
|
|
15
|
+
3. Call `SpinWheel.init(...)` or `ScratchCard.init(...)` (Vanilla) **or** use the React wrappers
|
|
16
|
+
|
|
17
|
+
Everything else (HTML structure, styles, DOM events, animations) is handled internally by the SDK.
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Browser environment (needs `window` and `document`)
|
|
22
|
+
- Node.js >= 16 for building this SDK
|
|
23
|
+
|
|
24
|
+
If you use SSR frameworks (Next.js, Remix), initialize the widgets only on the client (e.g. inside `useEffect`).
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
| Feature | Details |
|
|
29
|
+
|---|---|
|
|
30
|
+
| **Dynamic segments** | 2–N segments – just pass an array |
|
|
31
|
+
| **Fully configurable** | 40+ options for SpinWheel, 50+ for ScratchCard |
|
|
32
|
+
| **Spin physics** | Configurable duration, spin count, easing |
|
|
33
|
+
| **Spin limit** | Restrict number of spins per session |
|
|
34
|
+
| **Win card overlay** | Auto-generated coupon code, copy button, configurable redeem CTA |
|
|
35
|
+
| **Confetti** | Toggleable confetti with custom colors and count |
|
|
36
|
+
| **Appearance** | Customize ring, pointer, button, background, shadows, animations |
|
|
37
|
+
| **Callbacks** | `onSpinStart`, `onSpinEnd`, `onRedeem`, `onSpinLimitReached` |
|
|
38
|
+
| **Runtime updates** | `updateOptions()`, `updateSegments()`, `updatePrize()` |
|
|
39
|
+
| **React support** | Thin wrapper with `ref` for imperative control |
|
|
40
|
+
| **Zero dependencies** | CSS is auto-injected; fonts loaded from Google Fonts |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
### Install from npm (when published)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm i @zencemarketing/spin-scratch-sdk
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Use locally (not published yet)
|
|
53
|
+
|
|
54
|
+
In your client app `package.json`:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@zencemarketing/spin-scratch-sdk": "file:../path-to/ZenceGamification/sdk"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# In the SDK folder
|
|
68
|
+
npm i
|
|
69
|
+
npm run build
|
|
70
|
+
|
|
71
|
+
# In the client folder
|
|
72
|
+
npm i
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Note: Always point `file:` to the SDK **root folder** (the one that contains `package.json`), not `dist/`.
|
|
76
|
+
|
|
77
|
+
## TypeScript support
|
|
78
|
+
|
|
79
|
+
This SDK ships TypeScript declarations out of the box — no `@types/` package needed.
|
|
80
|
+
|
|
81
|
+
### Two entry points
|
|
82
|
+
|
|
83
|
+
| Entry | Import path | Use case |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| **Main** | `@zencemarketing/spin-scratch-sdk` | Vanilla JS/TS, factory React |
|
|
86
|
+
| **React** | `@zencemarketing/spin-scratch-sdk/react` | Pre-wired React components |
|
|
87
|
+
|
|
88
|
+
### Recommended import for React + TypeScript
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import {
|
|
92
|
+
SpinWheelReact,
|
|
93
|
+
ScratchCardReact,
|
|
94
|
+
type SpinWheelReactProps,
|
|
95
|
+
type ScratchCardReactProps,
|
|
96
|
+
type SpinWheelReactHandle,
|
|
97
|
+
type ScratchCardReactHandle,
|
|
98
|
+
type SegmentConfig,
|
|
99
|
+
type ScratchPrize,
|
|
100
|
+
} from '@zencemarketing/spin-scratch-sdk/react';
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Recommended import for Vanilla TypeScript
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import {
|
|
107
|
+
SpinWheel,
|
|
108
|
+
ScratchCard,
|
|
109
|
+
type SpinWheelOptions,
|
|
110
|
+
type ScratchCardOptions,
|
|
111
|
+
type SegmentConfig,
|
|
112
|
+
type ScratchPrize,
|
|
113
|
+
} from '@zencemarketing/spin-scratch-sdk';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Key type tips
|
|
117
|
+
|
|
118
|
+
- **Segment shape**: Required fields are `label` and `color` (NOT `name`)
|
|
119
|
+
- **React props**: Use `SpinWheelReactProps` / `ScratchCardReactProps` — these already omit `container` (the SDK handles it). **Do NOT use** `Omit<SpinWheelOptions, 'container'>` manually.
|
|
120
|
+
- **Ref handles**: Use `SpinWheelReactHandle` / `ScratchCardReactHandle` for `useRef` generic.
|
|
121
|
+
|
|
122
|
+
Tip: If you hover on `SpinWheel.init` and you only see `options: SpinWheelOptions`, that’s normal. To see all available fields:
|
|
123
|
+
|
|
124
|
+
- Use IntelliSense inside `SpinWheel.init({ ... })` (Ctrl+Space)
|
|
125
|
+
- Or Ctrl/Cmd-click `SpinWheelOptions` to open the full type
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Quick Start (Vanilla JS)
|
|
130
|
+
|
|
131
|
+
### Option A: Use the UMD bundle in plain HTML
|
|
132
|
+
|
|
133
|
+
When the package is published, you can use a CDN like `unpkg`:
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<div id="my-wheel"></div>
|
|
137
|
+
|
|
138
|
+
<!-- Uses the "unpkg" entry from package.json -->
|
|
139
|
+
<script src="https://unpkg.com/@zencemarketing/spin-scratch-sdk"></script>
|
|
140
|
+
|
|
141
|
+
<script>
|
|
142
|
+
var SpinWheel = window.SpinWheelSDK.SpinWheel;
|
|
143
|
+
|
|
144
|
+
var wheel = SpinWheel.init({
|
|
145
|
+
container: '#my-wheel',
|
|
146
|
+
segments: [
|
|
147
|
+
{ label: 'Free Gift', color: '#55efc4', icon: '🎁', title: 'Free Gift', worth: '₹299' },
|
|
148
|
+
{ label: 'Surprise Reward', color: '#81ecec', icon: '✨', title: 'Surprise Reward', worth: '₹199' },
|
|
149
|
+
{ label: 'Better Luck', color: '#dfe6e9', icon: '🌟', title: 'Better Luck', worth: '' },
|
|
150
|
+
],
|
|
151
|
+
headerTitle: 'Spin & Win',
|
|
152
|
+
headerSubtitle: 'Try your luck!',
|
|
153
|
+
onSpinEnd: function (prize, index) {
|
|
154
|
+
console.log('Won:', prize, 'at index', index);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Optional: wheel.spin();
|
|
159
|
+
</script>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Option B: Import in a bundler app (Vite/Webpack/etc.)
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
import { SpinWheel } from '@zencemarketing/spin-scratch-sdk';
|
|
166
|
+
|
|
167
|
+
const wheel = SpinWheel.init({
|
|
168
|
+
container: '#my-wheel',
|
|
169
|
+
segments: [
|
|
170
|
+
{ label: 'Prize 1', color: '#55efc4' },
|
|
171
|
+
{ label: 'Prize 2', color: '#81ecec' },
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Quick Start (React)
|
|
177
|
+
|
|
178
|
+
There are two ways to use this SDK in React.
|
|
179
|
+
|
|
180
|
+
### Option A (recommended): Import from `/react` subpath
|
|
181
|
+
|
|
182
|
+
The simplest way — components are pre-wired, fully typed, and just work:
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
import React, { useRef } from 'react';
|
|
186
|
+
import {
|
|
187
|
+
SpinWheelReact,
|
|
188
|
+
type SpinWheelReactHandle,
|
|
189
|
+
type SegmentConfig,
|
|
190
|
+
} from '@zencemarketing/spin-scratch-sdk/react';
|
|
191
|
+
|
|
192
|
+
export default function App() {
|
|
193
|
+
const ref = useRef<SpinWheelReactHandle>(null);
|
|
194
|
+
|
|
195
|
+
const segments: SegmentConfig[] = [
|
|
196
|
+
{ label: 'Free Gift', color: '#55efc4', icon: '🎁', title: 'Free Gift', worth: '₹299' },
|
|
197
|
+
{ label: 'Surprise', color: '#81ecec', icon: '✨', title: 'Surprise', worth: '₹199' },
|
|
198
|
+
{ label: 'Better Luck', color: '#dfe6e9', icon: '🌟' },
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<SpinWheelReact
|
|
203
|
+
ref={ref}
|
|
204
|
+
headerTitle="Spin & Win"
|
|
205
|
+
segments={segments}
|
|
206
|
+
onSpinEnd={(prize: SegmentConfig, idx: number) => console.log('Won:', prize, idx)}
|
|
207
|
+
/>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Option B: Factory function (advanced)
|
|
213
|
+
|
|
214
|
+
If you need more control or want to avoid the `/react` subpath:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import React, { useRef } from 'react';
|
|
218
|
+
import { createSpinWheelReact, type SpinWheelReactHandle } from '@zencemarketing/spin-scratch-sdk';
|
|
219
|
+
|
|
220
|
+
const SpinWheelReact = createSpinWheelReact(React);
|
|
221
|
+
|
|
222
|
+
export default function App() {
|
|
223
|
+
const ref = useRef<SpinWheelReactHandle>(null);
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<SpinWheelReact
|
|
227
|
+
ref={ref}
|
|
228
|
+
headerTitle="Spin & Win"
|
|
229
|
+
segments={[
|
|
230
|
+
{ label: 'Free Gift', color: '#55efc4', icon: '🎁', title: 'Free Gift', worth: '₹299' },
|
|
231
|
+
{ label: 'Surprise', color: '#81ecec', icon: '✨', title: 'Surprise', worth: '₹199' },
|
|
232
|
+
]}
|
|
233
|
+
onSpinEnd={(prize, idx) => console.log('Won:', prize, idx)}
|
|
234
|
+
/>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Option B: Use Vanilla API inside `useEffect`
|
|
240
|
+
|
|
241
|
+
This gives you full control, but you must clean up on unmount.
|
|
242
|
+
|
|
243
|
+
```jsx
|
|
244
|
+
import React, { useEffect } from 'react';
|
|
245
|
+
import { SpinWheel } from '@zencemarketing/spin-scratch-sdk';
|
|
246
|
+
|
|
247
|
+
export default function App() {
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
const wheel = SpinWheel.init({
|
|
250
|
+
container: '#spin-wheel-container',
|
|
251
|
+
segments: [
|
|
252
|
+
{ label: 'Prize 1', color: '#55efc4' },
|
|
253
|
+
{ label: 'Prize 2', color: '#81ecec' },
|
|
254
|
+
],
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return () => {
|
|
258
|
+
wheel.destroy();
|
|
259
|
+
};
|
|
260
|
+
}, []);
|
|
261
|
+
|
|
262
|
+
return <div id="spin-wheel-container" />;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Tip (React StrictMode): React may mount/unmount twice in development. Always keep the cleanup (`destroy()`) to avoid duplicate widgets.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## ScratchCard quick start (Vanilla)
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
import { ScratchCard } from '@zencemarketing/spin-scratch-sdk';
|
|
274
|
+
|
|
275
|
+
const card = ScratchCard.init({
|
|
276
|
+
container: '#scratch-card-container',
|
|
277
|
+
prize: { name: 'Gift Voucher', icon: '🎁', label: 'Congratulations!' },
|
|
278
|
+
onReveal: (prize) => console.log('Revealed:', prize),
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## ScratchCard quick start (React)
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
import React, { useRef } from 'react';
|
|
286
|
+
import {
|
|
287
|
+
ScratchCardReact,
|
|
288
|
+
type ScratchCardReactHandle,
|
|
289
|
+
type ScratchPrize,
|
|
290
|
+
} from '@zencemarketing/spin-scratch-sdk/react';
|
|
291
|
+
|
|
292
|
+
export default function App() {
|
|
293
|
+
const ref = useRef<ScratchCardReactHandle>(null);
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<ScratchCardReact
|
|
297
|
+
ref={ref}
|
|
298
|
+
prize={{ name: 'Gift Voucher', icon: '🎁', label: 'Congratulations!' }}
|
|
299
|
+
onReveal={(prize: ScratchPrize) => console.log('Revealed:', prize)}
|
|
300
|
+
/>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Or using the factory pattern:
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import React, { useRef } from 'react';
|
|
309
|
+
import { createScratchCardReact, type ScratchCardReactHandle } from '@zencemarketing/spin-scratch-sdk';
|
|
310
|
+
|
|
311
|
+
const ScratchCardReact = createScratchCardReact(React);
|
|
312
|
+
|
|
313
|
+
export default function App() {
|
|
314
|
+
const ref = useRef<ScratchCardReactHandle>(null);
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<ScratchCardReact
|
|
318
|
+
ref={ref}
|
|
319
|
+
prize={{ name: 'Gift Voucher', icon: '🎁', label: 'Congratulations!' }}
|
|
320
|
+
onReveal={(prize) => console.log('Revealed:', prize)}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## SpinWheel API Reference
|
|
327
|
+
|
|
328
|
+
### `SpinWheel.init(options)` → `SpinWheelInstance`
|
|
329
|
+
|
|
330
|
+
#### Core Options
|
|
331
|
+
|
|
332
|
+
| Option | Type | Default | Description |
|
|
333
|
+
|---|---|---|---|
|
|
334
|
+
| `container` | `string \| HTMLElement` | *required* | CSS selector or DOM element to mount into |
|
|
335
|
+
| `segments` | `Array<Segment>` | *required* | Array of prize segments (min 2) |
|
|
336
|
+
| `winningIndex` | `number \| null` | `null` | Pre-determined winning index. Overridden by `forceIndex` in `.spin()` |
|
|
337
|
+
|
|
338
|
+
#### Spin Behavior
|
|
339
|
+
|
|
340
|
+
| Option | Type | Default | Description |
|
|
341
|
+
|---|---|---|---|
|
|
342
|
+
| `spinDuration` | `number` | `5000` | Total spin animation duration (ms) |
|
|
343
|
+
| `minSpins` | `number` | `5` | Minimum full rotations |
|
|
344
|
+
| `maxSpins` | `number` | `8` | Maximum full rotations |
|
|
345
|
+
| `spinLimit` | `number \| null` | `null` | Max spins allowed (`null` = unlimited) |
|
|
346
|
+
|
|
347
|
+
#### Header UI
|
|
348
|
+
|
|
349
|
+
| Option | Type | Default | Description |
|
|
350
|
+
|---|---|---|---|
|
|
351
|
+
| `headerTitle` | `string \| null` | `null` | Title above the wheel |
|
|
352
|
+
| `headerSubtitle` | `string \| null` | `null` | Subtitle below the title |
|
|
353
|
+
| `titleColor` | `string \| null` | `null` | Custom title color (uses `theme.goldLight` if null) |
|
|
354
|
+
| `subtitleColor` | `string \| null` | `null` | Custom subtitle color (uses `theme.textMuted` if null) |
|
|
355
|
+
|
|
356
|
+
#### Hub / Center
|
|
357
|
+
|
|
358
|
+
| Option | Type | Default | Description |
|
|
359
|
+
|---|---|---|---|
|
|
360
|
+
| `hubLabel` | `string` | `'Spin & win'` | Text inside the center hub |
|
|
361
|
+
| `hubIcon` | `string` | `'▲'` | Icon inside the center hub |
|
|
362
|
+
|
|
363
|
+
#### Spin Button
|
|
364
|
+
|
|
365
|
+
| Option | Type | Default | Description |
|
|
366
|
+
|---|---|---|---|
|
|
367
|
+
| `showButton` | `boolean` | `true` | Show the external SPIN! button |
|
|
368
|
+
| `buttonText` | `string` | `'SPIN!'` | Button label text |
|
|
369
|
+
|
|
370
|
+
#### Wheel Appearance
|
|
371
|
+
|
|
372
|
+
| Option | Type | Default | Description |
|
|
373
|
+
|---|---|---|---|
|
|
374
|
+
| `backgroundColor` | `string \| null` | `null` | Container background color |
|
|
375
|
+
| `backgroundImage` | `string \| null` | `null` | Background image URL |
|
|
376
|
+
| `ringColor` | `string \| null` | `null` | Wheel ring color |
|
|
377
|
+
| `ringShadow` | `boolean` | `true` | Enable ring shadow/glow |
|
|
378
|
+
| `ringAnimation` | `boolean` | `true` | Enable pulsing ring animation |
|
|
379
|
+
| `pointerColor` | `string \| null` | `null` | Pointer/arrow color |
|
|
380
|
+
| `buttonColor` | `string \| null` | `null` | Spin button gradient color |
|
|
381
|
+
| `buttonShadow` | `boolean` | `true` | Enable button shadow |
|
|
382
|
+
| `buttonAnimation` | `boolean` | `true` | Enable button hover/active animations |
|
|
383
|
+
|
|
384
|
+
#### Win Card
|
|
385
|
+
|
|
386
|
+
| Option | Type | Default | Description |
|
|
387
|
+
|---|---|---|---|
|
|
388
|
+
| `showWinCard` | `boolean` | `true` | Show win card overlay after spin |
|
|
389
|
+
| `generateCode` | `boolean` | `true` | Auto-generate a random coupon code |
|
|
390
|
+
| `codeLength` | `number` | `9` | Length of auto-generated codes |
|
|
391
|
+
| `redeemUrl` | `string \| null` | `null` | URL for redeem button |
|
|
392
|
+
| `winCardBrandLabel` | `string \| null` | `null` | Brand label on win card (uses `hubLabel` if null) |
|
|
393
|
+
| `winCardWorthLabel` | `string` | `'WORTH'` | Label before worth value |
|
|
394
|
+
| `winCardRedeemButtonText` | `string` | `'Redeem Now'` | Redeem button text |
|
|
395
|
+
| `winCardRedeemButtonColorTop` | `string` | `'#15803d'` | Redeem button gradient top color |
|
|
396
|
+
| `winCardRedeemButtonColorBottom` | `string` | `'#166534'` | Redeem button gradient bottom color |
|
|
397
|
+
| `winCardRedeemButtonTextColor` | `string` | `'#ffffff'` | Redeem button text color |
|
|
398
|
+
|
|
399
|
+
#### Confetti
|
|
400
|
+
|
|
401
|
+
| Option | Type | Default | Description |
|
|
402
|
+
|---|---|---|---|
|
|
403
|
+
| `confettiOnWin` | `boolean` | `true` | Show confetti on win |
|
|
404
|
+
| `confettiColors` | `string[] \| null` | `null` | Array of confetti colors |
|
|
405
|
+
| `confettiCount` | `number` | `40` | Number of confetti pieces |
|
|
406
|
+
|
|
407
|
+
#### Theme
|
|
408
|
+
|
|
409
|
+
| Option | Type | Default | Description |
|
|
410
|
+
|---|---|---|---|
|
|
411
|
+
| `theme` | `object` | See below | Color theme overrides |
|
|
412
|
+
|
|
413
|
+
#### Callbacks
|
|
414
|
+
|
|
415
|
+
| Option | Type | Default | Description |
|
|
416
|
+
|---|---|---|---|
|
|
417
|
+
| `onSpinStart` | `function` | `null` | `(winIndex) => void` |
|
|
418
|
+
| `onSpinEnd` | `function` | `null` | `(prize, winIndex) => void` |
|
|
419
|
+
| `onRedeem` | `function` | `null` | `(prize) => void` |
|
|
420
|
+
| `onSpinLimitReached` | `function` | `null` | `(count) => void` |
|
|
421
|
+
|
|
422
|
+
### Segment Object
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
{
|
|
426
|
+
label: 'Free Gift', // text on the wheel (required)
|
|
427
|
+
color: '#55efc4', // segment background color (required)
|
|
428
|
+
icon: '🎁', // emoji/icon (optional)
|
|
429
|
+
title: 'Free Gift Voucher', // title on win card (optional, falls back to label)
|
|
430
|
+
worth: '₹299', // "WORTH ₹299" on win card (optional)
|
|
431
|
+
code: 'FIXEDCODE', // fixed code – overrides auto-generate (optional)
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### SpinWheel Instance Methods
|
|
436
|
+
|
|
437
|
+
| Method | Description |
|
|
438
|
+
|---|---|
|
|
439
|
+
| `.spin(forceIndex?)` | Trigger a spin; optionally force which segment wins |
|
|
440
|
+
| `.updateSegments(segments[])` | Replace all segments at runtime and re-render |
|
|
441
|
+
| `.hideWinCard()` | Programmatically close the win card overlay |
|
|
442
|
+
| `.updateOptions(opts)` | Update configuration options at runtime |
|
|
443
|
+
| `.resetSpinCount(count?)` | Reset the spin count (default: 0) |
|
|
444
|
+
| `.destroy()` | Remove all SDK-created DOM and clean up |
|
|
445
|
+
|
|
446
|
+
### SpinWheel Instance Getters
|
|
447
|
+
|
|
448
|
+
| Getter | Type | Description |
|
|
449
|
+
|---|---|---|
|
|
450
|
+
| `.lastWonPrize` | `Segment \| null` | The last prize that was won |
|
|
451
|
+
| `.lastWonIndex` | `number` | The last won segment index (-1 if none) |
|
|
452
|
+
| `.spinCount` | `number` | Total spins performed |
|
|
453
|
+
| `.remainingSpins` | `number \| null` | Remaining spins (`null` if unlimited) |
|
|
454
|
+
|
|
455
|
+
### SpinWheel Theme Defaults
|
|
456
|
+
|
|
457
|
+
```js
|
|
458
|
+
{
|
|
459
|
+
gold: '#e8c547',
|
|
460
|
+
goldLight: '#f5d76e',
|
|
461
|
+
goldDark: '#c9a227',
|
|
462
|
+
bgDark: '#0d0d12',
|
|
463
|
+
textMuted: '#9ca3af',
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## ScratchCard API Reference
|
|
470
|
+
|
|
471
|
+
### `ScratchCard.init(options)` → `ScratchCardInstance`
|
|
472
|
+
|
|
473
|
+
#### Core Options
|
|
474
|
+
|
|
475
|
+
| Option | Type | Default | Description |
|
|
476
|
+
|---|---|---|---|
|
|
477
|
+
| `container` | `string \| HTMLElement` | *required* | CSS selector or DOM element |
|
|
478
|
+
| `prize` | `Prize` | *required* | Prize object: `{ name, icon, label }` |
|
|
479
|
+
|
|
480
|
+
#### Header UI
|
|
481
|
+
|
|
482
|
+
| Option | Type | Default | Description |
|
|
483
|
+
|---|---|---|---|
|
|
484
|
+
| `headerTitle` | `string` | `'Scratch the Card...'` | Header text |
|
|
485
|
+
| `headerTitleColor` | `string \| null` | `null` | Header title color |
|
|
486
|
+
|
|
487
|
+
#### Instruction
|
|
488
|
+
|
|
489
|
+
| Option | Type | Default | Description |
|
|
490
|
+
|---|---|---|---|
|
|
491
|
+
| `instruction` | `string` | `'Scratch the card...'` | Instruction text |
|
|
492
|
+
| `instructionColor` | `string \| null` | `null` | Instruction text color |
|
|
493
|
+
|
|
494
|
+
#### Scratch Behavior
|
|
495
|
+
|
|
496
|
+
| Option | Type | Default | Description |
|
|
497
|
+
|---|---|---|---|
|
|
498
|
+
| `revealThreshold` | `number` | `55` | % scratched to auto-reveal |
|
|
499
|
+
| `brushSize` | `number` | `28` | Scratch brush size in px |
|
|
500
|
+
|
|
501
|
+
#### Coin / Eraser Tool
|
|
502
|
+
|
|
503
|
+
| Option | Type | Default | Description |
|
|
504
|
+
|---|---|---|---|
|
|
505
|
+
| `coinSize` | `number` | `56` | Coin cursor size in px |
|
|
506
|
+
| `showCoin` | `boolean` | `true` | Show coin cursor |
|
|
507
|
+
| `coinIcon` | `string` | `'$'` | Icon on coin |
|
|
508
|
+
| `coinGradientStart` | `string \| null` | `null` | Coin gradient start color |
|
|
509
|
+
| `coinGradientEnd` | `string \| null` | `null` | Coin gradient end color |
|
|
510
|
+
|
|
511
|
+
#### Card Appearance
|
|
512
|
+
|
|
513
|
+
| Option | Type | Default | Description |
|
|
514
|
+
|---|---|---|---|
|
|
515
|
+
| `cardBackground` | `string \| null` | `null` | Card background CSS |
|
|
516
|
+
| `cardShadow` | `boolean` | `true` | Enable card shadow |
|
|
517
|
+
| `cardBorderRadius` | `number` | `24` | Card border radius in px |
|
|
518
|
+
|
|
519
|
+
#### Scratch Zone
|
|
520
|
+
|
|
521
|
+
| Option | Type | Default | Description |
|
|
522
|
+
|---|---|---|---|
|
|
523
|
+
| `scratchZoneBackground` | `string \| null` | `null` | Scratch zone background |
|
|
524
|
+
| `scratchZoneShadow` | `boolean` | `true` | Enable zone shadow |
|
|
525
|
+
| `scratchZoneBorderRadius` | `number` | `20` | Zone border radius in px |
|
|
526
|
+
|
|
527
|
+
#### Scratch Layer
|
|
528
|
+
|
|
529
|
+
| Option | Type | Default | Description |
|
|
530
|
+
|---|---|---|---|
|
|
531
|
+
| `scratchLayerColor` | `string` | `'rgb(150,130,180)'` | Scratch layer color |
|
|
532
|
+
| `scratchLayerSparkles` | `boolean` | `true` | Show sparkles on layer |
|
|
533
|
+
| `scratchLayerSparkleCount` | `number` | `40` | Number of sparkles |
|
|
534
|
+
|
|
535
|
+
#### Prize Display
|
|
536
|
+
|
|
537
|
+
| Option | Type | Default | Description |
|
|
538
|
+
|---|---|---|---|
|
|
539
|
+
| `prizeTextColor` | `string \| null` | `null` | Prize label color |
|
|
540
|
+
| `prizeNameColor` | `string \| null` | `null` | Prize name color |
|
|
541
|
+
| `prizeIconBackground` | `string \| null` | `null` | Prize icon background |
|
|
542
|
+
|
|
543
|
+
#### Gift Icon Hint
|
|
544
|
+
|
|
545
|
+
| Option | Type | Default | Description |
|
|
546
|
+
|---|---|---|---|
|
|
547
|
+
| `showGiftIcon` | `boolean` | `true` | Show gift icon hint |
|
|
548
|
+
| `giftIcon` | `string` | `'🎁'` | Gift icon emoji |
|
|
549
|
+
| `giftIconBackground` | `string \| null` | `null` | Gift icon background |
|
|
550
|
+
|
|
551
|
+
#### Modal
|
|
552
|
+
|
|
553
|
+
| Option | Type | Default | Description |
|
|
554
|
+
|---|---|---|---|
|
|
555
|
+
| `showModal` | `boolean` | `true` | Show modal after reveal |
|
|
556
|
+
| `modalTitle` | `string` | `'Congratulations!'` | Modal title |
|
|
557
|
+
| `modalTitleColor` | `string \| null` | `null` | Modal title color |
|
|
558
|
+
| `modalButtonText` | `string` | `'Claim your'` | Modal button text prefix |
|
|
559
|
+
| `modalButtonColor` | `string \| null` | `null` | Modal button background |
|
|
560
|
+
| `modalButtonTextColor` | `string \| null` | `null` | Modal button text color |
|
|
561
|
+
| `modalBackdropBlur` | `boolean` | `true` | Enable backdrop blur |
|
|
562
|
+
|
|
563
|
+
#### Confetti
|
|
564
|
+
|
|
565
|
+
| Option | Type | Default | Description |
|
|
566
|
+
|---|---|---|---|
|
|
567
|
+
| `confettiEnabled` | `boolean` | `true` | Enable confetti |
|
|
568
|
+
| `confettiColors` | `string[] \| null` | `null` | Confetti colors array |
|
|
569
|
+
| `confettiCount` | `number` | `100` | Number of confetti pieces |
|
|
570
|
+
| `confettiDuration` | `number` | `5500` | Confetti duration in ms |
|
|
571
|
+
|
|
572
|
+
#### Animation
|
|
573
|
+
|
|
574
|
+
| Option | Type | Default | Description |
|
|
575
|
+
|---|---|---|---|
|
|
576
|
+
| `animationType` | `string` | `'default'` | `'default'` \| `'bounce'` \| `'none'` |
|
|
577
|
+
| `animationDuration` | `number` | `600` | Animation duration in ms |
|
|
578
|
+
|
|
579
|
+
#### Theme
|
|
580
|
+
|
|
581
|
+
| Option | Type | Default | Description |
|
|
582
|
+
|---|---|---|---|
|
|
583
|
+
| `theme` | `object` | See below | Color theme overrides |
|
|
584
|
+
|
|
585
|
+
#### Callbacks
|
|
586
|
+
|
|
587
|
+
| Option | Type | Default | Description |
|
|
588
|
+
|---|---|---|---|
|
|
589
|
+
| `onScratchStart` | `function` | `null` | `() => void` |
|
|
590
|
+
| `onScratchProgress` | `function` | `null` | `(percent) => void` |
|
|
591
|
+
| `onReveal` | `function` | `null` | `(prize) => void` |
|
|
592
|
+
| `onClaim` | `function` | `null` | `(prize) => void` |
|
|
593
|
+
|
|
594
|
+
### Prize Object
|
|
595
|
+
|
|
596
|
+
```js
|
|
597
|
+
{
|
|
598
|
+
name: 'iPhone 16', // Prize name (required)
|
|
599
|
+
icon: '📱', // Emoji/icon (optional)
|
|
600
|
+
label: 'Congratulations!', // Label above prize name (optional)
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### ScratchCard Instance Methods
|
|
605
|
+
|
|
606
|
+
| Method | Description |
|
|
607
|
+
|---|---|
|
|
608
|
+
| `.reveal()` | Programmatically reveal the prize |
|
|
609
|
+
| `.reset()` | Reset the card for replay |
|
|
610
|
+
| `.hideModal()` | Hide the win modal |
|
|
611
|
+
| `.showModal()` | Show the win modal |
|
|
612
|
+
| `.updatePrize(prize)` | Update prize at runtime and reset card |
|
|
613
|
+
| `.updateOptions(opts)` | Update configuration at runtime |
|
|
614
|
+
| `.destroy()` | Remove all SDK-created DOM and clean up |
|
|
615
|
+
|
|
616
|
+
### ScratchCard Instance Getters
|
|
617
|
+
|
|
618
|
+
| Getter | Type | Description |
|
|
619
|
+
|---|---|---|
|
|
620
|
+
| `.scratchPercent` | `number` | Current scratch progress (0-100) |
|
|
621
|
+
| `.hasRevealed` | `boolean` | Whether the prize has been revealed |
|
|
622
|
+
| `.prize` | `Prize \| null` | Current prize object |
|
|
623
|
+
|
|
624
|
+
### ScratchCard Theme Defaults
|
|
625
|
+
|
|
626
|
+
```js
|
|
627
|
+
{
|
|
628
|
+
purpleDark: '#4a2c6a',
|
|
629
|
+
purpleMid: '#6b4a8a',
|
|
630
|
+
purpleLight: '#8b6baa',
|
|
631
|
+
gold: '#d4a84b',
|
|
632
|
+
goldLight: '#e8c547',
|
|
633
|
+
goldDark: '#b8923a',
|
|
634
|
+
white: '#ffffff',
|
|
635
|
+
textDark: '#2d2d2d',
|
|
636
|
+
textMuted: '#6b6b6b',
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## React Ref Methods
|
|
643
|
+
|
|
644
|
+
### SpinWheelReact
|
|
645
|
+
|
|
646
|
+
| Method / Getter | Description |
|
|
647
|
+
|---|---|
|
|
648
|
+
| `ref.current.spin(forceIndex?)` | Trigger a spin |
|
|
649
|
+
| `ref.current.updateSegments(segs)` | Replace segments |
|
|
650
|
+
| `ref.current.hideWinCard()` | Close win card |
|
|
651
|
+
| `ref.current.updateOptions(opts)` | Update config |
|
|
652
|
+
| `ref.current.resetSpinCount(count?)` | Reset spin count |
|
|
653
|
+
| `ref.current.spinCount` | Current spin count |
|
|
654
|
+
| `ref.current.remainingSpins` | Remaining spins |
|
|
655
|
+
| `ref.current.lastWonPrize` | Last won prize |
|
|
656
|
+
| `ref.current.lastWonIndex` | Last won index |
|
|
657
|
+
| `ref.current.instance` | Raw SpinWheelInstance |
|
|
658
|
+
|
|
659
|
+
### ScratchCardReact
|
|
660
|
+
|
|
661
|
+
| Method / Getter | Description |
|
|
662
|
+
|---|---|
|
|
663
|
+
| `ref.current.reveal()` | Reveal prize |
|
|
664
|
+
| `ref.current.reset()` | Reset card |
|
|
665
|
+
| `ref.current.hideModal()` | Hide modal |
|
|
666
|
+
| `ref.current.showModal()` | Show modal |
|
|
667
|
+
| `ref.current.updatePrize(prize)` | Update prize |
|
|
668
|
+
| `ref.current.updateOptions(opts)` | Update config |
|
|
669
|
+
| `ref.current.scratchPercent` | Scratch progress |
|
|
670
|
+
| `ref.current.hasRevealed` | Is revealed? |
|
|
671
|
+
| `ref.current.prize` | Current prize |
|
|
672
|
+
| `ref.current.instance` | Raw ScratchCardInstance |
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## File Structure
|
|
677
|
+
|
|
678
|
+
```
|
|
679
|
+
sdk/
|
|
680
|
+
├── src/
|
|
681
|
+
│ ├── SpinWheel.js ← SpinWheel Core SDK (vanilla JS)
|
|
682
|
+
│ ├── SpinWheelReact.js ← SpinWheel React wrapper (factory)
|
|
683
|
+
│ ├── ScratchCard.js ← ScratchCard Core SDK (vanilla JS)
|
|
684
|
+
│ ├── ScratchCardReact.js ← ScratchCard React wrapper (factory)
|
|
685
|
+
│ ├── styles.js ← SpinWheel styles
|
|
686
|
+
│ ├── scratchStyles.js ← ScratchCard styles
|
|
687
|
+
│ ├── index.js ← Main barrel export
|
|
688
|
+
│ ├── react.js ← React subpath entry (pre-wires factories)
|
|
689
|
+
│ └── utils.js ← Shared utilities
|
|
690
|
+
├── dist/ ← Built SDK files
|
|
691
|
+
│ ├── spin-wheel-sdk.umd.js ← UMD (browser <script>)
|
|
692
|
+
│ ├── spin-wheel-sdk.umd.min.js ← UMD minified
|
|
693
|
+
│ ├── spin-wheel-sdk.esm.mjs ← ESM (import/export)
|
|
694
|
+
│ ├── spin-wheel-sdk.cjs.js ← CommonJS (require)
|
|
695
|
+
│ ├── spin-wheel-sdk.d.ts ← TypeScript declarations (main)
|
|
696
|
+
│ ├── react.esm.mjs ← React subpath ESM
|
|
697
|
+
│ ├── react.cjs.js ← React subpath CJS
|
|
698
|
+
│ └── react.d.ts ← TypeScript declarations (React)
|
|
699
|
+
├── types/ ← Source TypeScript declarations (copied into dist/)
|
|
700
|
+
│ ├── spin-wheel-sdk.d.ts
|
|
701
|
+
│ └── react.d.ts
|
|
702
|
+
├── scripts/ ← Build helpers
|
|
703
|
+
│ └── copy-types.mjs
|
|
704
|
+
├── demo-vanilla-combined.html ← Combined Vanilla JS demo
|
|
705
|
+
├── demo-react-combined.html ← Combined React demo
|
|
706
|
+
├── package.json
|
|
707
|
+
├── CHANGELOG.md
|
|
708
|
+
├── LICENSE
|
|
709
|
+
└── README.md
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## License
|
|
715
|
+
|
|
716
|
+
MIT
|