react-raffle-picker 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,549 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let react = require("react");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ //#region src/utils/get-random.ts
5
+ const getRandom = (min, max) => {
6
+ min = Math.ceil(min);
7
+ max = Math.floor(max);
8
+ return Math.floor(Math.random() * (max - min + 1)) + min;
9
+ };
10
+ //#endregion
11
+ //#region src/hooks/useNumberCycle.ts
12
+ const useNumberCycle = ({ min, max, interval, random, running, valueRef, onTick }) => {
13
+ const onTickRef = (0, react.useRef)(onTick);
14
+ (0, react.useEffect)(() => {
15
+ onTickRef.current = onTick;
16
+ });
17
+ (0, react.useEffect)(() => {
18
+ if (!running) return;
19
+ const id = setInterval(() => {
20
+ const cur = valueRef.current;
21
+ const next = random ? getRandom(min, max) : cur >= max ? min : cur + 1;
22
+ valueRef.current = next;
23
+ onTickRef.current?.(next);
24
+ }, interval);
25
+ return () => clearInterval(id);
26
+ }, [
27
+ running,
28
+ interval,
29
+ min,
30
+ max,
31
+ random,
32
+ valueRef
33
+ ]);
34
+ return valueRef;
35
+ };
36
+ //#endregion
37
+ //#region src/utils/inertia.ts
38
+ const STOP_INERTIA_MS = 1080;
39
+ const START_INTERVAL_MULTIPLIERS = [
40
+ 2.4,
41
+ 1.55,
42
+ 1
43
+ ];
44
+ const STOP_INTERVAL_MULTIPLIERS = [
45
+ 1.15,
46
+ 1.65,
47
+ 2.35,
48
+ 3.25
49
+ ];
50
+ const START_INERTIA_STEPS = [{
51
+ delay: 140,
52
+ step: 1
53
+ }, {
54
+ delay: 300,
55
+ step: 2
56
+ }];
57
+ const STOP_INERTIA_STEPS = [
58
+ {
59
+ delay: 180,
60
+ step: 1
61
+ },
62
+ {
63
+ delay: 460,
64
+ step: 2
65
+ },
66
+ {
67
+ delay: 760,
68
+ step: 3
69
+ }
70
+ ];
71
+ const getInertiaMultiplier = (phase, step, inertia) => {
72
+ if (!inertia) return 1;
73
+ if (phase === "starting") return START_INTERVAL_MULTIPLIERS[step] ?? 1;
74
+ if (phase === "settling") return STOP_INTERVAL_MULTIPLIERS[step] ?? STOP_INTERVAL_MULTIPLIERS[STOP_INTERVAL_MULTIPLIERS.length - 1];
75
+ return 1;
76
+ };
77
+ //#endregion
78
+ //#region src/hooks/useRafflePhase.ts
79
+ const reducer = (s, a) => a.type === "phase" ? {
80
+ phase: a.phase,
81
+ step: 0
82
+ } : {
83
+ phase: s.phase,
84
+ step: a.step
85
+ };
86
+ function useRafflePhase(inertia, initialPhase, onSettle) {
87
+ const [state, dispatch] = (0, react.useReducer)(reducer, {
88
+ phase: initialPhase,
89
+ step: 0
90
+ });
91
+ const timersRef = (0, react.useRef)([]);
92
+ const onSettleRef = (0, react.useRef)(onSettle);
93
+ (0, react.useEffect)(() => {
94
+ onSettleRef.current = onSettle;
95
+ });
96
+ const clear = (0, react.useCallback)(() => {
97
+ const timers = timersRef.current;
98
+ for (let i = 0; i < timers.length; i++) clearTimeout(timers[i]);
99
+ timersRef.current = [];
100
+ }, []);
101
+ (0, react.useEffect)(() => {
102
+ if (state.phase === "starting") {
103
+ for (const { delay, step } of START_INERTIA_STEPS) timersRef.current.push(setTimeout(() => dispatch({
104
+ type: "step",
105
+ step
106
+ }), delay));
107
+ timersRef.current.push(setTimeout(() => dispatch({
108
+ type: "phase",
109
+ phase: "running"
110
+ }), 460));
111
+ } else if (state.phase === "settling") {
112
+ for (const { delay, step } of STOP_INERTIA_STEPS) timersRef.current.push(setTimeout(() => dispatch({
113
+ type: "step",
114
+ step
115
+ }), delay));
116
+ timersRef.current.push(setTimeout(() => {
117
+ onSettleRef.current();
118
+ dispatch({
119
+ type: "phase",
120
+ phase: "frozen"
121
+ });
122
+ }, STOP_INERTIA_MS));
123
+ }
124
+ return clear;
125
+ }, [state.phase, clear]);
126
+ const start = (0, react.useCallback)(() => {
127
+ clear();
128
+ dispatch({
129
+ type: "phase",
130
+ phase: inertia ? "starting" : "running"
131
+ });
132
+ }, [clear, inertia]);
133
+ const freeze = (0, react.useCallback)(() => {
134
+ clear();
135
+ if (inertia) dispatch({
136
+ type: "phase",
137
+ phase: "settling"
138
+ });
139
+ else {
140
+ onSettleRef.current();
141
+ dispatch({
142
+ type: "phase",
143
+ phase: "frozen"
144
+ });
145
+ }
146
+ }, [clear, inertia]);
147
+ const reset = (0, react.useCallback)(() => {
148
+ clear();
149
+ dispatch({
150
+ type: "phase",
151
+ phase: "idle"
152
+ });
153
+ }, [clear]);
154
+ return {
155
+ phase: state.phase,
156
+ step: state.step,
157
+ start,
158
+ freeze,
159
+ reset
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/utils/class-names.ts
164
+ const joinClassNames = (...classNames) => classNames.filter(Boolean).join(" ");
165
+ //#endregion
166
+ //#region src/components/RafflePick/context.ts
167
+ const RaffleContext = (0, react.createContext)(null);
168
+ const useRaffleContext = (componentName) => {
169
+ const ctx = (0, react.useContext)(RaffleContext);
170
+ if (!ctx) throw new Error(`<${componentName}> must be rendered inside <RafflePick>.`);
171
+ return ctx;
172
+ };
173
+ //#endregion
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 }) {
176
+ const itemCount = items?.length ?? 0;
177
+ const hasItems = itemCount > 0;
178
+ const cycleMin = hasItems ? 0 : min;
179
+ const cycleMax = hasItems ? itemCount - 1 : max;
180
+ const initialPhase = autoStart ? inertia ? "starting" : "running" : "idle";
181
+ const itemsRef = (0, react.useRef)(items);
182
+ (0, react.useEffect)(() => {
183
+ itemsRef.current = items;
184
+ }, [items]);
185
+ const displayValue = (0, react.useCallback)((index) => {
186
+ const its = itemsRef.current;
187
+ return its && its.length > 0 ? its[index] : index;
188
+ }, []);
189
+ const [displayed, setDisplayed] = (0, react.useState)(() => items && items.length > 0 ? items[cycleMin] : cycleMin);
190
+ const subscribersRef = (0, react.useRef)(/* @__PURE__ */ new Set());
191
+ const subscribe = (0, react.useCallback)((fn) => {
192
+ subscribersRef.current.add(fn);
193
+ return () => {
194
+ subscribersRef.current.delete(fn);
195
+ };
196
+ }, []);
197
+ const onTick = (0, react.useCallback)((value) => {
198
+ subscribersRef.current.forEach((fn) => fn(value));
199
+ }, []);
200
+ const valueRef = (0, react.useRef)(cycleMin);
201
+ const { phase, step, start, freeze, reset } = useRafflePhase(inertia, initialPhase, (0, react.useCallback)(() => {
202
+ const v = displayValue(valueRef.current);
203
+ setDisplayed(v);
204
+ onSelect?.(v);
205
+ }, [displayValue, onSelect]));
206
+ const multiplier = getInertiaMultiplier(phase, step, inertia);
207
+ const cycleInterval = Math.round(Math.max(50, interval) * multiplier);
208
+ useNumberCycle({
209
+ min: cycleMin,
210
+ max: cycleMax,
211
+ interval: cycleInterval,
212
+ random,
213
+ running: phase === "starting" || phase === "running" || phase === "settling",
214
+ valueRef,
215
+ onTick
216
+ });
217
+ const ctxValue = (0, react.useMemo)(() => ({
218
+ phase,
219
+ step,
220
+ displayed,
221
+ cycleInterval,
222
+ inertia,
223
+ hasItems,
224
+ initialIndex: cycleMin,
225
+ valueRef,
226
+ displayValue,
227
+ subscribe,
228
+ start,
229
+ freeze,
230
+ reset
231
+ }), [
232
+ phase,
233
+ step,
234
+ displayed,
235
+ cycleInterval,
236
+ inertia,
237
+ hasItems,
238
+ cycleMin,
239
+ displayValue,
240
+ subscribe,
241
+ start,
242
+ freeze,
243
+ reset
244
+ ]);
245
+ const selectionState = phase === "idle" ? "idle" : phase === "frozen" ? "frozen" : "running";
246
+ return (0, react.createElement)(as, {
247
+ className: joinClassNames("rrp", className),
248
+ "data-state": selectionState,
249
+ "data-phase": phase,
250
+ "data-inertia-step": step,
251
+ "data-inertia": inertia ? "" : void 0,
252
+ style
253
+ }, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RaffleContext.Provider, {
254
+ value: ctxValue,
255
+ children
256
+ }));
257
+ }
258
+ //#endregion
259
+ //#region src/components/RafflePick/RafflePickValue.tsx
260
+ function RafflePickValue({ animation = "roll", className, style, as = "span" }) {
261
+ const { phase, step, displayed, cycleInterval, valueRef, displayValue, subscribe } = useRaffleContext("RafflePick.Value");
262
+ const nodeRef = (0, react.useRef)(null);
263
+ const writeNode = (0, react.useCallback)((value) => {
264
+ const node = nodeRef.current;
265
+ if (!node) return;
266
+ const txt = String(displayValue(value));
267
+ node.textContent = txt;
268
+ node.setAttribute("data-value", txt);
269
+ if (typeof node.getAnimations === "function") {
270
+ const anims = node.getAnimations({ subtree: true });
271
+ for (let i = 0; i < anims.length; i++) anims[i].currentTime = 0;
272
+ }
273
+ }, [displayValue]);
274
+ (0, react.useEffect)(() => subscribe(writeNode), [subscribe, writeNode]);
275
+ const running = phase === "starting" || phase === "running" || phase === "settling";
276
+ (0, react.useLayoutEffect)(() => {
277
+ if (running) writeNode(valueRef.current);
278
+ });
279
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(as, {
280
+ ref: nodeRef,
281
+ className: (0, react.useMemo)(() => joinClassNames("rrp-value", className), [className]),
282
+ "data-animation": animation,
283
+ "data-value": displayed,
284
+ "data-phase": phase,
285
+ "data-inertia-step": step,
286
+ style: (0, react.useMemo)(() => ({
287
+ ...style,
288
+ ["--rrp-tick"]: `${cycleInterval}ms`
289
+ }), [style, cycleInterval]),
290
+ children: displayed
291
+ });
292
+ }
293
+ //#endregion
294
+ //#region src/components/RafflePick/RafflePickButton.tsx
295
+ function RafflePickButton({ className, style, children, startLabel, stopLabel, waitLabel }) {
296
+ const { phase, start, freeze, reset } = useRaffleContext("RafflePick.Button");
297
+ const running = phase === "starting" || phase === "running" || phase === "settling";
298
+ const handleClick = (0, react.useCallback)(() => {
299
+ if (phase === "settling") return;
300
+ if (running) {
301
+ freeze();
302
+ return;
303
+ }
304
+ reset();
305
+ start();
306
+ }, [
307
+ phase,
308
+ running,
309
+ freeze,
310
+ reset,
311
+ start
312
+ ]);
313
+ const cls = (0, react.useMemo)(() => joinClassNames("rrp-button", className), [className]);
314
+ let label;
315
+ if (phase === "settling") label = waitLabel ?? stopLabel ?? children;
316
+ else if (phase === "starting" || phase === "running") label = stopLabel ?? children;
317
+ else label = startLabel ?? children;
318
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
319
+ className: cls,
320
+ style,
321
+ disabled: phase === "settling",
322
+ onClick: handleClick,
323
+ "data-phase": phase,
324
+ children: label
325
+ });
326
+ }
327
+ //#endregion
328
+ //#region src/components/RafflePick/RafflePickCountdown.tsx
329
+ function RafflePickCountdown({ seconds, className, style, children }) {
330
+ const { phase } = useRaffleContext("RafflePick.Countdown");
331
+ if (phase !== "running") return null;
332
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CountdownRunning, {
333
+ seconds,
334
+ className,
335
+ style,
336
+ children
337
+ }, `countdown-${seconds}`);
338
+ }
339
+ function CountdownRunning({ seconds, className, style, children }) {
340
+ const { freeze } = useRaffleContext("RafflePick.Countdown");
341
+ const [remaining, setRemaining] = (0, react.useState)(seconds);
342
+ (0, react.useEffect)(() => {
343
+ if (!seconds || seconds <= 0) return;
344
+ const tickId = setInterval(() => {
345
+ setRemaining((r) => r > 1 ? r - 1 : 0);
346
+ }, 1e3);
347
+ const stopId = setTimeout(() => freeze(), seconds * 1e3);
348
+ return () => {
349
+ clearInterval(tickId);
350
+ clearTimeout(stopId);
351
+ };
352
+ }, [seconds, freeze]);
353
+ const cls = (0, react.useMemo)(() => joinClassNames("rrp-countdown", className), [className]);
354
+ const mergedStyle = (0, react.useMemo)(() => ({
355
+ ...style,
356
+ ["--rrp-countdown"]: `${seconds}s`
357
+ }), [style, seconds]);
358
+ if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
359
+ className: cls,
360
+ style: mergedStyle,
361
+ "aria-hidden": "true",
362
+ children: children(remaining)
363
+ });
364
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
365
+ className: cls,
366
+ style: mergedStyle,
367
+ "aria-hidden": "true",
368
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
369
+ className: "rrp-countdown__svg",
370
+ viewBox: "0 0 36 36",
371
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
372
+ className: "rrp-countdown__track",
373
+ cx: "18",
374
+ cy: "18",
375
+ r: "16"
376
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
377
+ className: "rrp-countdown__bar",
378
+ cx: "18",
379
+ cy: "18",
380
+ r: "16"
381
+ })]
382
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
383
+ className: "rrp-countdown__label",
384
+ children: remaining
385
+ })]
386
+ });
387
+ }
388
+ //#endregion
389
+ //#region src/components/RafflePick/RafflePickSlots.tsx
390
+ const pickRandom = (pool) => pool[Math.floor(Math.random() * pool.length)] ?? "";
391
+ const makeRefs = () => ({
392
+ root: null,
393
+ col: null,
394
+ prev: null,
395
+ curr: null,
396
+ next: null,
397
+ currChar: "",
398
+ stopped: false
399
+ });
400
+ function RafflePickSlots({ length = 3, chars = "0123456789", spinInterval = 80, staggerMs = 220, className, slotClassName, style, slotStyle, onResult }) {
401
+ const { phase } = useRaffleContext("RafflePick.Slots");
402
+ const slotsRef = (0, react.useRef)([]);
403
+ const stopTimersRef = (0, react.useRef)([]);
404
+ const finalRef = (0, react.useRef)([]);
405
+ const onResultRef = (0, react.useRef)(onResult);
406
+ (0, react.useEffect)(() => {
407
+ onResultRef.current = onResult;
408
+ });
409
+ if (slotsRef.current.length !== length) slotsRef.current = Array.from({ length }, (_, i) => slotsRef.current[i] ?? makeRefs());
410
+ const pool = (0, react.useMemo)(() => Array.from(chars), [chars]);
411
+ const safeInterval = Math.max(50, spinInterval);
412
+ const running = phase === "starting" || phase === "running";
413
+ const settling = phase === "settling" || phase === "frozen";
414
+ const writeSlot = (s, prev, curr, next) => {
415
+ if (s.prev) s.prev.textContent = prev;
416
+ if (s.curr) s.curr.textContent = curr;
417
+ if (s.next) s.next.textContent = next;
418
+ s.currChar = curr;
419
+ if (s.root) s.root.setAttribute("data-value", curr);
420
+ if (s.col && typeof s.col.getAnimations === "function") {
421
+ const anims = s.col.getAnimations();
422
+ for (let a = 0; a < anims.length; a++) anims[a].currentTime = 0;
423
+ }
424
+ };
425
+ (0, react.useEffect)(() => {
426
+ if (!running) return;
427
+ for (let i = 0; i < length; i++) {
428
+ const s = slotsRef.current[i];
429
+ s.stopped = false;
430
+ if (s.root) s.root.removeAttribute("data-stopped");
431
+ writeSlot(s, pickRandom(pool), pickRandom(pool), pickRandom(pool));
432
+ }
433
+ finalRef.current = new Array(length).fill("");
434
+ const id = setInterval(() => {
435
+ for (let i = 0; i < length; i++) {
436
+ const s = slotsRef.current[i];
437
+ if (s.stopped) continue;
438
+ const newPrev = s.currChar;
439
+ writeSlot(s, newPrev, s.next?.textContent ?? pickRandom(pool), pickRandom(pool));
440
+ }
441
+ }, safeInterval);
442
+ return () => clearInterval(id);
443
+ }, [
444
+ running,
445
+ length,
446
+ pool,
447
+ safeInterval
448
+ ]);
449
+ (0, react.useEffect)(() => {
450
+ if (!settling) return;
451
+ const clear = () => {
452
+ stopTimersRef.current.forEach(clearTimeout);
453
+ stopTimersRef.current = [];
454
+ };
455
+ clear();
456
+ for (let i = 0; i < length; i++) {
457
+ const id = setTimeout(() => {
458
+ const s = slotsRef.current[i];
459
+ s.stopped = true;
460
+ if (s.root) s.root.setAttribute("data-stopped", "");
461
+ finalRef.current[i] = s.currChar;
462
+ if (i === length - 1) onResultRef.current?.(finalRef.current.join(""));
463
+ }, i * staggerMs);
464
+ stopTimersRef.current.push(id);
465
+ }
466
+ return clear;
467
+ }, [
468
+ settling,
469
+ length,
470
+ staggerMs
471
+ ]);
472
+ (0, react.useEffect)(() => {
473
+ if (phase !== "idle") return;
474
+ const c = pool[0] ?? "";
475
+ for (let i = 0; i < length; i++) {
476
+ const s = slotsRef.current[i];
477
+ s.stopped = true;
478
+ writeSlot(s, c, c, c);
479
+ if (s.root) s.root.removeAttribute("data-stopped");
480
+ }
481
+ }, [
482
+ phase,
483
+ length,
484
+ pool
485
+ ]);
486
+ const cls = (0, react.useMemo)(() => joinClassNames("rrp-slots", className), [className]);
487
+ const slotCls = (0, react.useMemo)(() => joinClassNames("rrp-slot", slotClassName), [slotClassName]);
488
+ const mergedSlotStyle = (0, react.useMemo)(() => ({
489
+ ...slotStyle,
490
+ ["--rrp-tick"]: `${safeInterval}ms`
491
+ }), [slotStyle, safeInterval]);
492
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
493
+ className: cls,
494
+ style,
495
+ "data-phase": phase,
496
+ children: Array.from({ length }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
497
+ ref: (n) => {
498
+ slotsRef.current[i].root = n;
499
+ },
500
+ className: slotCls,
501
+ style: mergedSlotStyle,
502
+ "data-slot-index": i,
503
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
504
+ className: "rrp-slot__col",
505
+ ref: (n) => {
506
+ slotsRef.current[i].col = n;
507
+ },
508
+ children: [
509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
510
+ className: "rrp-slot__cell",
511
+ ref: (n) => {
512
+ slotsRef.current[i].prev = n;
513
+ },
514
+ children: pool[0] ?? ""
515
+ }),
516
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
517
+ className: "rrp-slot__cell",
518
+ ref: (n) => {
519
+ slotsRef.current[i].curr = n;
520
+ },
521
+ children: pool[0] ?? ""
522
+ }),
523
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
524
+ className: "rrp-slot__cell",
525
+ ref: (n) => {
526
+ slotsRef.current[i].next = n;
527
+ },
528
+ children: pool[0] ?? ""
529
+ })
530
+ ]
531
+ })
532
+ }, i))
533
+ });
534
+ }
535
+ //#endregion
536
+ //#region src/components/RafflePick/index.ts
537
+ const RafflePick = RafflePickRoot;
538
+ RafflePick.Value = RafflePickValue;
539
+ RafflePick.Button = RafflePickButton;
540
+ RafflePick.Countdown = RafflePickCountdown;
541
+ RafflePick.Slots = RafflePickSlots;
542
+ //#endregion
543
+ exports.RaffleContext = RaffleContext;
544
+ exports.RafflePick = RafflePick;
545
+ exports.RafflePickButton = RafflePickButton;
546
+ exports.RafflePickCountdown = RafflePickCountdown;
547
+ exports.RafflePickSlots = RafflePickSlots;
548
+ exports.RafflePickValue = RafflePickValue;
549
+ exports.useRaffleContext = useRaffleContext;
@@ -0,0 +1,151 @@
1
+ import * as _$react from "react";
2
+ import { CSSProperties, ElementType, ReactNode, RefObject } from "react";
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/types.d.ts
6
+ type AnimationType = 'roll' | 'fade' | 'blur' | 'reel';
7
+ type RafflePickValue$1 = number | string;
8
+ interface RafflePickRootProps {
9
+ items?: string[];
10
+ min?: number;
11
+ max?: number;
12
+ interval?: number;
13
+ random?: boolean;
14
+ inertia?: boolean;
15
+ autoStart?: boolean;
16
+ onSelect?: (value: RafflePickValue$1) => void;
17
+ as?: ElementType;
18
+ className?: string;
19
+ style?: CSSProperties;
20
+ children?: ReactNode;
21
+ }
22
+ interface RafflePickValueProps {
23
+ animation?: AnimationType;
24
+ className?: string;
25
+ style?: CSSProperties;
26
+ as?: ElementType;
27
+ }
28
+ interface RafflePickButtonProps {
29
+ className?: string;
30
+ style?: CSSProperties;
31
+ /** Fallback label across all states. */
32
+ children?: ReactNode;
33
+ /** Label for idle / frozen (click starts a round). */
34
+ startLabel?: ReactNode;
35
+ /** Label while running (click stops). */
36
+ stopLabel?: ReactNode;
37
+ /** Label while settling (button disabled). */
38
+ waitLabel?: ReactNode;
39
+ }
40
+ interface RafflePickSlotsProps {
41
+ /** Number of slots. */
42
+ length?: number;
43
+ /** Character pool each slot picks from. */
44
+ chars?: string;
45
+ /** Tick interval per slot, ms. Clamped ≥ 50. */
46
+ spinInterval?: number;
47
+ /** Delay between consecutive slot stops on settle, ms. */
48
+ staggerMs?: number;
49
+ className?: string;
50
+ slotClassName?: string;
51
+ style?: CSSProperties;
52
+ slotStyle?: CSSProperties;
53
+ /** Fires when last slot stops with joined result. */
54
+ onResult?: (result: string) => void;
55
+ }
56
+ interface RafflePickCountdownProps {
57
+ /** Seconds before auto-freeze. Required. */
58
+ seconds: number;
59
+ className?: string;
60
+ style?: CSSProperties;
61
+ /** Render-prop for fully custom output. Receives remaining seconds. */
62
+ children?: (remaining: number) => ReactNode;
63
+ }
64
+ //#endregion
65
+ //#region src/components/RafflePick/RafflePick.d.ts
66
+ declare function RafflePickRoot({
67
+ items,
68
+ min,
69
+ max,
70
+ interval,
71
+ random,
72
+ inertia,
73
+ autoStart,
74
+ onSelect,
75
+ as,
76
+ className,
77
+ style,
78
+ children
79
+ }: RafflePickRootProps): _$react.ReactElement<any, string | _$react.JSXElementConstructor<any>>;
80
+ //#endregion
81
+ //#region src/components/RafflePick/RafflePickValue.d.ts
82
+ declare function RafflePickValue({
83
+ animation,
84
+ className,
85
+ style,
86
+ as
87
+ }: RafflePickValueProps): _$react_jsx_runtime0.JSX.Element;
88
+ //#endregion
89
+ //#region src/components/RafflePick/RafflePickButton.d.ts
90
+ declare function RafflePickButton({
91
+ className,
92
+ style,
93
+ children,
94
+ startLabel,
95
+ stopLabel,
96
+ waitLabel
97
+ }: RafflePickButtonProps): _$react_jsx_runtime0.JSX.Element;
98
+ //#endregion
99
+ //#region src/components/RafflePick/RafflePickCountdown.d.ts
100
+ declare function RafflePickCountdown({
101
+ seconds,
102
+ className,
103
+ style,
104
+ children
105
+ }: RafflePickCountdownProps): _$react_jsx_runtime0.JSX.Element | null;
106
+ //#endregion
107
+ //#region src/components/RafflePick/RafflePickSlots.d.ts
108
+ declare function RafflePickSlots({
109
+ length,
110
+ chars,
111
+ spinInterval,
112
+ staggerMs,
113
+ className,
114
+ slotClassName,
115
+ style,
116
+ slotStyle,
117
+ onResult
118
+ }: RafflePickSlotsProps): _$react_jsx_runtime0.JSX.Element;
119
+ //#endregion
120
+ //#region src/utils/inertia.d.ts
121
+ type RafflePickPhase = 'idle' | 'starting' | 'running' | 'settling' | 'frozen';
122
+ //#endregion
123
+ //#region src/components/RafflePick/context.d.ts
124
+ interface RaffleContextValue {
125
+ phase: RafflePickPhase;
126
+ step: number;
127
+ displayed: RafflePickValue$1;
128
+ cycleInterval: number;
129
+ inertia: boolean;
130
+ hasItems: boolean;
131
+ initialIndex: number;
132
+ valueRef: RefObject<number>;
133
+ displayValue: (index: number) => RafflePickValue$1;
134
+ subscribe: (fn: (value: number) => void) => () => void;
135
+ start: () => void;
136
+ freeze: () => void;
137
+ reset: () => void;
138
+ }
139
+ declare const RaffleContext: _$react.Context<RaffleContextValue | null>;
140
+ declare const useRaffleContext: (componentName: string) => RaffleContextValue;
141
+ //#endregion
142
+ //#region src/components/RafflePick/index.d.ts
143
+ type RafflePickCompound = typeof RafflePickRoot & {
144
+ Value: typeof RafflePickValue;
145
+ Button: typeof RafflePickButton;
146
+ Countdown: typeof RafflePickCountdown;
147
+ Slots: typeof RafflePickSlots;
148
+ };
149
+ declare const RafflePick: RafflePickCompound;
150
+ //#endregion
151
+ export { type AnimationType, RaffleContext, RafflePick, RafflePickButton, type RafflePickButtonProps, RafflePickCountdown, type RafflePickCountdownProps, type RafflePickRootProps, RafflePickSlots, type RafflePickSlotsProps, RafflePickValue, type RafflePickValueProps, type RafflePickValue$1 as RafflePickValueType, useRaffleContext };