react-raffle-picker 0.1.0 → 0.2.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 +35 -1
- package/dist/index.cjs +64 -6
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +64 -6
- package/dist/styles.css +63 -0
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
<h1>react-raffle-picker</h1>
|
|
5
5
|
|
|
6
|
-
<p><strong>
|
|
6
|
+
<p><strong>React like you just won. The raffle picker your UI deserves.</strong></p>
|
|
7
7
|
|
|
8
8
|
<p>
|
|
9
9
|
<a href="https://react-raffle-one.vercel.app/">Live demo</a>
|
|
@@ -75,6 +75,21 @@ import { RafflePick } from 'react-raffle-picker'
|
|
|
75
75
|
</RafflePick>
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
### Styles
|
|
79
|
+
|
|
80
|
+
The library is headless — no global stylesheet is required for `Value`, `Button`, or `Countdown`. You bring your own CSS.
|
|
81
|
+
|
|
82
|
+
For the **slot reel** (`<RafflePick.Slots>`), a minimal stylesheet *is* required to make the column animate. Two ways to load it:
|
|
83
|
+
|
|
84
|
+
1. **Auto-injected at runtime** — `<RafflePick.Slots>` injects a `<style data-rrp-slot-base>` tag into `document.head` on first mount. No action needed in CSR apps.
|
|
85
|
+
2. **Static import** (recommended for SSR / strict CSP / full control):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import 'react-raffle-picker/styles.css'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This file also includes opt-in keyframes for `<RafflePick.Value animation="roll|fade|blur|reel" />`. Override or replace any selector in your own CSS.
|
|
92
|
+
|
|
78
93
|
## Components
|
|
79
94
|
|
|
80
95
|
### `<RafflePick>` (root)
|
|
@@ -89,6 +104,8 @@ Provides context. Renders an optional wrapper element (`as` prop, default `'div'
|
|
|
89
104
|
| `random` | `boolean` | `true` | Random pick vs sequential. |
|
|
90
105
|
| `inertia` | `boolean` | `false` | Soft start / soft stop ramp. |
|
|
91
106
|
| `autoStart` | `boolean` | `true` | Begin cycling on mount. |
|
|
107
|
+
| `initialValue` | `number \| string` | — | Starting display before first run. Number for `min`/`max` mode, string for `items` mode. |
|
|
108
|
+
| `finalValue` | `number \| string` | — | Forces settle to land on this value. Cycle still appears random; only final freeze is rigged. |
|
|
92
109
|
| `onSelect` | `(value) => void` | — | Fires once per round on freeze. |
|
|
93
110
|
| `as` | `ElementType` | `'div'` | Wrapper tag. |
|
|
94
111
|
| `className` | `string` | — | Wrapper class. |
|
|
@@ -166,6 +183,23 @@ Independent multi-reel slot machine. Each reel ticks on its own and stops with a
|
|
|
166
183
|
</RafflePick>
|
|
167
184
|
```
|
|
168
185
|
|
|
186
|
+
### Rigged draw with predetermined winner
|
|
187
|
+
|
|
188
|
+
`finalValue` lands the freeze on a specific value while the cycle still looks random — useful for staged demos, scripted reveals, or showing a known winner.
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
<RafflePick
|
|
192
|
+
items={['Alice', 'Bob', 'Carol']}
|
|
193
|
+
initialValue="Alice"
|
|
194
|
+
finalValue="Bob"
|
|
195
|
+
autoStart={false}
|
|
196
|
+
onSelect={(winner) => console.log(winner)} // always 'Bob'
|
|
197
|
+
>
|
|
198
|
+
<RafflePick.Value animation="reel" />
|
|
199
|
+
<RafflePick.Button startLabel="Draw" stopLabel="Reveal" />
|
|
200
|
+
</RafflePick>
|
|
201
|
+
```
|
|
202
|
+
|
|
169
203
|
### Slot machine with custom result handler
|
|
170
204
|
|
|
171
205
|
```tsx
|
package/dist/index.cjs
CHANGED
|
@@ -172,7 +172,7 @@ const useRaffleContext = (componentName) => {
|
|
|
172
172
|
};
|
|
173
173
|
//#endregion
|
|
174
174
|
//#region src/components/RafflePick/RafflePick.tsx
|
|
175
|
-
function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = true, inertia = false, autoStart = true, onSelect, as = "div", className, style, children }) {
|
|
175
|
+
function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = true, inertia = false, autoStart = true, initialValue, finalValue, onSelect, as = "div", className, style, children }) {
|
|
176
176
|
const itemCount = items?.length ?? 0;
|
|
177
177
|
const hasItems = itemCount > 0;
|
|
178
178
|
const cycleMin = hasItems ? 0 : min;
|
|
@@ -186,7 +186,33 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
186
186
|
const its = itemsRef.current;
|
|
187
187
|
return its && its.length > 0 ? its[index] : index;
|
|
188
188
|
}, []);
|
|
189
|
-
const
|
|
189
|
+
const valueToIndex = (0, react.useCallback)((value) => {
|
|
190
|
+
if (value === void 0) return void 0;
|
|
191
|
+
const its = itemsRef.current;
|
|
192
|
+
if (its && its.length > 0) {
|
|
193
|
+
const i = its.indexOf(String(value));
|
|
194
|
+
return i >= 0 ? i : void 0;
|
|
195
|
+
}
|
|
196
|
+
return typeof value === "number" ? value : void 0;
|
|
197
|
+
}, []);
|
|
198
|
+
const initialIndex = (() => {
|
|
199
|
+
if (initialValue === void 0) return cycleMin;
|
|
200
|
+
if (items && items.length > 0) {
|
|
201
|
+
const i = items.indexOf(String(initialValue));
|
|
202
|
+
return i >= 0 ? i : cycleMin;
|
|
203
|
+
}
|
|
204
|
+
return typeof initialValue === "number" ? initialValue : cycleMin;
|
|
205
|
+
})();
|
|
206
|
+
const [displayed, setDisplayed] = (0, react.useState)(() => {
|
|
207
|
+
if (initialValue !== void 0) {
|
|
208
|
+
const its = items;
|
|
209
|
+
if (its && its.length > 0) {
|
|
210
|
+
const i = its.indexOf(String(initialValue));
|
|
211
|
+
if (i >= 0) return its[i];
|
|
212
|
+
} else if (typeof initialValue === "number") return initialValue;
|
|
213
|
+
}
|
|
214
|
+
return items && items.length > 0 ? items[cycleMin] : cycleMin;
|
|
215
|
+
});
|
|
190
216
|
const subscribersRef = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
191
217
|
const subscribe = (0, react.useCallback)((fn) => {
|
|
192
218
|
subscribersRef.current.add(fn);
|
|
@@ -197,12 +223,22 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
197
223
|
const onTick = (0, react.useCallback)((value) => {
|
|
198
224
|
subscribersRef.current.forEach((fn) => fn(value));
|
|
199
225
|
}, []);
|
|
200
|
-
const valueRef = (0, react.useRef)(
|
|
226
|
+
const valueRef = (0, react.useRef)(initialIndex);
|
|
227
|
+
const finalValueRef = (0, react.useRef)(finalValue);
|
|
228
|
+
(0, react.useEffect)(() => {
|
|
229
|
+
finalValueRef.current = finalValue;
|
|
230
|
+
}, [finalValue]);
|
|
201
231
|
const { phase, step, start, freeze, reset } = useRafflePhase(inertia, initialPhase, (0, react.useCallback)(() => {
|
|
232
|
+
const forced = valueToIndex(finalValueRef.current);
|
|
233
|
+
if (forced !== void 0) valueRef.current = forced;
|
|
202
234
|
const v = displayValue(valueRef.current);
|
|
203
235
|
setDisplayed(v);
|
|
204
236
|
onSelect?.(v);
|
|
205
|
-
}, [
|
|
237
|
+
}, [
|
|
238
|
+
displayValue,
|
|
239
|
+
onSelect,
|
|
240
|
+
valueToIndex
|
|
241
|
+
]));
|
|
206
242
|
const multiplier = getInertiaMultiplier(phase, step, inertia);
|
|
207
243
|
const cycleInterval = Math.round(Math.max(50, interval) * multiplier);
|
|
208
244
|
useNumberCycle({
|
|
@@ -221,7 +257,7 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
221
257
|
cycleInterval,
|
|
222
258
|
inertia,
|
|
223
259
|
hasItems,
|
|
224
|
-
initialIndex
|
|
260
|
+
initialIndex,
|
|
225
261
|
valueRef,
|
|
226
262
|
displayValue,
|
|
227
263
|
subscribe,
|
|
@@ -235,7 +271,7 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
235
271
|
cycleInterval,
|
|
236
272
|
inertia,
|
|
237
273
|
hasItems,
|
|
238
|
-
|
|
274
|
+
initialIndex,
|
|
239
275
|
displayValue,
|
|
240
276
|
subscribe,
|
|
241
277
|
start,
|
|
@@ -388,6 +424,27 @@ function CountdownRunning({ seconds, className, style, children }) {
|
|
|
388
424
|
//#endregion
|
|
389
425
|
//#region src/components/RafflePick/RafflePickSlots.tsx
|
|
390
426
|
const pickRandom = (pool) => pool[Math.floor(Math.random() * pool.length)] ?? "";
|
|
427
|
+
const SLOT_BASE_CSS = `
|
|
428
|
+
.rrp-slot{display:inline-block;overflow:hidden;height:1em;line-height:1em;vertical-align:baseline}
|
|
429
|
+
.rrp-slot__col{display:flex;flex-direction:column;transform:translateY(-1em);animation:rrp-slot-reel var(--rrp-tick,80ms) linear infinite}
|
|
430
|
+
.rrp-slot__cell{display:block;height:1em;line-height:1em}
|
|
431
|
+
.rrp-slot[data-stopped] .rrp-slot__col{animation:none;transform:translateY(-1em)}
|
|
432
|
+
@keyframes rrp-slot-reel{from{transform:translateY(-1em)}to{transform:translateY(-2em)}}
|
|
433
|
+
`;
|
|
434
|
+
let slotStylesInjected = false;
|
|
435
|
+
const injectSlotStyles = () => {
|
|
436
|
+
if (slotStylesInjected) return;
|
|
437
|
+
if (typeof document === "undefined") return;
|
|
438
|
+
if (document.querySelector("style[data-rrp-slot-base]")) {
|
|
439
|
+
slotStylesInjected = true;
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const tag = document.createElement("style");
|
|
443
|
+
tag.setAttribute("data-rrp-slot-base", "");
|
|
444
|
+
tag.textContent = SLOT_BASE_CSS;
|
|
445
|
+
document.head.appendChild(tag);
|
|
446
|
+
slotStylesInjected = true;
|
|
447
|
+
};
|
|
391
448
|
const makeRefs = () => ({
|
|
392
449
|
root: null,
|
|
393
450
|
col: null,
|
|
@@ -398,6 +455,7 @@ const makeRefs = () => ({
|
|
|
398
455
|
stopped: false
|
|
399
456
|
});
|
|
400
457
|
function RafflePickSlots({ length = 3, chars = "0123456789", spinInterval = 80, staggerMs = 220, className, slotClassName, style, slotStyle, onResult }) {
|
|
458
|
+
injectSlotStyles();
|
|
401
459
|
const { phase } = useRaffleContext("RafflePick.Slots");
|
|
402
460
|
const slotsRef = (0, react.useRef)([]);
|
|
403
461
|
const stopTimersRef = (0, react.useRef)([]);
|
package/dist/index.d.cts
CHANGED
|
@@ -13,6 +13,10 @@ interface RafflePickRootProps {
|
|
|
13
13
|
random?: boolean;
|
|
14
14
|
inertia?: boolean;
|
|
15
15
|
autoStart?: boolean;
|
|
16
|
+
/** Value shown before first run. Number in min/max mode, string in items mode. */
|
|
17
|
+
initialValue?: RafflePickValue$1;
|
|
18
|
+
/** When set, settle always lands on this value while cycle still appears random. */
|
|
19
|
+
finalValue?: RafflePickValue$1;
|
|
16
20
|
onSelect?: (value: RafflePickValue$1) => void;
|
|
17
21
|
as?: ElementType;
|
|
18
22
|
className?: string;
|
|
@@ -71,6 +75,8 @@ declare function RafflePickRoot({
|
|
|
71
75
|
random,
|
|
72
76
|
inertia,
|
|
73
77
|
autoStart,
|
|
78
|
+
initialValue,
|
|
79
|
+
finalValue,
|
|
74
80
|
onSelect,
|
|
75
81
|
as,
|
|
76
82
|
className,
|
package/dist/index.d.mts
CHANGED
|
@@ -13,6 +13,10 @@ interface RafflePickRootProps {
|
|
|
13
13
|
random?: boolean;
|
|
14
14
|
inertia?: boolean;
|
|
15
15
|
autoStart?: boolean;
|
|
16
|
+
/** Value shown before first run. Number in min/max mode, string in items mode. */
|
|
17
|
+
initialValue?: RafflePickValue$1;
|
|
18
|
+
/** When set, settle always lands on this value while cycle still appears random. */
|
|
19
|
+
finalValue?: RafflePickValue$1;
|
|
16
20
|
onSelect?: (value: RafflePickValue$1) => void;
|
|
17
21
|
as?: ElementType;
|
|
18
22
|
className?: string;
|
|
@@ -71,6 +75,8 @@ declare function RafflePickRoot({
|
|
|
71
75
|
random,
|
|
72
76
|
inertia,
|
|
73
77
|
autoStart,
|
|
78
|
+
initialValue,
|
|
79
|
+
finalValue,
|
|
74
80
|
onSelect,
|
|
75
81
|
as,
|
|
76
82
|
className,
|
package/dist/index.mjs
CHANGED
|
@@ -171,7 +171,7 @@ const useRaffleContext = (componentName) => {
|
|
|
171
171
|
};
|
|
172
172
|
//#endregion
|
|
173
173
|
//#region src/components/RafflePick/RafflePick.tsx
|
|
174
|
-
function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = true, inertia = false, autoStart = true, onSelect, as = "div", className, style, children }) {
|
|
174
|
+
function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = true, inertia = false, autoStart = true, initialValue, finalValue, onSelect, as = "div", className, style, children }) {
|
|
175
175
|
const itemCount = items?.length ?? 0;
|
|
176
176
|
const hasItems = itemCount > 0;
|
|
177
177
|
const cycleMin = hasItems ? 0 : min;
|
|
@@ -185,7 +185,33 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
185
185
|
const its = itemsRef.current;
|
|
186
186
|
return its && its.length > 0 ? its[index] : index;
|
|
187
187
|
}, []);
|
|
188
|
-
const
|
|
188
|
+
const valueToIndex = useCallback((value) => {
|
|
189
|
+
if (value === void 0) return void 0;
|
|
190
|
+
const its = itemsRef.current;
|
|
191
|
+
if (its && its.length > 0) {
|
|
192
|
+
const i = its.indexOf(String(value));
|
|
193
|
+
return i >= 0 ? i : void 0;
|
|
194
|
+
}
|
|
195
|
+
return typeof value === "number" ? value : void 0;
|
|
196
|
+
}, []);
|
|
197
|
+
const initialIndex = (() => {
|
|
198
|
+
if (initialValue === void 0) return cycleMin;
|
|
199
|
+
if (items && items.length > 0) {
|
|
200
|
+
const i = items.indexOf(String(initialValue));
|
|
201
|
+
return i >= 0 ? i : cycleMin;
|
|
202
|
+
}
|
|
203
|
+
return typeof initialValue === "number" ? initialValue : cycleMin;
|
|
204
|
+
})();
|
|
205
|
+
const [displayed, setDisplayed] = useState(() => {
|
|
206
|
+
if (initialValue !== void 0) {
|
|
207
|
+
const its = items;
|
|
208
|
+
if (its && its.length > 0) {
|
|
209
|
+
const i = its.indexOf(String(initialValue));
|
|
210
|
+
if (i >= 0) return its[i];
|
|
211
|
+
} else if (typeof initialValue === "number") return initialValue;
|
|
212
|
+
}
|
|
213
|
+
return items && items.length > 0 ? items[cycleMin] : cycleMin;
|
|
214
|
+
});
|
|
189
215
|
const subscribersRef = useRef(/* @__PURE__ */ new Set());
|
|
190
216
|
const subscribe = useCallback((fn) => {
|
|
191
217
|
subscribersRef.current.add(fn);
|
|
@@ -196,12 +222,22 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
196
222
|
const onTick = useCallback((value) => {
|
|
197
223
|
subscribersRef.current.forEach((fn) => fn(value));
|
|
198
224
|
}, []);
|
|
199
|
-
const valueRef = useRef(
|
|
225
|
+
const valueRef = useRef(initialIndex);
|
|
226
|
+
const finalValueRef = useRef(finalValue);
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
finalValueRef.current = finalValue;
|
|
229
|
+
}, [finalValue]);
|
|
200
230
|
const { phase, step, start, freeze, reset } = useRafflePhase(inertia, initialPhase, useCallback(() => {
|
|
231
|
+
const forced = valueToIndex(finalValueRef.current);
|
|
232
|
+
if (forced !== void 0) valueRef.current = forced;
|
|
201
233
|
const v = displayValue(valueRef.current);
|
|
202
234
|
setDisplayed(v);
|
|
203
235
|
onSelect?.(v);
|
|
204
|
-
}, [
|
|
236
|
+
}, [
|
|
237
|
+
displayValue,
|
|
238
|
+
onSelect,
|
|
239
|
+
valueToIndex
|
|
240
|
+
]));
|
|
205
241
|
const multiplier = getInertiaMultiplier(phase, step, inertia);
|
|
206
242
|
const cycleInterval = Math.round(Math.max(50, interval) * multiplier);
|
|
207
243
|
useNumberCycle({
|
|
@@ -220,7 +256,7 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
220
256
|
cycleInterval,
|
|
221
257
|
inertia,
|
|
222
258
|
hasItems,
|
|
223
|
-
initialIndex
|
|
259
|
+
initialIndex,
|
|
224
260
|
valueRef,
|
|
225
261
|
displayValue,
|
|
226
262
|
subscribe,
|
|
@@ -234,7 +270,7 @@ function RafflePickRoot({ items, min = 1, max = 100, interval = 100, random = tr
|
|
|
234
270
|
cycleInterval,
|
|
235
271
|
inertia,
|
|
236
272
|
hasItems,
|
|
237
|
-
|
|
273
|
+
initialIndex,
|
|
238
274
|
displayValue,
|
|
239
275
|
subscribe,
|
|
240
276
|
start,
|
|
@@ -387,6 +423,27 @@ function CountdownRunning({ seconds, className, style, children }) {
|
|
|
387
423
|
//#endregion
|
|
388
424
|
//#region src/components/RafflePick/RafflePickSlots.tsx
|
|
389
425
|
const pickRandom = (pool) => pool[Math.floor(Math.random() * pool.length)] ?? "";
|
|
426
|
+
const SLOT_BASE_CSS = `
|
|
427
|
+
.rrp-slot{display:inline-block;overflow:hidden;height:1em;line-height:1em;vertical-align:baseline}
|
|
428
|
+
.rrp-slot__col{display:flex;flex-direction:column;transform:translateY(-1em);animation:rrp-slot-reel var(--rrp-tick,80ms) linear infinite}
|
|
429
|
+
.rrp-slot__cell{display:block;height:1em;line-height:1em}
|
|
430
|
+
.rrp-slot[data-stopped] .rrp-slot__col{animation:none;transform:translateY(-1em)}
|
|
431
|
+
@keyframes rrp-slot-reel{from{transform:translateY(-1em)}to{transform:translateY(-2em)}}
|
|
432
|
+
`;
|
|
433
|
+
let slotStylesInjected = false;
|
|
434
|
+
const injectSlotStyles = () => {
|
|
435
|
+
if (slotStylesInjected) return;
|
|
436
|
+
if (typeof document === "undefined") return;
|
|
437
|
+
if (document.querySelector("style[data-rrp-slot-base]")) {
|
|
438
|
+
slotStylesInjected = true;
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
const tag = document.createElement("style");
|
|
442
|
+
tag.setAttribute("data-rrp-slot-base", "");
|
|
443
|
+
tag.textContent = SLOT_BASE_CSS;
|
|
444
|
+
document.head.appendChild(tag);
|
|
445
|
+
slotStylesInjected = true;
|
|
446
|
+
};
|
|
390
447
|
const makeRefs = () => ({
|
|
391
448
|
root: null,
|
|
392
449
|
col: null,
|
|
@@ -397,6 +454,7 @@ const makeRefs = () => ({
|
|
|
397
454
|
stopped: false
|
|
398
455
|
});
|
|
399
456
|
function RafflePickSlots({ length = 3, chars = "0123456789", spinInterval = 80, staggerMs = 220, className, slotClassName, style, slotStyle, onResult }) {
|
|
457
|
+
injectSlotStyles();
|
|
400
458
|
const { phase } = useRaffleContext("RafflePick.Slots");
|
|
401
459
|
const slotsRef = useRef([]);
|
|
402
460
|
const stopTimersRef = useRef([]);
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* react-raffle-picker — base styles */
|
|
2
|
+
/* Optional. Slot reel animation is also auto-injected at runtime. */
|
|
3
|
+
/* Import via: import 'react-raffle-picker/styles.css' */
|
|
4
|
+
|
|
5
|
+
.rrp-slot {
|
|
6
|
+
display: inline-block;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
height: 1em;
|
|
9
|
+
line-height: 1em;
|
|
10
|
+
vertical-align: baseline;
|
|
11
|
+
}
|
|
12
|
+
.rrp-slot__col {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
transform: translateY(-1em);
|
|
16
|
+
animation: rrp-slot-reel var(--rrp-tick, 80ms) linear infinite;
|
|
17
|
+
}
|
|
18
|
+
.rrp-slot__cell {
|
|
19
|
+
display: block;
|
|
20
|
+
height: 1em;
|
|
21
|
+
line-height: 1em;
|
|
22
|
+
}
|
|
23
|
+
.rrp-slot[data-stopped] .rrp-slot__col {
|
|
24
|
+
animation: none;
|
|
25
|
+
transform: translateY(-1em);
|
|
26
|
+
}
|
|
27
|
+
@keyframes rrp-slot-reel {
|
|
28
|
+
from { transform: translateY(-1em); }
|
|
29
|
+
to { transform: translateY(-2em); }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Value animations: opt-in via <RafflePick.Value animation="..." /> */
|
|
33
|
+
.rrp-value {
|
|
34
|
+
display: inline-block;
|
|
35
|
+
}
|
|
36
|
+
.rrp-value[data-animation='roll'][data-phase='running'] {
|
|
37
|
+
animation: rrp-value-roll var(--rrp-tick, 100ms) linear;
|
|
38
|
+
}
|
|
39
|
+
.rrp-value[data-animation='fade'][data-phase='running'] {
|
|
40
|
+
animation: rrp-value-fade var(--rrp-tick, 100ms) linear;
|
|
41
|
+
}
|
|
42
|
+
.rrp-value[data-animation='blur'][data-phase='running'] {
|
|
43
|
+
animation: rrp-value-blur var(--rrp-tick, 100ms) linear;
|
|
44
|
+
}
|
|
45
|
+
.rrp-value[data-animation='reel'][data-phase='running'] {
|
|
46
|
+
animation: rrp-value-reel var(--rrp-tick, 100ms) linear;
|
|
47
|
+
}
|
|
48
|
+
@keyframes rrp-value-roll {
|
|
49
|
+
from { transform: translateY(-0.4em); opacity: 0.4; }
|
|
50
|
+
to { transform: translateY(0); opacity: 1; }
|
|
51
|
+
}
|
|
52
|
+
@keyframes rrp-value-fade {
|
|
53
|
+
from { opacity: 0.2; }
|
|
54
|
+
to { opacity: 1; }
|
|
55
|
+
}
|
|
56
|
+
@keyframes rrp-value-blur {
|
|
57
|
+
from { filter: blur(4px); }
|
|
58
|
+
to { filter: blur(0); }
|
|
59
|
+
}
|
|
60
|
+
@keyframes rrp-value-reel {
|
|
61
|
+
from { transform: translateY(-1em); opacity: 0; }
|
|
62
|
+
to { transform: translateY(0); opacity: 1; }
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-raffle-picker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Headless React raffle picker for giveaways, winner draws, countdowns, and slot-machine UIs.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public",
|
|
8
|
+
"registry": "https://registry.npmjs.org/",
|
|
9
|
+
"provenance": true
|
|
10
|
+
},
|
|
6
11
|
"main": "./dist/index.cjs",
|
|
7
12
|
"module": "./dist/index.mjs",
|
|
8
13
|
"types": "./dist/index.d.mts",
|
|
@@ -16,9 +21,12 @@
|
|
|
16
21
|
"require": "./dist/index.cjs",
|
|
17
22
|
"default": "./dist/index.mjs"
|
|
18
23
|
},
|
|
24
|
+
"./styles.css": "./dist/styles.css",
|
|
19
25
|
"./package.json": "./package.json"
|
|
20
26
|
},
|
|
21
|
-
"sideEffects":
|
|
27
|
+
"sideEffects": [
|
|
28
|
+
"**/*.css"
|
|
29
|
+
],
|
|
22
30
|
"files": [
|
|
23
31
|
"dist"
|
|
24
32
|
],
|
|
@@ -31,7 +39,7 @@
|
|
|
31
39
|
},
|
|
32
40
|
"homepage": "https://react-raffle-one.vercel.app/",
|
|
33
41
|
"scripts": {
|
|
34
|
-
"build": "tsdown",
|
|
42
|
+
"build": "tsdown && cp src/styles.css dist/styles.css",
|
|
35
43
|
"dev": "tsdown --watch",
|
|
36
44
|
"typecheck": "tsc --noEmit",
|
|
37
45
|
"test": "vitest",
|
|
@@ -45,7 +53,7 @@
|
|
|
45
53
|
"build-storybook": "storybook build",
|
|
46
54
|
"changeset": "changeset",
|
|
47
55
|
"version": "changeset version",
|
|
48
|
-
"release": "changeset publish
|
|
56
|
+
"release": "changeset publish"
|
|
49
57
|
},
|
|
50
58
|
"peerDependencies": {
|
|
51
59
|
"react": ">=17",
|
|
@@ -68,9 +76,6 @@
|
|
|
68
76
|
],
|
|
69
77
|
"author": "Kirilinsky (https://github.com/kirilinsky)",
|
|
70
78
|
"license": "MIT",
|
|
71
|
-
"publishConfig": {
|
|
72
|
-
"access": "public"
|
|
73
|
-
},
|
|
74
79
|
"engines": {
|
|
75
80
|
"node": ">=18"
|
|
76
81
|
},
|
|
@@ -107,4 +112,4 @@
|
|
|
107
112
|
"vite": "^8.0.8",
|
|
108
113
|
"vitest": "^4.1.4"
|
|
109
114
|
}
|
|
110
|
-
}
|
|
115
|
+
}
|