@digilogiclabs/saas-factory-ui 2.3.0 → 2.4.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.d.mts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +137 -65
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +137 -65
- package/dist/index.mjs.map +1 -1
- package/dist/web/index.d.mts +20 -3
- package/dist/web/index.d.ts +20 -3
- package/dist/web/index.js +243 -169
- package/dist/web/index.js.map +1 -1
- package/dist/web/index.mjs +186 -112
- package/dist/web/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/web/index.js
CHANGED
|
@@ -30225,7 +30225,7 @@ function TiltCard({
|
|
|
30225
30225
|
}
|
|
30226
30226
|
|
|
30227
30227
|
// src/components/ui/dice-roller/index.tsx
|
|
30228
|
-
var
|
|
30228
|
+
var import_react69 = require("react");
|
|
30229
30229
|
|
|
30230
30230
|
// src/hooks/web/use-dark-mode.ts
|
|
30231
30231
|
var import_react68 = require("react");
|
|
@@ -30274,21 +30274,6 @@ function useDarkMode(forced) {
|
|
|
30274
30274
|
return dark;
|
|
30275
30275
|
}
|
|
30276
30276
|
|
|
30277
|
-
// src/hooks/web/use-prefers-reduced-motion.ts
|
|
30278
|
-
var import_react69 = require("react");
|
|
30279
|
-
function usePrefersReducedMotion() {
|
|
30280
|
-
const [reduced, setReduced] = (0, import_react69.useState)(false);
|
|
30281
|
-
(0, import_react69.useEffect)(() => {
|
|
30282
|
-
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
30283
|
-
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
30284
|
-
setReduced(mq.matches);
|
|
30285
|
-
const read = () => setReduced(mq.matches);
|
|
30286
|
-
mq.addEventListener("change", read);
|
|
30287
|
-
return () => mq.removeEventListener("change", read);
|
|
30288
|
-
}, []);
|
|
30289
|
-
return reduced;
|
|
30290
|
-
}
|
|
30291
|
-
|
|
30292
30277
|
// src/components/ui/dice-roller/index.tsx
|
|
30293
30278
|
var import_jsx_runtime113 = require("react/jsx-runtime");
|
|
30294
30279
|
var PRESETS = {
|
|
@@ -30507,8 +30492,8 @@ function simulateDice(arenaW, arenaH, diceSize, starts, numDice) {
|
|
|
30507
30492
|
return frames;
|
|
30508
30493
|
}
|
|
30509
30494
|
function useArenaBounds(ref) {
|
|
30510
|
-
const [bounds, setBounds] = (0,
|
|
30511
|
-
(0,
|
|
30495
|
+
const [bounds, setBounds] = (0, import_react69.useState)({ w: 400, h: 260 });
|
|
30496
|
+
(0, import_react69.useEffect)(() => {
|
|
30512
30497
|
if (!ref.current) return;
|
|
30513
30498
|
const el = ref.current;
|
|
30514
30499
|
const update = () => setBounds({ w: el.offsetWidth, h: el.offsetHeight });
|
|
@@ -30563,19 +30548,18 @@ function DiceRoller({
|
|
|
30563
30548
|
}) {
|
|
30564
30549
|
const clampedCount = Math.max(1, Math.min(MAX_COUNT, count2));
|
|
30565
30550
|
const dark = useDarkMode(darkMode);
|
|
30566
|
-
const
|
|
30567
|
-
const [
|
|
30568
|
-
const [
|
|
30569
|
-
const
|
|
30570
|
-
const
|
|
30571
|
-
const
|
|
30572
|
-
const
|
|
30573
|
-
const
|
|
30574
|
-
const
|
|
30575
|
-
const
|
|
30576
|
-
const
|
|
30577
|
-
const
|
|
30578
|
-
const shadowSetters = (0, import_react70.useRef)([]);
|
|
30551
|
+
const [rolling, setRolling] = (0, import_react69.useState)(false);
|
|
30552
|
+
const [results, setResults] = (0, import_react69.useState)(null);
|
|
30553
|
+
const [history, setHistory] = (0, import_react69.useState)([]);
|
|
30554
|
+
const dieWrapperRefs = (0, import_react69.useRef)([]);
|
|
30555
|
+
const cubeRefs = (0, import_react69.useRef)([]);
|
|
30556
|
+
const shadowRefs = (0, import_react69.useRef)([]);
|
|
30557
|
+
const numeralRefs = (0, import_react69.useRef)([]);
|
|
30558
|
+
const currentPositionsRef = (0, import_react69.useRef)(null);
|
|
30559
|
+
const rollingRef = (0, import_react69.useRef)(false);
|
|
30560
|
+
const dieSetters = (0, import_react69.useRef)([]);
|
|
30561
|
+
const cubeSetters = (0, import_react69.useRef)([]);
|
|
30562
|
+
const shadowSetters = (0, import_react69.useRef)([]);
|
|
30579
30563
|
const getDieSetter = (i) => {
|
|
30580
30564
|
if (!dieSetters.current[i]) {
|
|
30581
30565
|
dieSetters.current[i] = (el) => {
|
|
@@ -30600,7 +30584,7 @@ function DiceRoller({
|
|
|
30600
30584
|
}
|
|
30601
30585
|
return shadowSetters.current[i];
|
|
30602
30586
|
};
|
|
30603
|
-
const numeralSetters = (0,
|
|
30587
|
+
const numeralSetters = (0, import_react69.useRef)([]);
|
|
30604
30588
|
const getNumeralSetter = (i) => {
|
|
30605
30589
|
if (!numeralSetters.current[i]) {
|
|
30606
30590
|
numeralSetters.current[i] = (el) => {
|
|
@@ -30609,11 +30593,11 @@ function DiceRoller({
|
|
|
30609
30593
|
}
|
|
30610
30594
|
return numeralSetters.current[i];
|
|
30611
30595
|
};
|
|
30612
|
-
const timersRef = (0,
|
|
30613
|
-
const rafHandleRef = (0,
|
|
30614
|
-
const arenaRef = (0,
|
|
30596
|
+
const timersRef = (0, import_react69.useRef)([]);
|
|
30597
|
+
const rafHandleRef = (0, import_react69.useRef)(null);
|
|
30598
|
+
const arenaRef = (0, import_react69.useRef)(null);
|
|
30615
30599
|
const arena = useArenaBounds(arenaRef);
|
|
30616
|
-
const colors = (0,
|
|
30600
|
+
const colors = (0, import_react69.useMemo)(() => {
|
|
30617
30601
|
if (typeof theme5 === "object") {
|
|
30618
30602
|
const pipL = theme5.pip;
|
|
30619
30603
|
const pipD = theme5.pipDark ?? theme5.pip;
|
|
@@ -30650,7 +30634,7 @@ function DiceRoller({
|
|
|
30650
30634
|
chipDim: dark ? "#3a4358" : "#94a3b8"
|
|
30651
30635
|
};
|
|
30652
30636
|
}, [theme5, dark]);
|
|
30653
|
-
const effectiveSize = (0,
|
|
30637
|
+
const effectiveSize = (0, import_react69.useMemo)(() => {
|
|
30654
30638
|
if (!responsive2) return size;
|
|
30655
30639
|
const needed = clampedCount * size * 1.6;
|
|
30656
30640
|
if (arena.w >= needed || arena.w === 0) return size;
|
|
@@ -30661,7 +30645,7 @@ function DiceRoller({
|
|
|
30661
30645
|
const pipDiameter = Math.round(effectiveSize * 0.2);
|
|
30662
30646
|
const faceRadius = Math.round(effectiveSize * 0.07);
|
|
30663
30647
|
const arenaHeight = arenaHeightProp ?? Math.max(effectiveSize * 3, 200);
|
|
30664
|
-
const faceTransformFor = (0,
|
|
30648
|
+
const faceTransformFor = (0, import_react69.useCallback)(
|
|
30665
30649
|
(value) => {
|
|
30666
30650
|
const p = D6_FACE_PLACEMENTS[value];
|
|
30667
30651
|
const parts = [];
|
|
@@ -30672,14 +30656,14 @@ function DiceRoller({
|
|
|
30672
30656
|
},
|
|
30673
30657
|
[half]
|
|
30674
30658
|
);
|
|
30675
|
-
const defaultPositions = (0,
|
|
30659
|
+
const defaultPositions = (0, import_react69.useCallback)(
|
|
30676
30660
|
(w, h, n) => Array.from({ length: n }, (_, i) => ({
|
|
30677
30661
|
x: (i + 1) * w / (n + 1),
|
|
30678
30662
|
y: h / 2
|
|
30679
30663
|
})),
|
|
30680
30664
|
[]
|
|
30681
30665
|
);
|
|
30682
|
-
const writeDiePosition = (0,
|
|
30666
|
+
const writeDiePosition = (0, import_react69.useCallback)(
|
|
30683
30667
|
(i, x, y, sx = 1, sy = 1) => {
|
|
30684
30668
|
const el = dieWrapperRefs.current[i];
|
|
30685
30669
|
if (!el) return;
|
|
@@ -30690,7 +30674,7 @@ function DiceRoller({
|
|
|
30690
30674
|
},
|
|
30691
30675
|
[half]
|
|
30692
30676
|
);
|
|
30693
|
-
const writeCubeRotation = (0,
|
|
30677
|
+
const writeCubeRotation = (0, import_react69.useCallback)(
|
|
30694
30678
|
(i, rx, ry, rz, withTransition, tiltZ = 0) => {
|
|
30695
30679
|
const el = cubeRefs.current[i];
|
|
30696
30680
|
if (!el) return;
|
|
@@ -30699,7 +30683,15 @@ function DiceRoller({
|
|
|
30699
30683
|
},
|
|
30700
30684
|
[]
|
|
30701
30685
|
);
|
|
30702
|
-
(0,
|
|
30686
|
+
(0, import_react69.useEffect)(() => {
|
|
30687
|
+
if (timersRef.current.length > 0) {
|
|
30688
|
+
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30689
|
+
timersRef.current = [];
|
|
30690
|
+
}
|
|
30691
|
+
if (rollingRef.current) {
|
|
30692
|
+
rollingRef.current = false;
|
|
30693
|
+
setRolling(false);
|
|
30694
|
+
}
|
|
30703
30695
|
const rawW = arenaRef.current?.offsetWidth ?? 0;
|
|
30704
30696
|
const rawH = arenaRef.current?.offsetHeight ?? 0;
|
|
30705
30697
|
const w = rawW > 20 ? rawW : arena.w > 20 ? arena.w : 400;
|
|
@@ -30732,10 +30724,10 @@ function DiceRoller({
|
|
|
30732
30724
|
defaultPositions,
|
|
30733
30725
|
half
|
|
30734
30726
|
]);
|
|
30735
|
-
(0,
|
|
30727
|
+
(0, import_react69.useEffect)(() => {
|
|
30736
30728
|
setHistory([]);
|
|
30737
30729
|
}, [sides]);
|
|
30738
|
-
const roll = (0,
|
|
30730
|
+
const roll = (0, import_react69.useCallback)(() => {
|
|
30739
30731
|
if (rollingRef.current) return;
|
|
30740
30732
|
rollingRef.current = true;
|
|
30741
30733
|
setRolling(true);
|
|
@@ -30856,25 +30848,24 @@ function DiceRoller({
|
|
|
30856
30848
|
defaultPositions,
|
|
30857
30849
|
effectiveSize,
|
|
30858
30850
|
half,
|
|
30859
|
-
reducedMotion,
|
|
30860
30851
|
onRoll,
|
|
30861
30852
|
writeCubeRotation,
|
|
30862
30853
|
writeDiePosition,
|
|
30863
30854
|
showHistory,
|
|
30864
30855
|
historyMax
|
|
30865
30856
|
]);
|
|
30866
|
-
(0,
|
|
30857
|
+
(0, import_react69.useEffect)(() => {
|
|
30867
30858
|
if (rollRef) rollRef.current = roll;
|
|
30868
30859
|
return () => {
|
|
30869
30860
|
if (rollRef && rollRef.current === roll) rollRef.current = null;
|
|
30870
30861
|
};
|
|
30871
30862
|
}, [roll, rollRef]);
|
|
30872
|
-
(0,
|
|
30863
|
+
(0, import_react69.useEffect)(() => {
|
|
30873
30864
|
if (!autoRoll) return;
|
|
30874
30865
|
const t = setTimeout(roll, 300);
|
|
30875
30866
|
return () => clearTimeout(t);
|
|
30876
30867
|
}, []);
|
|
30877
|
-
(0,
|
|
30868
|
+
(0, import_react69.useEffect)(
|
|
30878
30869
|
() => () => {
|
|
30879
30870
|
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30880
30871
|
timersRef.current = [];
|
|
@@ -31174,7 +31165,7 @@ function DiceRoller({
|
|
|
31174
31165
|
DiceRoller.displayName = "DiceRoller";
|
|
31175
31166
|
|
|
31176
31167
|
// src/components/ui/bracket-generator/index.tsx
|
|
31177
|
-
var
|
|
31168
|
+
var import_react70 = require("react");
|
|
31178
31169
|
|
|
31179
31170
|
// src/utils/array.ts
|
|
31180
31171
|
function shuffle(arr) {
|
|
@@ -31394,15 +31385,15 @@ function computeLayout(rounds, firstRoundCount) {
|
|
|
31394
31385
|
};
|
|
31395
31386
|
}
|
|
31396
31387
|
function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
31397
|
-
const [transform, setTransform] = (0,
|
|
31388
|
+
const [transform, setTransform] = (0, import_react70.useState)({
|
|
31398
31389
|
x: 0,
|
|
31399
31390
|
y: 0,
|
|
31400
31391
|
scale: 1
|
|
31401
31392
|
});
|
|
31402
|
-
const isDragging = (0,
|
|
31403
|
-
const dragStart = (0,
|
|
31404
|
-
const pinchRef = (0,
|
|
31405
|
-
const clampTransform = (0,
|
|
31393
|
+
const isDragging = (0, import_react70.useRef)(false);
|
|
31394
|
+
const dragStart = (0, import_react70.useRef)({ x: 0, y: 0 });
|
|
31395
|
+
const pinchRef = (0, import_react70.useRef)(null);
|
|
31396
|
+
const clampTransform = (0, import_react70.useCallback)(
|
|
31406
31397
|
(t, vw, vh) => {
|
|
31407
31398
|
const sw = contentSize.w * t.scale;
|
|
31408
31399
|
const sh = contentSize.h * t.scale;
|
|
@@ -31414,7 +31405,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31414
31405
|
},
|
|
31415
31406
|
[contentSize]
|
|
31416
31407
|
);
|
|
31417
|
-
(0,
|
|
31408
|
+
(0, import_react70.useEffect)(() => {
|
|
31418
31409
|
const el = viewportRef.current;
|
|
31419
31410
|
if (!el) return;
|
|
31420
31411
|
const onWheel = (e) => {
|
|
@@ -31439,7 +31430,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31439
31430
|
el.addEventListener("wheel", onWheel, { passive: false });
|
|
31440
31431
|
return () => el.removeEventListener("wheel", onWheel);
|
|
31441
31432
|
}, [viewportRef, minZoom, maxZoom, clampTransform]);
|
|
31442
|
-
const onPointerDown = (0,
|
|
31433
|
+
const onPointerDown = (0, import_react70.useCallback)(
|
|
31443
31434
|
(e) => {
|
|
31444
31435
|
if (e.target.closest("[data-no-pan]")) return;
|
|
31445
31436
|
isDragging.current = true;
|
|
@@ -31452,7 +31443,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31452
31443
|
},
|
|
31453
31444
|
[transform]
|
|
31454
31445
|
);
|
|
31455
|
-
const onPointerMove = (0,
|
|
31446
|
+
const onPointerMove = (0, import_react70.useCallback)(
|
|
31456
31447
|
(e) => {
|
|
31457
31448
|
if (!isDragging.current) return;
|
|
31458
31449
|
const el = viewportRef.current;
|
|
@@ -31472,11 +31463,11 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31472
31463
|
},
|
|
31473
31464
|
[viewportRef, clampTransform]
|
|
31474
31465
|
);
|
|
31475
|
-
const onPointerUp = (0,
|
|
31466
|
+
const onPointerUp = (0, import_react70.useCallback)((e) => {
|
|
31476
31467
|
isDragging.current = false;
|
|
31477
31468
|
e.currentTarget.style.cursor = "grab";
|
|
31478
31469
|
}, []);
|
|
31479
|
-
const onTouchStart = (0,
|
|
31470
|
+
const onTouchStart = (0, import_react70.useCallback)(
|
|
31480
31471
|
(e) => {
|
|
31481
31472
|
if (e.touches.length === 2) {
|
|
31482
31473
|
const [t1, t2] = [e.touches[0], e.touches[1]];
|
|
@@ -31496,7 +31487,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31496
31487
|
},
|
|
31497
31488
|
[transform]
|
|
31498
31489
|
);
|
|
31499
|
-
const onTouchMove = (0,
|
|
31490
|
+
const onTouchMove = (0, import_react70.useCallback)(
|
|
31500
31491
|
(e) => {
|
|
31501
31492
|
if (e.touches.length === 2 && pinchRef.current) {
|
|
31502
31493
|
e.preventDefault();
|
|
@@ -31533,10 +31524,10 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31533
31524
|
},
|
|
31534
31525
|
[viewportRef, minZoom, maxZoom, clampTransform]
|
|
31535
31526
|
);
|
|
31536
|
-
const onTouchEnd = (0,
|
|
31527
|
+
const onTouchEnd = (0, import_react70.useCallback)(() => {
|
|
31537
31528
|
pinchRef.current = null;
|
|
31538
31529
|
}, []);
|
|
31539
|
-
const zoomBy = (0,
|
|
31530
|
+
const zoomBy = (0, import_react70.useCallback)(
|
|
31540
31531
|
(factor) => {
|
|
31541
31532
|
const el = viewportRef.current;
|
|
31542
31533
|
if (!el) return;
|
|
@@ -31555,7 +31546,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31555
31546
|
},
|
|
31556
31547
|
[viewportRef, minZoom, maxZoom, clampTransform]
|
|
31557
31548
|
);
|
|
31558
|
-
const fit = (0,
|
|
31549
|
+
const fit = (0, import_react70.useCallback)(() => {
|
|
31559
31550
|
const el = viewportRef.current;
|
|
31560
31551
|
if (!el || !contentSize.w) return;
|
|
31561
31552
|
const rect = el.getBoundingClientRect();
|
|
@@ -31569,10 +31560,10 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31569
31560
|
scale
|
|
31570
31561
|
});
|
|
31571
31562
|
}, [viewportRef, contentSize, minZoom, maxZoom]);
|
|
31572
|
-
const reset = (0,
|
|
31563
|
+
const reset = (0, import_react70.useCallback)(() => {
|
|
31573
31564
|
setTransform({ x: 40, y: 40, scale: 1 });
|
|
31574
31565
|
}, []);
|
|
31575
|
-
const panTo = (0,
|
|
31566
|
+
const panTo = (0, import_react70.useCallback)(
|
|
31576
31567
|
(contentX, contentY) => {
|
|
31577
31568
|
const el = viewportRef.current;
|
|
31578
31569
|
if (!el) return;
|
|
@@ -31645,15 +31636,15 @@ function BracketGenerator({
|
|
|
31645
31636
|
ariaLabel = "Tournament bracket"
|
|
31646
31637
|
}) {
|
|
31647
31638
|
const dark = useDarkMode(darkMode);
|
|
31648
|
-
const [bracketState, setBracketState] = (0,
|
|
31639
|
+
const [bracketState, setBracketState] = (0, import_react70.useState)({
|
|
31649
31640
|
matches: [],
|
|
31650
31641
|
rounds: 0,
|
|
31651
31642
|
champion: null
|
|
31652
31643
|
});
|
|
31653
|
-
const [simulating, setSimulating] = (0,
|
|
31654
|
-
const autoRef = (0,
|
|
31655
|
-
const viewportRef = (0,
|
|
31656
|
-
const effectiveParticipants = (0,
|
|
31644
|
+
const [simulating, setSimulating] = (0, import_react70.useState)(false);
|
|
31645
|
+
const autoRef = (0, import_react70.useRef)(null);
|
|
31646
|
+
const viewportRef = (0, import_react70.useRef)(null);
|
|
31647
|
+
const effectiveParticipants = (0, import_react70.useMemo)(() => {
|
|
31657
31648
|
if (participantsProp?.length) {
|
|
31658
31649
|
return padToSize(
|
|
31659
31650
|
participantsProp.map((p, i) => ({
|
|
@@ -31672,7 +31663,7 @@ function BracketGenerator({
|
|
|
31672
31663
|
}));
|
|
31673
31664
|
}, [participantsProp, size]);
|
|
31674
31665
|
const preset = typeof theme5 === "string" ? PRESETS2[theme5] || PRESETS2.blue : null;
|
|
31675
|
-
const themeColors = (0,
|
|
31666
|
+
const themeColors = (0, import_react70.useMemo)(() => {
|
|
31676
31667
|
if (typeof theme5 === "object") return theme5;
|
|
31677
31668
|
const p = preset;
|
|
31678
31669
|
return {
|
|
@@ -31681,9 +31672,9 @@ function BracketGenerator({
|
|
|
31681
31672
|
color: p.color
|
|
31682
31673
|
};
|
|
31683
31674
|
}, [theme5, dark, preset]);
|
|
31684
|
-
const colors = (0,
|
|
31675
|
+
const colors = (0, import_react70.useMemo)(() => buildColorTokens(dark), [dark]);
|
|
31685
31676
|
const roundLabels = ROUND_NAMES[effectiveParticipants.length] || [];
|
|
31686
|
-
const layout = (0,
|
|
31677
|
+
const layout = (0, import_react70.useMemo)(() => {
|
|
31687
31678
|
if (!bracketState.rounds)
|
|
31688
31679
|
return {
|
|
31689
31680
|
positions: {},
|
|
@@ -31692,7 +31683,7 @@ function BracketGenerator({
|
|
|
31692
31683
|
};
|
|
31693
31684
|
return computeLayout(bracketState.rounds, effectiveParticipants.length / 2);
|
|
31694
31685
|
}, [bracketState.rounds, effectiveParticipants.length]);
|
|
31695
|
-
const contentSize = (0,
|
|
31686
|
+
const contentSize = (0, import_react70.useMemo)(
|
|
31696
31687
|
() => ({
|
|
31697
31688
|
w: layout.totalW + CANVAS_PAD * 2,
|
|
31698
31689
|
h: layout.totalH + CANVAS_PAD * 2
|
|
@@ -31705,10 +31696,10 @@ function BracketGenerator({
|
|
|
31705
31696
|
minZoom,
|
|
31706
31697
|
maxZoom
|
|
31707
31698
|
);
|
|
31708
|
-
const [miniMapHidden, setMiniMapHidden] = (0,
|
|
31709
|
-
const miniMapDragRef = (0,
|
|
31710
|
-
const resumeRef = (0,
|
|
31711
|
-
const hydrateFromResume = (0,
|
|
31699
|
+
const [miniMapHidden, setMiniMapHidden] = (0, import_react70.useState)(false);
|
|
31700
|
+
const miniMapDragRef = (0, import_react70.useRef)(false);
|
|
31701
|
+
const resumeRef = (0, import_react70.useRef)(resumeMatches);
|
|
31702
|
+
const hydrateFromResume = (0, import_react70.useCallback)(() => {
|
|
31712
31703
|
const resume = resumeRef.current;
|
|
31713
31704
|
if (!resume?.length) return null;
|
|
31714
31705
|
const n = effectiveParticipants.length;
|
|
@@ -31748,7 +31739,7 @@ function BracketGenerator({
|
|
|
31748
31739
|
const finalMatch = matches.find((m) => m.round === rounds - 1);
|
|
31749
31740
|
return { matches, rounds, champion: finalMatch?.winner ?? null };
|
|
31750
31741
|
}, [effectiveParticipants]);
|
|
31751
|
-
const seedBracket = (0,
|
|
31742
|
+
const seedBracket = (0, import_react70.useCallback)(() => {
|
|
31752
31743
|
const { matches, rounds } = buildBracket(
|
|
31753
31744
|
effectiveParticipants,
|
|
31754
31745
|
seedingStrategy
|
|
@@ -31771,7 +31762,7 @@ function BracketGenerator({
|
|
|
31771
31762
|
};
|
|
31772
31763
|
setBracketState(newState);
|
|
31773
31764
|
}, [effectiveParticipants, seedingStrategy]);
|
|
31774
|
-
const simulateNext = (0,
|
|
31765
|
+
const simulateNext = (0, import_react70.useCallback)(() => {
|
|
31775
31766
|
setBracketState((prev) => {
|
|
31776
31767
|
const next = prev.matches.find((m) => m.a && m.b && !m.winner);
|
|
31777
31768
|
if (!next) return prev;
|
|
@@ -31786,7 +31777,7 @@ function BracketGenerator({
|
|
|
31786
31777
|
return { ...prev, matches, champion };
|
|
31787
31778
|
});
|
|
31788
31779
|
}, []);
|
|
31789
|
-
const autoPlay = (0,
|
|
31780
|
+
const autoPlay = (0, import_react70.useCallback)(() => {
|
|
31790
31781
|
if (simulating) {
|
|
31791
31782
|
if (autoRef.current) clearTimeout(autoRef.current);
|
|
31792
31783
|
setSimulating(false);
|
|
@@ -31815,7 +31806,7 @@ function BracketGenerator({
|
|
|
31815
31806
|
};
|
|
31816
31807
|
tick();
|
|
31817
31808
|
}, [simulating, simulateDelayMs]);
|
|
31818
|
-
const advanceWinner = (0,
|
|
31809
|
+
const advanceWinner = (0, import_react70.useCallback)(
|
|
31819
31810
|
(matchId, winnerSlot) => {
|
|
31820
31811
|
setBracketState((prev) => {
|
|
31821
31812
|
const m = prev.matches.find((x) => x.id === matchId);
|
|
@@ -31838,8 +31829,8 @@ function BracketGenerator({
|
|
|
31838
31829
|
},
|
|
31839
31830
|
[]
|
|
31840
31831
|
);
|
|
31841
|
-
const prevBracketStateRef = (0,
|
|
31842
|
-
(0,
|
|
31832
|
+
const prevBracketStateRef = (0, import_react70.useRef)(bracketState);
|
|
31833
|
+
(0, import_react70.useEffect)(() => {
|
|
31843
31834
|
const prev = prevBracketStateRef.current;
|
|
31844
31835
|
const next = bracketState;
|
|
31845
31836
|
if (prev === next) return;
|
|
@@ -31858,12 +31849,12 @@ function BracketGenerator({
|
|
|
31858
31849
|
onStateChange?.(next);
|
|
31859
31850
|
prevBracketStateRef.current = next;
|
|
31860
31851
|
}, [bracketState, onMatchComplete, onChampion, onStateChange]);
|
|
31861
|
-
const structuralKey = (0,
|
|
31852
|
+
const structuralKey = (0, import_react70.useMemo)(
|
|
31862
31853
|
() => `${seedingStrategy}|${effectiveParticipants.map((p) => `${p.id}:${p.seed ?? ""}`).join(",")}`,
|
|
31863
31854
|
[effectiveParticipants, seedingStrategy]
|
|
31864
31855
|
);
|
|
31865
|
-
const seededKeyRef = (0,
|
|
31866
|
-
(0,
|
|
31856
|
+
const seededKeyRef = (0, import_react70.useRef)(null);
|
|
31857
|
+
(0, import_react70.useEffect)(() => {
|
|
31867
31858
|
if (seededKeyRef.current === structuralKey) {
|
|
31868
31859
|
setBracketState((prev) => {
|
|
31869
31860
|
if (!prev.matches.length) return prev;
|
|
@@ -31894,24 +31885,24 @@ function BracketGenerator({
|
|
|
31894
31885
|
seedBracket();
|
|
31895
31886
|
}
|
|
31896
31887
|
}, [structuralKey, effectiveParticipants, hydrateFromResume, seedBracket]);
|
|
31897
|
-
(0,
|
|
31888
|
+
(0, import_react70.useEffect)(() => {
|
|
31898
31889
|
return () => {
|
|
31899
31890
|
if (autoRef.current) clearTimeout(autoRef.current);
|
|
31900
31891
|
};
|
|
31901
31892
|
}, []);
|
|
31902
|
-
(0,
|
|
31893
|
+
(0, import_react70.useLayoutEffect)(() => {
|
|
31903
31894
|
if (contentSize.w > 0) {
|
|
31904
31895
|
const timer = setTimeout(fit, 50);
|
|
31905
31896
|
return () => clearTimeout(timer);
|
|
31906
31897
|
}
|
|
31907
31898
|
}, [contentSize.w]);
|
|
31908
|
-
(0,
|
|
31899
|
+
(0, import_react70.useEffect)(() => {
|
|
31909
31900
|
if (autoSimulate && bracketState.matches.length && !bracketState.champion) {
|
|
31910
31901
|
const timer = setTimeout(autoPlay, 500);
|
|
31911
31902
|
return () => clearTimeout(timer);
|
|
31912
31903
|
}
|
|
31913
31904
|
}, [autoSimulate]);
|
|
31914
|
-
const stats = (0,
|
|
31905
|
+
const stats = (0, import_react70.useMemo)(() => {
|
|
31915
31906
|
const done = bracketState.matches.filter((m) => m.winner).length;
|
|
31916
31907
|
const total = bracketState.matches.length;
|
|
31917
31908
|
const remaining = bracketState.matches.filter(
|
|
@@ -31919,7 +31910,7 @@ function BracketGenerator({
|
|
|
31919
31910
|
).length;
|
|
31920
31911
|
return { done, total, remaining };
|
|
31921
31912
|
}, [bracketState]);
|
|
31922
|
-
const connectorPaths = (0,
|
|
31913
|
+
const connectorPaths = (0, import_react70.useMemo)(() => {
|
|
31923
31914
|
const paths = [];
|
|
31924
31915
|
bracketState.matches.forEach((m) => {
|
|
31925
31916
|
if (m.round >= bracketState.rounds - 1) return;
|
|
@@ -32624,7 +32615,7 @@ function BracketGenerator({
|
|
|
32624
32615
|
}
|
|
32625
32616
|
|
|
32626
32617
|
// src/components/ui/coin-flipper/index.tsx
|
|
32627
|
-
var
|
|
32618
|
+
var import_react71 = require("react");
|
|
32628
32619
|
var import_jsx_runtime115 = require("react/jsx-runtime");
|
|
32629
32620
|
var PRESETS3 = {
|
|
32630
32621
|
gold: {
|
|
@@ -32808,15 +32799,15 @@ function CoinFlipper({
|
|
|
32808
32799
|
}) {
|
|
32809
32800
|
const dark = useDarkMode(darkMode);
|
|
32810
32801
|
const tc = typeof theme5 === "string" ? PRESETS3[theme5] || PRESETS3.gold : theme5;
|
|
32811
|
-
const [result, setResult] = (0,
|
|
32812
|
-
const [flipping, setFlipping] = (0,
|
|
32813
|
-
const [history, setHistory] = (0,
|
|
32814
|
-
const [stats, setStats] = (0,
|
|
32815
|
-
const flipIdRef = (0,
|
|
32816
|
-
const coinRef = (0,
|
|
32817
|
-
const shadowRef = (0,
|
|
32818
|
-
const timersRef = (0,
|
|
32819
|
-
const colors = (0,
|
|
32802
|
+
const [result, setResult] = (0, import_react71.useState)(null);
|
|
32803
|
+
const [flipping, setFlipping] = (0, import_react71.useState)(false);
|
|
32804
|
+
const [history, setHistory] = (0, import_react71.useState)([]);
|
|
32805
|
+
const [stats, setStats] = (0, import_react71.useState)({ heads: 0, tails: 0 });
|
|
32806
|
+
const flipIdRef = (0, import_react71.useRef)(0);
|
|
32807
|
+
const coinRef = (0, import_react71.useRef)(null);
|
|
32808
|
+
const shadowRef = (0, import_react71.useRef)(null);
|
|
32809
|
+
const timersRef = (0, import_react71.useRef)([]);
|
|
32810
|
+
const colors = (0, import_react71.useMemo)(
|
|
32820
32811
|
() => ({
|
|
32821
32812
|
bg: dark ? "#0f1117" : "#f8fafc",
|
|
32822
32813
|
surface: dark ? "#1a1d27" : "#ffffff",
|
|
@@ -32827,7 +32818,7 @@ function CoinFlipper({
|
|
|
32827
32818
|
}),
|
|
32828
32819
|
[dark]
|
|
32829
32820
|
);
|
|
32830
|
-
const flip = (0,
|
|
32821
|
+
const flip = (0, import_react71.useCallback)(() => {
|
|
32831
32822
|
if (flipping) return;
|
|
32832
32823
|
setFlipping(true);
|
|
32833
32824
|
const outcome = Math.random() < 0.5 ? "heads" : "tails";
|
|
@@ -32867,16 +32858,19 @@ function CoinFlipper({
|
|
|
32867
32858
|
}, frames.length * stepMs);
|
|
32868
32859
|
timersRef.current.push(settleTimer);
|
|
32869
32860
|
}, [flipping, onFlip, historyMax]);
|
|
32870
|
-
(0,
|
|
32861
|
+
(0, import_react71.useEffect)(() => {
|
|
32871
32862
|
if (flipRef) flipRef.current = flip;
|
|
32863
|
+
return () => {
|
|
32864
|
+
if (flipRef && flipRef.current === flip) flipRef.current = null;
|
|
32865
|
+
};
|
|
32872
32866
|
}, [flip, flipRef]);
|
|
32873
|
-
(0,
|
|
32867
|
+
(0, import_react71.useEffect)(() => {
|
|
32874
32868
|
if (autoFlip) {
|
|
32875
32869
|
const timer = setTimeout(flip, 300);
|
|
32876
32870
|
return () => clearTimeout(timer);
|
|
32877
32871
|
}
|
|
32878
32872
|
}, []);
|
|
32879
|
-
(0,
|
|
32873
|
+
(0, import_react71.useEffect)(() => {
|
|
32880
32874
|
return () => {
|
|
32881
32875
|
timersRef.current.forEach(clearTimeout);
|
|
32882
32876
|
};
|
|
@@ -33313,6 +33307,23 @@ function CoinFlipper({
|
|
|
33313
33307
|
|
|
33314
33308
|
// src/components/ui/random-player-picker/index.tsx
|
|
33315
33309
|
var import_react73 = require("react");
|
|
33310
|
+
|
|
33311
|
+
// src/hooks/web/use-prefers-reduced-motion.ts
|
|
33312
|
+
var import_react72 = require("react");
|
|
33313
|
+
function usePrefersReducedMotion() {
|
|
33314
|
+
const [reduced, setReduced] = (0, import_react72.useState)(false);
|
|
33315
|
+
(0, import_react72.useEffect)(() => {
|
|
33316
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
33317
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
33318
|
+
setReduced(mq.matches);
|
|
33319
|
+
const read = () => setReduced(mq.matches);
|
|
33320
|
+
mq.addEventListener("change", read);
|
|
33321
|
+
return () => mq.removeEventListener("change", read);
|
|
33322
|
+
}, []);
|
|
33323
|
+
return reduced;
|
|
33324
|
+
}
|
|
33325
|
+
|
|
33326
|
+
// src/components/ui/random-player-picker/index.tsx
|
|
33316
33327
|
var import_jsx_runtime116 = require("react/jsx-runtime");
|
|
33317
33328
|
var PRESETS4 = {
|
|
33318
33329
|
blue: {
|
|
@@ -33760,6 +33771,8 @@ function RandomPlayerPicker({
|
|
|
33760
33771
|
const particleTimer = (0, import_react73.useRef)(null);
|
|
33761
33772
|
const popTimer = (0, import_react73.useRef)(null);
|
|
33762
33773
|
const tickInterval = (0, import_react73.useRef)(null);
|
|
33774
|
+
const pendingPopIdxRef = (0, import_react73.useRef)(null);
|
|
33775
|
+
const removeWinnersRef = (0, import_react73.useRef)(removeWinners);
|
|
33763
33776
|
const tickAudioRef = (0, import_react73.useRef)(null);
|
|
33764
33777
|
const winAudioRef = (0, import_react73.useRef)(null);
|
|
33765
33778
|
const containerRef = (0, import_react73.useRef)(null);
|
|
@@ -33798,10 +33811,27 @@ function RandomPlayerPicker({
|
|
|
33798
33811
|
winAudioRef.current = null;
|
|
33799
33812
|
};
|
|
33800
33813
|
}, [winSoundUrl, soundVolume]);
|
|
33814
|
+
(0, import_react73.useEffect)(() => {
|
|
33815
|
+
removeWinnersRef.current = removeWinners;
|
|
33816
|
+
}, [removeWinners]);
|
|
33801
33817
|
(0, import_react73.useEffect)(() => {
|
|
33802
33818
|
const ids = participants.map((p) => p.id).join("|");
|
|
33803
33819
|
const structuralChange = ids !== prevIdsRef.current;
|
|
33804
33820
|
if (structuralChange) {
|
|
33821
|
+
if (winnerTimer.current) {
|
|
33822
|
+
clearTimeout(winnerTimer.current);
|
|
33823
|
+
winnerTimer.current = null;
|
|
33824
|
+
}
|
|
33825
|
+
if (tickInterval.current) {
|
|
33826
|
+
clearTimeout(tickInterval.current);
|
|
33827
|
+
tickInterval.current = null;
|
|
33828
|
+
}
|
|
33829
|
+
if (popTimer.current) {
|
|
33830
|
+
clearTimeout(popTimer.current);
|
|
33831
|
+
popTimer.current = null;
|
|
33832
|
+
}
|
|
33833
|
+
pendingPopIdxRef.current = null;
|
|
33834
|
+
setSpinning(false);
|
|
33805
33835
|
setPool(participants);
|
|
33806
33836
|
setHistory([]);
|
|
33807
33837
|
setWinner(null);
|
|
@@ -33858,33 +33888,50 @@ function RandomPlayerPicker({
|
|
|
33858
33888
|
[dark]
|
|
33859
33889
|
);
|
|
33860
33890
|
const spin = (0, import_react73.useCallback)(() => {
|
|
33861
|
-
if (spinning
|
|
33891
|
+
if (spinning) return;
|
|
33892
|
+
let activePool = pool;
|
|
33893
|
+
if (popTimer.current) {
|
|
33894
|
+
clearTimeout(popTimer.current);
|
|
33895
|
+
popTimer.current = null;
|
|
33896
|
+
const pendingIdx = pendingPopIdxRef.current;
|
|
33897
|
+
pendingPopIdxRef.current = null;
|
|
33898
|
+
if (pendingIdx != null && pendingIdx >= 0 && pendingIdx < pool.length && removeWinnersRef.current) {
|
|
33899
|
+
activePool = pool.filter((_, i) => i !== pendingIdx);
|
|
33900
|
+
setPool(activePool);
|
|
33901
|
+
setWinner(null);
|
|
33902
|
+
}
|
|
33903
|
+
}
|
|
33904
|
+
const activeN = activePool.length;
|
|
33905
|
+
if (activeN < 2) return;
|
|
33906
|
+
const activeAnglePerWedge = 2 * Math.PI / activeN;
|
|
33907
|
+
const activeRotation = rotation;
|
|
33908
|
+
const activeReelY = reelY;
|
|
33862
33909
|
onSpinStart?.();
|
|
33863
|
-
const winnerIdx = weightedIndex(
|
|
33910
|
+
const winnerIdx = weightedIndex(activePool);
|
|
33864
33911
|
const minRev = minRevolutions + intensityCfg.revsBoost;
|
|
33865
33912
|
const maxRev = maxRevolutions + intensityCfg.revsBoost;
|
|
33866
33913
|
const minFullRevs = Math.ceil(minRev);
|
|
33867
33914
|
const maxFullRevs = Math.max(minFullRevs, Math.floor(maxRev));
|
|
33868
33915
|
const revolutions = minFullRevs + Math.floor(Math.random() * (maxFullRevs - minFullRevs + 1));
|
|
33869
|
-
const wedgeMidRad = winnerIdx *
|
|
33916
|
+
const wedgeMidRad = winnerIdx * activeAnglePerWedge + activeAnglePerWedge / 2;
|
|
33870
33917
|
const wedgeMidDeg = wedgeMidRad * 180 / Math.PI;
|
|
33871
|
-
const wheelWobble = (Math.random() - 0.5) * (
|
|
33872
|
-
const currentMod = (
|
|
33918
|
+
const wheelWobble = (Math.random() - 0.5) * (activeAnglePerWedge * 180 / Math.PI) * 0.6;
|
|
33919
|
+
const currentMod = (activeRotation % 360 + 360) % 360;
|
|
33873
33920
|
const targetMod = ((-wedgeMidDeg + wheelWobble) % 360 + 360) % 360;
|
|
33874
33921
|
let deltaMod = targetMod - currentMod;
|
|
33875
33922
|
if (deltaMod < 0) deltaMod += 360;
|
|
33876
|
-
const finalRotation =
|
|
33923
|
+
const finalRotation = activeRotation + deltaMod + revolutions * 360;
|
|
33877
33924
|
const centerOffsetRows = (reelVisibleRows - 1) / 2;
|
|
33878
33925
|
const centerOffsetPx = centerOffsetRows * reelRowHeight;
|
|
33879
33926
|
const currentCenterRow = Math.round(
|
|
33880
|
-
(
|
|
33927
|
+
(activeReelY + centerOffsetPx) / reelRowHeight
|
|
33881
33928
|
);
|
|
33882
|
-
const currentCenterMod = mod(currentCenterRow,
|
|
33883
|
-
const targetRowOffset = (winnerIdx - currentCenterMod +
|
|
33884
|
-
const reelRevRows = Math.round(revolutions *
|
|
33885
|
-
const finalReelY =
|
|
33886
|
-
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight,
|
|
33887
|
-
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx <
|
|
33929
|
+
const currentCenterMod = mod(currentCenterRow, activeN);
|
|
33930
|
+
const targetRowOffset = (winnerIdx - currentCenterMod + activeN) % activeN;
|
|
33931
|
+
const reelRevRows = Math.round(revolutions * activeN);
|
|
33932
|
+
const finalReelY = activeReelY + (reelRevRows + targetRowOffset) * reelRowHeight;
|
|
33933
|
+
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight, activeN) : wheelIndexAtPointer(finalRotation, activeN);
|
|
33934
|
+
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx < activePool.length ? settledWinnerIdx : winnerIdx;
|
|
33888
33935
|
const effectiveDuration = reducedMotion ? 250 : Math.round(spinDuration * intensityCfg.durationMult);
|
|
33889
33936
|
setSpinning(true);
|
|
33890
33937
|
setWinner(null);
|
|
@@ -33897,7 +33944,7 @@ function RandomPlayerPicker({
|
|
|
33897
33944
|
if ((onTick || tickAudioRef.current) && !reducedMotion) {
|
|
33898
33945
|
const wedges = mode === "reel" ? Math.max(1, reelRevRows + targetRowOffset) : (() => {
|
|
33899
33946
|
const totalDelta = deltaMod + revolutions * 360;
|
|
33900
|
-
const wedgeDeg =
|
|
33947
|
+
const wedgeDeg = activeAnglePerWedge * 180 / Math.PI;
|
|
33901
33948
|
return Math.max(
|
|
33902
33949
|
1,
|
|
33903
33950
|
Math.round(totalDelta / Math.max(wedgeDeg, 1))
|
|
@@ -33929,7 +33976,7 @@ function RandomPlayerPicker({
|
|
|
33929
33976
|
schedule();
|
|
33930
33977
|
}
|
|
33931
33978
|
winnerTimer.current = setTimeout(() => {
|
|
33932
|
-
const picked =
|
|
33979
|
+
const picked = activePool[finalWinnerIdx];
|
|
33933
33980
|
if (!picked) {
|
|
33934
33981
|
setSpinning(false);
|
|
33935
33982
|
return;
|
|
@@ -33975,7 +34022,11 @@ function RandomPlayerPicker({
|
|
|
33975
34022
|
particleTimer.current = setTimeout(() => setParticles([]), 2400);
|
|
33976
34023
|
}
|
|
33977
34024
|
if (removeWinners) {
|
|
34025
|
+
pendingPopIdxRef.current = finalWinnerIdx;
|
|
33978
34026
|
popTimer.current = setTimeout(() => {
|
|
34027
|
+
popTimer.current = null;
|
|
34028
|
+
pendingPopIdxRef.current = null;
|
|
34029
|
+
if (!removeWinnersRef.current) return;
|
|
33979
34030
|
setPool((p) => p.filter((_, i) => i !== finalWinnerIdx));
|
|
33980
34031
|
setWinner(null);
|
|
33981
34032
|
setRotation(0);
|
|
@@ -33986,8 +34037,6 @@ function RandomPlayerPicker({
|
|
|
33986
34037
|
}, [
|
|
33987
34038
|
pool,
|
|
33988
34039
|
spinning,
|
|
33989
|
-
n,
|
|
33990
|
-
anglePerWedge,
|
|
33991
34040
|
rotation,
|
|
33992
34041
|
reelY,
|
|
33993
34042
|
mode,
|
|
@@ -34023,6 +34072,7 @@ function RandomPlayerPicker({
|
|
|
34023
34072
|
[]
|
|
34024
34073
|
);
|
|
34025
34074
|
(0, import_react73.useEffect)(() => {
|
|
34075
|
+
if (trigger === "external") return;
|
|
34026
34076
|
const el = containerRef.current;
|
|
34027
34077
|
if (!el) return;
|
|
34028
34078
|
const h = (e) => {
|
|
@@ -34033,8 +34083,22 @@ function RandomPlayerPicker({
|
|
|
34033
34083
|
};
|
|
34034
34084
|
el.addEventListener("keydown", h);
|
|
34035
34085
|
return () => el.removeEventListener("keydown", h);
|
|
34036
|
-
}, [spin]);
|
|
34086
|
+
}, [spin, trigger]);
|
|
34037
34087
|
const reset = (0, import_react73.useCallback)(() => {
|
|
34088
|
+
if (winnerTimer.current) {
|
|
34089
|
+
clearTimeout(winnerTimer.current);
|
|
34090
|
+
winnerTimer.current = null;
|
|
34091
|
+
}
|
|
34092
|
+
if (tickInterval.current) {
|
|
34093
|
+
clearTimeout(tickInterval.current);
|
|
34094
|
+
tickInterval.current = null;
|
|
34095
|
+
}
|
|
34096
|
+
if (popTimer.current) {
|
|
34097
|
+
clearTimeout(popTimer.current);
|
|
34098
|
+
popTimer.current = null;
|
|
34099
|
+
}
|
|
34100
|
+
pendingPopIdxRef.current = null;
|
|
34101
|
+
setSpinning(false);
|
|
34038
34102
|
setPool(participants);
|
|
34039
34103
|
setHistory([]);
|
|
34040
34104
|
setWinner(null);
|
|
@@ -38487,27 +38551,28 @@ function GameTimer({
|
|
|
38487
38551
|
const now = performance.now();
|
|
38488
38552
|
const delta = now - lastTickRef.current;
|
|
38489
38553
|
lastTickRef.current = now;
|
|
38490
|
-
|
|
38491
|
-
|
|
38492
|
-
|
|
38493
|
-
|
|
38494
|
-
|
|
38495
|
-
|
|
38496
|
-
|
|
38554
|
+
const next = elapsedRef.current + delta;
|
|
38555
|
+
if (mode === "countdown" && next >= durationMs) {
|
|
38556
|
+
elapsedRef.current = durationMs;
|
|
38557
|
+
setElapsedMs(durationMs);
|
|
38558
|
+
setRunning(false);
|
|
38559
|
+
setCompleted(true);
|
|
38560
|
+
onComplete?.();
|
|
38561
|
+
return;
|
|
38562
|
+
}
|
|
38563
|
+
if (mode === "countdown") {
|
|
38564
|
+
const secLeft = Math.ceil((durationMs - next) / 1e3);
|
|
38565
|
+
if (secLeft <= warningAt && !warningFiredRef.current) {
|
|
38566
|
+
warningFiredRef.current = true;
|
|
38567
|
+
onWarning?.();
|
|
38497
38568
|
}
|
|
38498
|
-
if (
|
|
38499
|
-
|
|
38500
|
-
|
|
38501
|
-
warningFiredRef.current = true;
|
|
38502
|
-
onWarning?.();
|
|
38503
|
-
}
|
|
38504
|
-
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38505
|
-
dangerFiredRef.current = true;
|
|
38506
|
-
onDanger?.();
|
|
38507
|
-
}
|
|
38569
|
+
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38570
|
+
dangerFiredRef.current = true;
|
|
38571
|
+
onDanger?.();
|
|
38508
38572
|
}
|
|
38509
|
-
|
|
38510
|
-
|
|
38573
|
+
}
|
|
38574
|
+
elapsedRef.current = next;
|
|
38575
|
+
setElapsedMs(next);
|
|
38511
38576
|
rafRef.current = requestAnimationFrame(tick);
|
|
38512
38577
|
}, [mode, durationMs, warningAt, dangerAt, onComplete, onWarning, onDanger]);
|
|
38513
38578
|
(0, import_react76.useEffect)(() => {
|
|
@@ -38528,6 +38593,7 @@ function GameTimer({
|
|
|
38528
38593
|
}, []);
|
|
38529
38594
|
const reset = (0, import_react76.useCallback)(() => {
|
|
38530
38595
|
setRunning(false);
|
|
38596
|
+
elapsedRef.current = 0;
|
|
38531
38597
|
setElapsedMs(0);
|
|
38532
38598
|
setCompleted(false);
|
|
38533
38599
|
setLaps([]);
|
|
@@ -40467,6 +40533,8 @@ function RoundRobinScheduler({
|
|
|
40467
40533
|
theme: theme5 = "slate",
|
|
40468
40534
|
darkMode,
|
|
40469
40535
|
minTeams = 3,
|
|
40536
|
+
maxTeams,
|
|
40537
|
+
nameMaxLength,
|
|
40470
40538
|
defaultTeams = [],
|
|
40471
40539
|
resumeRounds,
|
|
40472
40540
|
onTeamsChange,
|
|
@@ -40489,39 +40557,41 @@ function RoundRobinScheduler({
|
|
|
40489
40557
|
(0, import_react79.useEffect)(() => {
|
|
40490
40558
|
onTeamsChange?.(teams);
|
|
40491
40559
|
}, [teams, onTeamsChange]);
|
|
40492
|
-
const
|
|
40493
|
-
|
|
40494
|
-
if (names.length === 0) return;
|
|
40495
|
-
setTeams((prev) => {
|
|
40560
|
+
const mergeNames = (0, import_react79.useCallback)(
|
|
40561
|
+
(prev, incoming) => {
|
|
40496
40562
|
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40497
40563
|
const next = [...prev];
|
|
40498
|
-
for (const
|
|
40499
|
-
if (
|
|
40500
|
-
|
|
40501
|
-
next.push(name);
|
|
40502
|
-
}
|
|
40503
|
-
}
|
|
40504
|
-
return next;
|
|
40505
|
-
});
|
|
40506
|
-
setInput("");
|
|
40507
|
-
setRounds([]);
|
|
40508
|
-
}, []);
|
|
40509
|
-
const importTeams = (0, import_react79.useCallback)((incoming) => {
|
|
40510
|
-
if (incoming.length === 0) return;
|
|
40511
|
-
setTeams((prev) => {
|
|
40512
|
-
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40513
|
-
const next = [...prev];
|
|
40514
|
-
for (const name of incoming) {
|
|
40564
|
+
for (const rawName of incoming) {
|
|
40565
|
+
if (maxTeams != null && next.length >= maxTeams) break;
|
|
40566
|
+
const name = nameMaxLength != null ? rawName.slice(0, nameMaxLength) : rawName;
|
|
40515
40567
|
const key = name.toLowerCase();
|
|
40516
|
-
if (!existing.has(key)) {
|
|
40568
|
+
if (name.length > 0 && !existing.has(key)) {
|
|
40517
40569
|
existing.add(key);
|
|
40518
40570
|
next.push(name);
|
|
40519
40571
|
}
|
|
40520
40572
|
}
|
|
40521
40573
|
return next;
|
|
40522
|
-
}
|
|
40523
|
-
|
|
40524
|
-
|
|
40574
|
+
},
|
|
40575
|
+
[maxTeams, nameMaxLength]
|
|
40576
|
+
);
|
|
40577
|
+
const addTeams = (0, import_react79.useCallback)(
|
|
40578
|
+
(raw) => {
|
|
40579
|
+
const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
40580
|
+
if (names.length === 0) return;
|
|
40581
|
+
setTeams((prev) => mergeNames(prev, names));
|
|
40582
|
+
setInput("");
|
|
40583
|
+
setRounds([]);
|
|
40584
|
+
},
|
|
40585
|
+
[mergeNames]
|
|
40586
|
+
);
|
|
40587
|
+
const importTeams = (0, import_react79.useCallback)(
|
|
40588
|
+
(incoming) => {
|
|
40589
|
+
if (incoming.length === 0) return;
|
|
40590
|
+
setTeams((prev) => mergeNames(prev, incoming));
|
|
40591
|
+
setRounds([]);
|
|
40592
|
+
},
|
|
40593
|
+
[mergeNames]
|
|
40594
|
+
);
|
|
40525
40595
|
const handleKeyDown = (0, import_react79.useCallback)(
|
|
40526
40596
|
(e) => {
|
|
40527
40597
|
if (e.key === "Enter") {
|
|
@@ -41010,6 +41080,8 @@ function Scoreboard({
|
|
|
41010
41080
|
onTeamsChange,
|
|
41011
41081
|
onRoundAdvance,
|
|
41012
41082
|
onNewGame,
|
|
41083
|
+
onReset,
|
|
41084
|
+
nameMaxLength,
|
|
41013
41085
|
labels,
|
|
41014
41086
|
ariaLabel = "Scoreboard",
|
|
41015
41087
|
className
|
|
@@ -41084,7 +41156,8 @@ function Scoreboard({
|
|
|
41084
41156
|
setRound(1);
|
|
41085
41157
|
setHistory([]);
|
|
41086
41158
|
setHistoryOpen(false);
|
|
41087
|
-
|
|
41159
|
+
onReset?.();
|
|
41160
|
+
}, [onReset]);
|
|
41088
41161
|
const newGame = (0, import_react80.useCallback)(() => {
|
|
41089
41162
|
setTeams(createDefaultTeams(seedCount, L.teamNamePrefix));
|
|
41090
41163
|
setRound(1);
|
|
@@ -41306,6 +41379,7 @@ function Scoreboard({
|
|
|
41306
41379
|
{
|
|
41307
41380
|
type: "text",
|
|
41308
41381
|
value: team.name,
|
|
41382
|
+
maxLength: nameMaxLength,
|
|
41309
41383
|
onChange: (e) => updateName(index, e.target.value),
|
|
41310
41384
|
style: nameInputStyle,
|
|
41311
41385
|
"aria-label": `Team ${index + 1} name`
|