@digilogiclabs/saas-factory-ui 2.2.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 +62 -6
- package/dist/index.d.ts +62 -6
- package/dist/index.js +300 -99
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +300 -99
- package/dist/index.mjs.map +1 -1
- package/dist/web/index.d.mts +62 -6
- package/dist/web/index.d.ts +62 -6
- package/dist/web/index.js +402 -199
- package/dist/web/index.js.map +1 -1
- package/dist/web/index.mjs +348 -145
- package/dist/web/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/web/index.mjs
CHANGED
|
@@ -30226,10 +30226,10 @@ function TiltCard({
|
|
|
30226
30226
|
// src/components/ui/dice-roller/index.tsx
|
|
30227
30227
|
import {
|
|
30228
30228
|
useCallback as useCallback41,
|
|
30229
|
-
useEffect as
|
|
30229
|
+
useEffect as useEffect51,
|
|
30230
30230
|
useMemo as useMemo26,
|
|
30231
30231
|
useRef as useRef40,
|
|
30232
|
-
useState as
|
|
30232
|
+
useState as useState66
|
|
30233
30233
|
} from "react";
|
|
30234
30234
|
|
|
30235
30235
|
// src/hooks/web/use-dark-mode.ts
|
|
@@ -30279,21 +30279,6 @@ function useDarkMode(forced) {
|
|
|
30279
30279
|
return dark;
|
|
30280
30280
|
}
|
|
30281
30281
|
|
|
30282
|
-
// src/hooks/web/use-prefers-reduced-motion.ts
|
|
30283
|
-
import { useEffect as useEffect51, useState as useState66 } from "react";
|
|
30284
|
-
function usePrefersReducedMotion() {
|
|
30285
|
-
const [reduced, setReduced] = useState66(false);
|
|
30286
|
-
useEffect51(() => {
|
|
30287
|
-
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
30288
|
-
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
30289
|
-
setReduced(mq.matches);
|
|
30290
|
-
const read = () => setReduced(mq.matches);
|
|
30291
|
-
mq.addEventListener("change", read);
|
|
30292
|
-
return () => mq.removeEventListener("change", read);
|
|
30293
|
-
}, []);
|
|
30294
|
-
return reduced;
|
|
30295
|
-
}
|
|
30296
|
-
|
|
30297
30282
|
// src/components/ui/dice-roller/index.tsx
|
|
30298
30283
|
import { Fragment as Fragment30, jsx as jsx113, jsxs as jsxs86 } from "react/jsx-runtime";
|
|
30299
30284
|
var PRESETS = {
|
|
@@ -30366,14 +30351,35 @@ var PIP_POS = {
|
|
|
30366
30351
|
[75, 75]
|
|
30367
30352
|
]
|
|
30368
30353
|
};
|
|
30369
|
-
var
|
|
30354
|
+
var D6_FACE_PLACEMENTS = {
|
|
30370
30355
|
1: { x: 0, y: 0 },
|
|
30371
|
-
2: { x: 0, y:
|
|
30372
|
-
3: { x:
|
|
30373
|
-
4: { x:
|
|
30374
|
-
5: { x:
|
|
30375
|
-
6: { x:
|
|
30356
|
+
2: { x: 0, y: 90 },
|
|
30357
|
+
3: { x: 90, y: 0 },
|
|
30358
|
+
4: { x: -90, y: 0 },
|
|
30359
|
+
5: { x: 0, y: -90 },
|
|
30360
|
+
6: { x: 0, y: 180 }
|
|
30361
|
+
};
|
|
30362
|
+
function d6LandingRotation(value) {
|
|
30363
|
+
const p = D6_FACE_PLACEMENTS[value];
|
|
30364
|
+
return {
|
|
30365
|
+
x: Math.abs(p.x) === 180 ? 180 : -p.x || 0,
|
|
30366
|
+
y: Math.abs(p.y) === 180 ? 180 : -p.y || 0
|
|
30367
|
+
};
|
|
30368
|
+
}
|
|
30369
|
+
var POLY_SHAPES = {
|
|
30370
|
+
4: { points: "50,8 93,86 7,86", textY: 62, fontScale: 0.3 },
|
|
30371
|
+
8: { points: "50,4 96,50 50,96 4,50", textY: 51, fontScale: 0.33 },
|
|
30372
|
+
10: { points: "50,4 93,44 50,96 7,44", textY: 47, fontScale: 0.3 },
|
|
30373
|
+
12: { points: "50,4 95,37 78,93 22,93 5,37", textY: 54, fontScale: 0.33 },
|
|
30374
|
+
20: {
|
|
30375
|
+
points: "50,3 91,26 91,74 50,97 9,74 9,26",
|
|
30376
|
+
textY: 51,
|
|
30377
|
+
fontScale: 0.33
|
|
30378
|
+
}
|
|
30376
30379
|
};
|
|
30380
|
+
function formatDieValue(v, sides) {
|
|
30381
|
+
return sides > 8 && (v === 6 || v === 9) ? `${v}.` : String(v);
|
|
30382
|
+
}
|
|
30377
30383
|
var MAX_COUNT = 6;
|
|
30378
30384
|
var TUMBLE_MS = 950;
|
|
30379
30385
|
var SETTLE_MS = 1100;
|
|
@@ -30491,8 +30497,8 @@ function simulateDice(arenaW, arenaH, diceSize, starts, numDice) {
|
|
|
30491
30497
|
return frames;
|
|
30492
30498
|
}
|
|
30493
30499
|
function useArenaBounds(ref) {
|
|
30494
|
-
const [bounds, setBounds] =
|
|
30495
|
-
|
|
30500
|
+
const [bounds, setBounds] = useState66({ w: 400, h: 260 });
|
|
30501
|
+
useEffect51(() => {
|
|
30496
30502
|
if (!ref.current) return;
|
|
30497
30503
|
const el = ref.current;
|
|
30498
30504
|
const update = () => setBounds({ w: el.offsetWidth, h: el.offsetHeight });
|
|
@@ -30525,6 +30531,7 @@ function Face({ value, pipColor, pipShadow, pipDiameter }) {
|
|
|
30525
30531
|
}
|
|
30526
30532
|
function DiceRoller({
|
|
30527
30533
|
count: count2 = 2,
|
|
30534
|
+
sides = 6,
|
|
30528
30535
|
theme: theme5 = "red",
|
|
30529
30536
|
darkMode,
|
|
30530
30537
|
size = 80,
|
|
@@ -30546,13 +30553,13 @@ function DiceRoller({
|
|
|
30546
30553
|
}) {
|
|
30547
30554
|
const clampedCount = Math.max(1, Math.min(MAX_COUNT, count2));
|
|
30548
30555
|
const dark = useDarkMode(darkMode);
|
|
30549
|
-
const
|
|
30550
|
-
const [
|
|
30551
|
-
const [
|
|
30552
|
-
const [history, setHistory] = useState67([]);
|
|
30556
|
+
const [rolling, setRolling] = useState66(false);
|
|
30557
|
+
const [results, setResults] = useState66(null);
|
|
30558
|
+
const [history, setHistory] = useState66([]);
|
|
30553
30559
|
const dieWrapperRefs = useRef40([]);
|
|
30554
30560
|
const cubeRefs = useRef40([]);
|
|
30555
30561
|
const shadowRefs = useRef40([]);
|
|
30562
|
+
const numeralRefs = useRef40([]);
|
|
30556
30563
|
const currentPositionsRef = useRef40(null);
|
|
30557
30564
|
const rollingRef = useRef40(false);
|
|
30558
30565
|
const dieSetters = useRef40([]);
|
|
@@ -30582,6 +30589,15 @@ function DiceRoller({
|
|
|
30582
30589
|
}
|
|
30583
30590
|
return shadowSetters.current[i];
|
|
30584
30591
|
};
|
|
30592
|
+
const numeralSetters = useRef40([]);
|
|
30593
|
+
const getNumeralSetter = (i) => {
|
|
30594
|
+
if (!numeralSetters.current[i]) {
|
|
30595
|
+
numeralSetters.current[i] = (el) => {
|
|
30596
|
+
numeralRefs.current[i] = el;
|
|
30597
|
+
};
|
|
30598
|
+
}
|
|
30599
|
+
return numeralSetters.current[i];
|
|
30600
|
+
};
|
|
30585
30601
|
const timersRef = useRef40([]);
|
|
30586
30602
|
const rafHandleRef = useRef40(null);
|
|
30587
30603
|
const arenaRef = useRef40(null);
|
|
@@ -30634,15 +30650,15 @@ function DiceRoller({
|
|
|
30634
30650
|
const pipDiameter = Math.round(effectiveSize * 0.2);
|
|
30635
30651
|
const faceRadius = Math.round(effectiveSize * 0.07);
|
|
30636
30652
|
const arenaHeight = arenaHeightProp ?? Math.max(effectiveSize * 3, 200);
|
|
30637
|
-
const
|
|
30638
|
-
() =>
|
|
30639
|
-
|
|
30640
|
-
|
|
30641
|
-
|
|
30642
|
-
|
|
30643
|
-
`
|
|
30644
|
-
|
|
30645
|
-
|
|
30653
|
+
const faceTransformFor = useCallback41(
|
|
30654
|
+
(value) => {
|
|
30655
|
+
const p = D6_FACE_PLACEMENTS[value];
|
|
30656
|
+
const parts = [];
|
|
30657
|
+
if (p.x !== 0) parts.push(`rotateX(${p.x}deg)`);
|
|
30658
|
+
if (p.y !== 0) parts.push(`rotateY(${p.y}deg)`);
|
|
30659
|
+
parts.push(`translateZ(${half}px)`);
|
|
30660
|
+
return parts.join(" ");
|
|
30661
|
+
},
|
|
30646
30662
|
[half]
|
|
30647
30663
|
);
|
|
30648
30664
|
const defaultPositions = useCallback41(
|
|
@@ -30664,15 +30680,23 @@ function DiceRoller({
|
|
|
30664
30680
|
[half]
|
|
30665
30681
|
);
|
|
30666
30682
|
const writeCubeRotation = useCallback41(
|
|
30667
|
-
(i, rx, ry, rz, withTransition) => {
|
|
30683
|
+
(i, rx, ry, rz, withTransition, tiltZ = 0) => {
|
|
30668
30684
|
const el = cubeRefs.current[i];
|
|
30669
30685
|
if (!el) return;
|
|
30670
30686
|
el.style.transition = withTransition ? "transform 0.95s cubic-bezier(0.12,0.8,0.22,1)" : "none";
|
|
30671
|
-
el.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
|
|
30687
|
+
el.style.transform = `${tiltZ ? `rotateZ(${tiltZ}deg) ` : ""}rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
|
|
30672
30688
|
},
|
|
30673
30689
|
[]
|
|
30674
30690
|
);
|
|
30675
|
-
|
|
30691
|
+
useEffect51(() => {
|
|
30692
|
+
if (timersRef.current.length > 0) {
|
|
30693
|
+
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30694
|
+
timersRef.current = [];
|
|
30695
|
+
}
|
|
30696
|
+
if (rollingRef.current) {
|
|
30697
|
+
rollingRef.current = false;
|
|
30698
|
+
setRolling(false);
|
|
30699
|
+
}
|
|
30676
30700
|
const rawW = arenaRef.current?.offsetWidth ?? 0;
|
|
30677
30701
|
const rawH = arenaRef.current?.offsetHeight ?? 0;
|
|
30678
30702
|
const w = rawW > 20 ? rawW : arena.w > 20 ? arena.w : 400;
|
|
@@ -30698,19 +30722,23 @@ function DiceRoller({
|
|
|
30698
30722
|
setResults(null);
|
|
30699
30723
|
}, [
|
|
30700
30724
|
clampedCount,
|
|
30725
|
+
sides,
|
|
30701
30726
|
effectiveSize,
|
|
30702
30727
|
arena.w,
|
|
30703
30728
|
arenaHeight,
|
|
30704
30729
|
defaultPositions,
|
|
30705
30730
|
half
|
|
30706
30731
|
]);
|
|
30732
|
+
useEffect51(() => {
|
|
30733
|
+
setHistory([]);
|
|
30734
|
+
}, [sides]);
|
|
30707
30735
|
const roll = useCallback41(() => {
|
|
30708
30736
|
if (rollingRef.current) return;
|
|
30709
30737
|
rollingRef.current = true;
|
|
30710
30738
|
setRolling(true);
|
|
30711
30739
|
const vals = Array.from(
|
|
30712
30740
|
{ length: clampedCount },
|
|
30713
|
-
() => Math.floor(Math.random() *
|
|
30741
|
+
() => Math.floor(Math.random() * sides) + 1
|
|
30714
30742
|
);
|
|
30715
30743
|
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30716
30744
|
timersRef.current = [];
|
|
@@ -30725,13 +30753,17 @@ function DiceRoller({
|
|
|
30725
30753
|
const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
|
|
30726
30754
|
const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
|
|
30727
30755
|
for (let i = 0; i < clampedCount; i++) {
|
|
30728
|
-
|
|
30729
|
-
|
|
30730
|
-
|
|
30731
|
-
|
|
30732
|
-
|
|
30733
|
-
|
|
30734
|
-
|
|
30756
|
+
if (sides === 6) {
|
|
30757
|
+
writeCubeRotation(
|
|
30758
|
+
i,
|
|
30759
|
+
(Math.random() - 0.5) * 720,
|
|
30760
|
+
(Math.random() - 0.5) * 720,
|
|
30761
|
+
(Math.random() - 0.5) * 720,
|
|
30762
|
+
false
|
|
30763
|
+
);
|
|
30764
|
+
} else {
|
|
30765
|
+
writeCubeRotation(i, 0, 0, (Math.random() - 0.5) * 720, false);
|
|
30766
|
+
}
|
|
30735
30767
|
const el = dieWrapperRefs.current[i];
|
|
30736
30768
|
if (el) el.style.transition = "none";
|
|
30737
30769
|
const shadow = shadowRefs.current[i];
|
|
@@ -30764,18 +30796,47 @@ function DiceRoller({
|
|
|
30764
30796
|
}, capturedStep * stepMs);
|
|
30765
30797
|
timersRef.current.push(timer);
|
|
30766
30798
|
}
|
|
30799
|
+
if (sides !== 6) {
|
|
30800
|
+
const flickerTicks = 8;
|
|
30801
|
+
const flickerStep = Math.max(60, Math.floor(TUMBLE_MS / flickerTicks));
|
|
30802
|
+
for (let f = 1; f <= flickerTicks; f++) {
|
|
30803
|
+
const t = setTimeout(() => {
|
|
30804
|
+
for (let i = 0; i < clampedCount; i++) {
|
|
30805
|
+
const el = numeralRefs.current[i];
|
|
30806
|
+
if (el)
|
|
30807
|
+
el.textContent = formatDieValue(
|
|
30808
|
+
Math.floor(Math.random() * sides) + 1,
|
|
30809
|
+
sides
|
|
30810
|
+
);
|
|
30811
|
+
}
|
|
30812
|
+
}, f * flickerStep);
|
|
30813
|
+
timersRef.current.push(t);
|
|
30814
|
+
}
|
|
30815
|
+
}
|
|
30767
30816
|
requestAnimationFrame(() => {
|
|
30768
30817
|
requestAnimationFrame(() => {
|
|
30769
30818
|
for (let i = 0; i < clampedCount; i++) {
|
|
30770
|
-
const
|
|
30771
|
-
|
|
30772
|
-
|
|
30773
|
-
|
|
30774
|
-
|
|
30819
|
+
const tilt = (Math.random() - 0.5) * 18;
|
|
30820
|
+
if (sides === 6) {
|
|
30821
|
+
const tgt = d6LandingRotation(vals[i]);
|
|
30822
|
+
const lx = tgt.x + (Math.random() > 0.5 ? 720 : -720);
|
|
30823
|
+
const ly = tgt.y;
|
|
30824
|
+
const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
|
|
30825
|
+
writeCubeRotation(i, lx, ly, lz, true, tilt);
|
|
30826
|
+
} else {
|
|
30827
|
+
const lz = (Math.random() > 0.5 ? 1 : -1) * 720 + tilt;
|
|
30828
|
+
writeCubeRotation(i, 0, 0, lz, true);
|
|
30829
|
+
}
|
|
30775
30830
|
}
|
|
30776
30831
|
});
|
|
30777
30832
|
});
|
|
30778
30833
|
const settleTimer = setTimeout(() => {
|
|
30834
|
+
if (sides !== 6) {
|
|
30835
|
+
for (let i = 0; i < clampedCount; i++) {
|
|
30836
|
+
const el = numeralRefs.current[i];
|
|
30837
|
+
if (el) el.textContent = formatDieValue(vals[i], sides);
|
|
30838
|
+
}
|
|
30839
|
+
}
|
|
30779
30840
|
setResults(vals);
|
|
30780
30841
|
setRolling(false);
|
|
30781
30842
|
rollingRef.current = false;
|
|
@@ -30788,28 +30849,28 @@ function DiceRoller({
|
|
|
30788
30849
|
timersRef.current.push(settleTimer);
|
|
30789
30850
|
}, [
|
|
30790
30851
|
clampedCount,
|
|
30852
|
+
sides,
|
|
30791
30853
|
defaultPositions,
|
|
30792
30854
|
effectiveSize,
|
|
30793
30855
|
half,
|
|
30794
|
-
reducedMotion,
|
|
30795
30856
|
onRoll,
|
|
30796
30857
|
writeCubeRotation,
|
|
30797
30858
|
writeDiePosition,
|
|
30798
30859
|
showHistory,
|
|
30799
30860
|
historyMax
|
|
30800
30861
|
]);
|
|
30801
|
-
|
|
30862
|
+
useEffect51(() => {
|
|
30802
30863
|
if (rollRef) rollRef.current = roll;
|
|
30803
30864
|
return () => {
|
|
30804
30865
|
if (rollRef && rollRef.current === roll) rollRef.current = null;
|
|
30805
30866
|
};
|
|
30806
30867
|
}, [roll, rollRef]);
|
|
30807
|
-
|
|
30868
|
+
useEffect51(() => {
|
|
30808
30869
|
if (!autoRoll) return;
|
|
30809
30870
|
const t = setTimeout(roll, 300);
|
|
30810
30871
|
return () => clearTimeout(t);
|
|
30811
30872
|
}, []);
|
|
30812
|
-
|
|
30873
|
+
useEffect51(
|
|
30813
30874
|
() => () => {
|
|
30814
30875
|
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30815
30876
|
timersRef.current = [];
|
|
@@ -30833,7 +30894,7 @@ function DiceRoller({
|
|
|
30833
30894
|
{
|
|
30834
30895
|
ref: arenaRef,
|
|
30835
30896
|
role: "img",
|
|
30836
|
-
"aria-label": ariaLabel ?? `${clampedCount} dice`,
|
|
30897
|
+
"aria-label": ariaLabel ?? `${clampedCount} ${sides === 6 ? "dice" : `${sides}-sided dice`}`,
|
|
30837
30898
|
"aria-live": "polite",
|
|
30838
30899
|
style: {
|
|
30839
30900
|
position: "relative",
|
|
@@ -30896,7 +30957,7 @@ function DiceRoller({
|
|
|
30896
30957
|
transformStyle: "preserve-3d",
|
|
30897
30958
|
willChange: "transform"
|
|
30898
30959
|
},
|
|
30899
|
-
children: [1, 2, 3, 4, 5, 6].map((val
|
|
30960
|
+
children: sides === 6 ? [1, 2, 3, 4, 5, 6].map((val) => /* @__PURE__ */ jsx113(
|
|
30900
30961
|
"div",
|
|
30901
30962
|
{
|
|
30902
30963
|
style: {
|
|
@@ -30906,7 +30967,7 @@ function DiceRoller({
|
|
|
30906
30967
|
background: colors.face,
|
|
30907
30968
|
border: `1px solid ${colors.faceBorder}`,
|
|
30908
30969
|
borderRadius: faceRadius,
|
|
30909
|
-
transform:
|
|
30970
|
+
transform: faceTransformFor(val),
|
|
30910
30971
|
transition: "background 0.3s, border-color 0.3s"
|
|
30911
30972
|
},
|
|
30912
30973
|
children: /* @__PURE__ */ jsx113(
|
|
@@ -30920,7 +30981,64 @@ function DiceRoller({
|
|
|
30920
30981
|
)
|
|
30921
30982
|
},
|
|
30922
30983
|
val
|
|
30923
|
-
))
|
|
30984
|
+
)) : (() => {
|
|
30985
|
+
const shape = POLY_SHAPES[sides];
|
|
30986
|
+
const shown = results?.[d] ?? sides;
|
|
30987
|
+
return /* @__PURE__ */ jsxs86(
|
|
30988
|
+
"svg",
|
|
30989
|
+
{
|
|
30990
|
+
viewBox: "0 0 100 100",
|
|
30991
|
+
width: "100%",
|
|
30992
|
+
height: "100%",
|
|
30993
|
+
style: { display: "block", overflow: "visible" },
|
|
30994
|
+
"aria-hidden": "true",
|
|
30995
|
+
children: [
|
|
30996
|
+
/* @__PURE__ */ jsx113(
|
|
30997
|
+
"polygon",
|
|
30998
|
+
{
|
|
30999
|
+
points: shape.points,
|
|
31000
|
+
fill: colors.face,
|
|
31001
|
+
stroke: colors.faceBorder,
|
|
31002
|
+
strokeWidth: 2.5,
|
|
31003
|
+
strokeLinejoin: "round",
|
|
31004
|
+
style: { transition: "fill 0.3s, stroke 0.3s" }
|
|
31005
|
+
}
|
|
31006
|
+
),
|
|
31007
|
+
/* @__PURE__ */ jsx113(
|
|
31008
|
+
"polygon",
|
|
31009
|
+
{
|
|
31010
|
+
points: shape.points,
|
|
31011
|
+
fill: "none",
|
|
31012
|
+
stroke: colors.faceBorder,
|
|
31013
|
+
strokeWidth: 1.5,
|
|
31014
|
+
strokeLinejoin: "round",
|
|
31015
|
+
opacity: 0.55,
|
|
31016
|
+
transform: "translate(50 50) scale(0.76) translate(-50 -50)"
|
|
31017
|
+
}
|
|
31018
|
+
),
|
|
31019
|
+
/* @__PURE__ */ jsx113(
|
|
31020
|
+
"text",
|
|
31021
|
+
{
|
|
31022
|
+
ref: getNumeralSetter(d),
|
|
31023
|
+
x: 50,
|
|
31024
|
+
y: shape.textY,
|
|
31025
|
+
textAnchor: "middle",
|
|
31026
|
+
dominantBaseline: "central",
|
|
31027
|
+
fontSize: 100 * shape.fontScale,
|
|
31028
|
+
fontWeight: 800,
|
|
31029
|
+
fill: colors.pip,
|
|
31030
|
+
style: {
|
|
31031
|
+
fontVariantNumeric: "tabular-nums",
|
|
31032
|
+
transition: "fill 0.3s",
|
|
31033
|
+
userSelect: "none"
|
|
31034
|
+
},
|
|
31035
|
+
children: formatDieValue(shown, sides)
|
|
31036
|
+
}
|
|
31037
|
+
)
|
|
31038
|
+
]
|
|
31039
|
+
}
|
|
31040
|
+
);
|
|
31041
|
+
})()
|
|
30924
31042
|
}
|
|
30925
31043
|
)
|
|
30926
31044
|
] }, d);
|
|
@@ -31053,10 +31171,10 @@ DiceRoller.displayName = "DiceRoller";
|
|
|
31053
31171
|
|
|
31054
31172
|
// src/components/ui/bracket-generator/index.tsx
|
|
31055
31173
|
import {
|
|
31056
|
-
useState as
|
|
31174
|
+
useState as useState67,
|
|
31057
31175
|
useCallback as useCallback42,
|
|
31058
31176
|
useRef as useRef41,
|
|
31059
|
-
useEffect as
|
|
31177
|
+
useEffect as useEffect52,
|
|
31060
31178
|
useMemo as useMemo27,
|
|
31061
31179
|
useLayoutEffect as useLayoutEffect2
|
|
31062
31180
|
} from "react";
|
|
@@ -31279,7 +31397,7 @@ function computeLayout(rounds, firstRoundCount) {
|
|
|
31279
31397
|
};
|
|
31280
31398
|
}
|
|
31281
31399
|
function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
31282
|
-
const [transform, setTransform] =
|
|
31400
|
+
const [transform, setTransform] = useState67({
|
|
31283
31401
|
x: 0,
|
|
31284
31402
|
y: 0,
|
|
31285
31403
|
scale: 1
|
|
@@ -31299,7 +31417,7 @@ function usePanZoom(viewportRef, contentSize, minZoom, maxZoom) {
|
|
|
31299
31417
|
},
|
|
31300
31418
|
[contentSize]
|
|
31301
31419
|
);
|
|
31302
|
-
|
|
31420
|
+
useEffect52(() => {
|
|
31303
31421
|
const el = viewportRef.current;
|
|
31304
31422
|
if (!el) return;
|
|
31305
31423
|
const onWheel = (e) => {
|
|
@@ -31530,12 +31648,12 @@ function BracketGenerator({
|
|
|
31530
31648
|
ariaLabel = "Tournament bracket"
|
|
31531
31649
|
}) {
|
|
31532
31650
|
const dark = useDarkMode(darkMode);
|
|
31533
|
-
const [bracketState, setBracketState] =
|
|
31651
|
+
const [bracketState, setBracketState] = useState67({
|
|
31534
31652
|
matches: [],
|
|
31535
31653
|
rounds: 0,
|
|
31536
31654
|
champion: null
|
|
31537
31655
|
});
|
|
31538
|
-
const [simulating, setSimulating] =
|
|
31656
|
+
const [simulating, setSimulating] = useState67(false);
|
|
31539
31657
|
const autoRef = useRef41(null);
|
|
31540
31658
|
const viewportRef = useRef41(null);
|
|
31541
31659
|
const effectiveParticipants = useMemo27(() => {
|
|
@@ -31590,7 +31708,7 @@ function BracketGenerator({
|
|
|
31590
31708
|
minZoom,
|
|
31591
31709
|
maxZoom
|
|
31592
31710
|
);
|
|
31593
|
-
const [miniMapHidden, setMiniMapHidden] =
|
|
31711
|
+
const [miniMapHidden, setMiniMapHidden] = useState67(false);
|
|
31594
31712
|
const miniMapDragRef = useRef41(false);
|
|
31595
31713
|
const resumeRef = useRef41(resumeMatches);
|
|
31596
31714
|
const hydrateFromResume = useCallback42(() => {
|
|
@@ -31724,7 +31842,7 @@ function BracketGenerator({
|
|
|
31724
31842
|
[]
|
|
31725
31843
|
);
|
|
31726
31844
|
const prevBracketStateRef = useRef41(bracketState);
|
|
31727
|
-
|
|
31845
|
+
useEffect52(() => {
|
|
31728
31846
|
const prev = prevBracketStateRef.current;
|
|
31729
31847
|
const next = bracketState;
|
|
31730
31848
|
if (prev === next) return;
|
|
@@ -31748,7 +31866,7 @@ function BracketGenerator({
|
|
|
31748
31866
|
[effectiveParticipants, seedingStrategy]
|
|
31749
31867
|
);
|
|
31750
31868
|
const seededKeyRef = useRef41(null);
|
|
31751
|
-
|
|
31869
|
+
useEffect52(() => {
|
|
31752
31870
|
if (seededKeyRef.current === structuralKey) {
|
|
31753
31871
|
setBracketState((prev) => {
|
|
31754
31872
|
if (!prev.matches.length) return prev;
|
|
@@ -31779,7 +31897,7 @@ function BracketGenerator({
|
|
|
31779
31897
|
seedBracket();
|
|
31780
31898
|
}
|
|
31781
31899
|
}, [structuralKey, effectiveParticipants, hydrateFromResume, seedBracket]);
|
|
31782
|
-
|
|
31900
|
+
useEffect52(() => {
|
|
31783
31901
|
return () => {
|
|
31784
31902
|
if (autoRef.current) clearTimeout(autoRef.current);
|
|
31785
31903
|
};
|
|
@@ -31790,7 +31908,7 @@ function BracketGenerator({
|
|
|
31790
31908
|
return () => clearTimeout(timer);
|
|
31791
31909
|
}
|
|
31792
31910
|
}, [contentSize.w]);
|
|
31793
|
-
|
|
31911
|
+
useEffect52(() => {
|
|
31794
31912
|
if (autoSimulate && bracketState.matches.length && !bracketState.champion) {
|
|
31795
31913
|
const timer = setTimeout(autoPlay, 500);
|
|
31796
31914
|
return () => clearTimeout(timer);
|
|
@@ -32511,10 +32629,10 @@ function BracketGenerator({
|
|
|
32511
32629
|
// src/components/ui/coin-flipper/index.tsx
|
|
32512
32630
|
import {
|
|
32513
32631
|
useCallback as useCallback43,
|
|
32514
|
-
useEffect as
|
|
32632
|
+
useEffect as useEffect53,
|
|
32515
32633
|
useMemo as useMemo28,
|
|
32516
32634
|
useRef as useRef42,
|
|
32517
|
-
useState as
|
|
32635
|
+
useState as useState68
|
|
32518
32636
|
} from "react";
|
|
32519
32637
|
import { jsx as jsx115, jsxs as jsxs88 } from "react/jsx-runtime";
|
|
32520
32638
|
var PRESETS3 = {
|
|
@@ -32699,10 +32817,10 @@ function CoinFlipper({
|
|
|
32699
32817
|
}) {
|
|
32700
32818
|
const dark = useDarkMode(darkMode);
|
|
32701
32819
|
const tc = typeof theme5 === "string" ? PRESETS3[theme5] || PRESETS3.gold : theme5;
|
|
32702
|
-
const [result, setResult] =
|
|
32703
|
-
const [flipping, setFlipping] =
|
|
32704
|
-
const [history, setHistory] =
|
|
32705
|
-
const [stats, setStats] =
|
|
32820
|
+
const [result, setResult] = useState68(null);
|
|
32821
|
+
const [flipping, setFlipping] = useState68(false);
|
|
32822
|
+
const [history, setHistory] = useState68([]);
|
|
32823
|
+
const [stats, setStats] = useState68({ heads: 0, tails: 0 });
|
|
32706
32824
|
const flipIdRef = useRef42(0);
|
|
32707
32825
|
const coinRef = useRef42(null);
|
|
32708
32826
|
const shadowRef = useRef42(null);
|
|
@@ -32758,16 +32876,19 @@ function CoinFlipper({
|
|
|
32758
32876
|
}, frames.length * stepMs);
|
|
32759
32877
|
timersRef.current.push(settleTimer);
|
|
32760
32878
|
}, [flipping, onFlip, historyMax]);
|
|
32761
|
-
|
|
32879
|
+
useEffect53(() => {
|
|
32762
32880
|
if (flipRef) flipRef.current = flip;
|
|
32881
|
+
return () => {
|
|
32882
|
+
if (flipRef && flipRef.current === flip) flipRef.current = null;
|
|
32883
|
+
};
|
|
32763
32884
|
}, [flip, flipRef]);
|
|
32764
|
-
|
|
32885
|
+
useEffect53(() => {
|
|
32765
32886
|
if (autoFlip) {
|
|
32766
32887
|
const timer = setTimeout(flip, 300);
|
|
32767
32888
|
return () => clearTimeout(timer);
|
|
32768
32889
|
}
|
|
32769
32890
|
}, []);
|
|
32770
|
-
|
|
32891
|
+
useEffect53(() => {
|
|
32771
32892
|
return () => {
|
|
32772
32893
|
timersRef.current.forEach(clearTimeout);
|
|
32773
32894
|
};
|
|
@@ -33210,6 +33331,23 @@ import {
|
|
|
33210
33331
|
useRef as useRef43,
|
|
33211
33332
|
useState as useState70
|
|
33212
33333
|
} from "react";
|
|
33334
|
+
|
|
33335
|
+
// src/hooks/web/use-prefers-reduced-motion.ts
|
|
33336
|
+
import { useEffect as useEffect54, useState as useState69 } from "react";
|
|
33337
|
+
function usePrefersReducedMotion() {
|
|
33338
|
+
const [reduced, setReduced] = useState69(false);
|
|
33339
|
+
useEffect54(() => {
|
|
33340
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
33341
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
33342
|
+
setReduced(mq.matches);
|
|
33343
|
+
const read = () => setReduced(mq.matches);
|
|
33344
|
+
mq.addEventListener("change", read);
|
|
33345
|
+
return () => mq.removeEventListener("change", read);
|
|
33346
|
+
}, []);
|
|
33347
|
+
return reduced;
|
|
33348
|
+
}
|
|
33349
|
+
|
|
33350
|
+
// src/components/ui/random-player-picker/index.tsx
|
|
33213
33351
|
import { Fragment as Fragment31, jsx as jsx116, jsxs as jsxs89 } from "react/jsx-runtime";
|
|
33214
33352
|
var PRESETS4 = {
|
|
33215
33353
|
blue: {
|
|
@@ -33657,6 +33795,8 @@ function RandomPlayerPicker({
|
|
|
33657
33795
|
const particleTimer = useRef43(null);
|
|
33658
33796
|
const popTimer = useRef43(null);
|
|
33659
33797
|
const tickInterval = useRef43(null);
|
|
33798
|
+
const pendingPopIdxRef = useRef43(null);
|
|
33799
|
+
const removeWinnersRef = useRef43(removeWinners);
|
|
33660
33800
|
const tickAudioRef = useRef43(null);
|
|
33661
33801
|
const winAudioRef = useRef43(null);
|
|
33662
33802
|
const containerRef = useRef43(null);
|
|
@@ -33695,10 +33835,27 @@ function RandomPlayerPicker({
|
|
|
33695
33835
|
winAudioRef.current = null;
|
|
33696
33836
|
};
|
|
33697
33837
|
}, [winSoundUrl, soundVolume]);
|
|
33838
|
+
useEffect55(() => {
|
|
33839
|
+
removeWinnersRef.current = removeWinners;
|
|
33840
|
+
}, [removeWinners]);
|
|
33698
33841
|
useEffect55(() => {
|
|
33699
33842
|
const ids = participants.map((p) => p.id).join("|");
|
|
33700
33843
|
const structuralChange = ids !== prevIdsRef.current;
|
|
33701
33844
|
if (structuralChange) {
|
|
33845
|
+
if (winnerTimer.current) {
|
|
33846
|
+
clearTimeout(winnerTimer.current);
|
|
33847
|
+
winnerTimer.current = null;
|
|
33848
|
+
}
|
|
33849
|
+
if (tickInterval.current) {
|
|
33850
|
+
clearTimeout(tickInterval.current);
|
|
33851
|
+
tickInterval.current = null;
|
|
33852
|
+
}
|
|
33853
|
+
if (popTimer.current) {
|
|
33854
|
+
clearTimeout(popTimer.current);
|
|
33855
|
+
popTimer.current = null;
|
|
33856
|
+
}
|
|
33857
|
+
pendingPopIdxRef.current = null;
|
|
33858
|
+
setSpinning(false);
|
|
33702
33859
|
setPool(participants);
|
|
33703
33860
|
setHistory([]);
|
|
33704
33861
|
setWinner(null);
|
|
@@ -33755,33 +33912,50 @@ function RandomPlayerPicker({
|
|
|
33755
33912
|
[dark]
|
|
33756
33913
|
);
|
|
33757
33914
|
const spin = useCallback44(() => {
|
|
33758
|
-
if (spinning
|
|
33915
|
+
if (spinning) return;
|
|
33916
|
+
let activePool = pool;
|
|
33917
|
+
if (popTimer.current) {
|
|
33918
|
+
clearTimeout(popTimer.current);
|
|
33919
|
+
popTimer.current = null;
|
|
33920
|
+
const pendingIdx = pendingPopIdxRef.current;
|
|
33921
|
+
pendingPopIdxRef.current = null;
|
|
33922
|
+
if (pendingIdx != null && pendingIdx >= 0 && pendingIdx < pool.length && removeWinnersRef.current) {
|
|
33923
|
+
activePool = pool.filter((_, i) => i !== pendingIdx);
|
|
33924
|
+
setPool(activePool);
|
|
33925
|
+
setWinner(null);
|
|
33926
|
+
}
|
|
33927
|
+
}
|
|
33928
|
+
const activeN = activePool.length;
|
|
33929
|
+
if (activeN < 2) return;
|
|
33930
|
+
const activeAnglePerWedge = 2 * Math.PI / activeN;
|
|
33931
|
+
const activeRotation = rotation;
|
|
33932
|
+
const activeReelY = reelY;
|
|
33759
33933
|
onSpinStart?.();
|
|
33760
|
-
const winnerIdx = weightedIndex(
|
|
33934
|
+
const winnerIdx = weightedIndex(activePool);
|
|
33761
33935
|
const minRev = minRevolutions + intensityCfg.revsBoost;
|
|
33762
33936
|
const maxRev = maxRevolutions + intensityCfg.revsBoost;
|
|
33763
33937
|
const minFullRevs = Math.ceil(minRev);
|
|
33764
33938
|
const maxFullRevs = Math.max(minFullRevs, Math.floor(maxRev));
|
|
33765
33939
|
const revolutions = minFullRevs + Math.floor(Math.random() * (maxFullRevs - minFullRevs + 1));
|
|
33766
|
-
const wedgeMidRad = winnerIdx *
|
|
33940
|
+
const wedgeMidRad = winnerIdx * activeAnglePerWedge + activeAnglePerWedge / 2;
|
|
33767
33941
|
const wedgeMidDeg = wedgeMidRad * 180 / Math.PI;
|
|
33768
|
-
const wheelWobble = (Math.random() - 0.5) * (
|
|
33769
|
-
const currentMod = (
|
|
33942
|
+
const wheelWobble = (Math.random() - 0.5) * (activeAnglePerWedge * 180 / Math.PI) * 0.6;
|
|
33943
|
+
const currentMod = (activeRotation % 360 + 360) % 360;
|
|
33770
33944
|
const targetMod = ((-wedgeMidDeg + wheelWobble) % 360 + 360) % 360;
|
|
33771
33945
|
let deltaMod = targetMod - currentMod;
|
|
33772
33946
|
if (deltaMod < 0) deltaMod += 360;
|
|
33773
|
-
const finalRotation =
|
|
33947
|
+
const finalRotation = activeRotation + deltaMod + revolutions * 360;
|
|
33774
33948
|
const centerOffsetRows = (reelVisibleRows - 1) / 2;
|
|
33775
33949
|
const centerOffsetPx = centerOffsetRows * reelRowHeight;
|
|
33776
33950
|
const currentCenterRow = Math.round(
|
|
33777
|
-
(
|
|
33951
|
+
(activeReelY + centerOffsetPx) / reelRowHeight
|
|
33778
33952
|
);
|
|
33779
|
-
const currentCenterMod = mod(currentCenterRow,
|
|
33780
|
-
const targetRowOffset = (winnerIdx - currentCenterMod +
|
|
33781
|
-
const reelRevRows = Math.round(revolutions *
|
|
33782
|
-
const finalReelY =
|
|
33783
|
-
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight,
|
|
33784
|
-
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx <
|
|
33953
|
+
const currentCenterMod = mod(currentCenterRow, activeN);
|
|
33954
|
+
const targetRowOffset = (winnerIdx - currentCenterMod + activeN) % activeN;
|
|
33955
|
+
const reelRevRows = Math.round(revolutions * activeN);
|
|
33956
|
+
const finalReelY = activeReelY + (reelRevRows + targetRowOffset) * reelRowHeight;
|
|
33957
|
+
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight, activeN) : wheelIndexAtPointer(finalRotation, activeN);
|
|
33958
|
+
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx < activePool.length ? settledWinnerIdx : winnerIdx;
|
|
33785
33959
|
const effectiveDuration = reducedMotion ? 250 : Math.round(spinDuration * intensityCfg.durationMult);
|
|
33786
33960
|
setSpinning(true);
|
|
33787
33961
|
setWinner(null);
|
|
@@ -33794,7 +33968,7 @@ function RandomPlayerPicker({
|
|
|
33794
33968
|
if ((onTick || tickAudioRef.current) && !reducedMotion) {
|
|
33795
33969
|
const wedges = mode === "reel" ? Math.max(1, reelRevRows + targetRowOffset) : (() => {
|
|
33796
33970
|
const totalDelta = deltaMod + revolutions * 360;
|
|
33797
|
-
const wedgeDeg =
|
|
33971
|
+
const wedgeDeg = activeAnglePerWedge * 180 / Math.PI;
|
|
33798
33972
|
return Math.max(
|
|
33799
33973
|
1,
|
|
33800
33974
|
Math.round(totalDelta / Math.max(wedgeDeg, 1))
|
|
@@ -33826,7 +34000,7 @@ function RandomPlayerPicker({
|
|
|
33826
34000
|
schedule();
|
|
33827
34001
|
}
|
|
33828
34002
|
winnerTimer.current = setTimeout(() => {
|
|
33829
|
-
const picked =
|
|
34003
|
+
const picked = activePool[finalWinnerIdx];
|
|
33830
34004
|
if (!picked) {
|
|
33831
34005
|
setSpinning(false);
|
|
33832
34006
|
return;
|
|
@@ -33872,7 +34046,11 @@ function RandomPlayerPicker({
|
|
|
33872
34046
|
particleTimer.current = setTimeout(() => setParticles([]), 2400);
|
|
33873
34047
|
}
|
|
33874
34048
|
if (removeWinners) {
|
|
34049
|
+
pendingPopIdxRef.current = finalWinnerIdx;
|
|
33875
34050
|
popTimer.current = setTimeout(() => {
|
|
34051
|
+
popTimer.current = null;
|
|
34052
|
+
pendingPopIdxRef.current = null;
|
|
34053
|
+
if (!removeWinnersRef.current) return;
|
|
33876
34054
|
setPool((p) => p.filter((_, i) => i !== finalWinnerIdx));
|
|
33877
34055
|
setWinner(null);
|
|
33878
34056
|
setRotation(0);
|
|
@@ -33883,8 +34061,6 @@ function RandomPlayerPicker({
|
|
|
33883
34061
|
}, [
|
|
33884
34062
|
pool,
|
|
33885
34063
|
spinning,
|
|
33886
|
-
n,
|
|
33887
|
-
anglePerWedge,
|
|
33888
34064
|
rotation,
|
|
33889
34065
|
reelY,
|
|
33890
34066
|
mode,
|
|
@@ -33920,6 +34096,7 @@ function RandomPlayerPicker({
|
|
|
33920
34096
|
[]
|
|
33921
34097
|
);
|
|
33922
34098
|
useEffect55(() => {
|
|
34099
|
+
if (trigger === "external") return;
|
|
33923
34100
|
const el = containerRef.current;
|
|
33924
34101
|
if (!el) return;
|
|
33925
34102
|
const h = (e) => {
|
|
@@ -33930,8 +34107,22 @@ function RandomPlayerPicker({
|
|
|
33930
34107
|
};
|
|
33931
34108
|
el.addEventListener("keydown", h);
|
|
33932
34109
|
return () => el.removeEventListener("keydown", h);
|
|
33933
|
-
}, [spin]);
|
|
34110
|
+
}, [spin, trigger]);
|
|
33934
34111
|
const reset = useCallback44(() => {
|
|
34112
|
+
if (winnerTimer.current) {
|
|
34113
|
+
clearTimeout(winnerTimer.current);
|
|
34114
|
+
winnerTimer.current = null;
|
|
34115
|
+
}
|
|
34116
|
+
if (tickInterval.current) {
|
|
34117
|
+
clearTimeout(tickInterval.current);
|
|
34118
|
+
tickInterval.current = null;
|
|
34119
|
+
}
|
|
34120
|
+
if (popTimer.current) {
|
|
34121
|
+
clearTimeout(popTimer.current);
|
|
34122
|
+
popTimer.current = null;
|
|
34123
|
+
}
|
|
34124
|
+
pendingPopIdxRef.current = null;
|
|
34125
|
+
setSpinning(false);
|
|
33935
34126
|
setPool(participants);
|
|
33936
34127
|
setHistory([]);
|
|
33937
34128
|
setWinner(null);
|
|
@@ -38404,27 +38595,28 @@ function GameTimer({
|
|
|
38404
38595
|
const now = performance.now();
|
|
38405
38596
|
const delta = now - lastTickRef.current;
|
|
38406
38597
|
lastTickRef.current = now;
|
|
38407
|
-
|
|
38408
|
-
|
|
38409
|
-
|
|
38410
|
-
|
|
38411
|
-
|
|
38412
|
-
|
|
38413
|
-
|
|
38598
|
+
const next = elapsedRef.current + delta;
|
|
38599
|
+
if (mode === "countdown" && next >= durationMs) {
|
|
38600
|
+
elapsedRef.current = durationMs;
|
|
38601
|
+
setElapsedMs(durationMs);
|
|
38602
|
+
setRunning(false);
|
|
38603
|
+
setCompleted(true);
|
|
38604
|
+
onComplete?.();
|
|
38605
|
+
return;
|
|
38606
|
+
}
|
|
38607
|
+
if (mode === "countdown") {
|
|
38608
|
+
const secLeft = Math.ceil((durationMs - next) / 1e3);
|
|
38609
|
+
if (secLeft <= warningAt && !warningFiredRef.current) {
|
|
38610
|
+
warningFiredRef.current = true;
|
|
38611
|
+
onWarning?.();
|
|
38414
38612
|
}
|
|
38415
|
-
if (
|
|
38416
|
-
|
|
38417
|
-
|
|
38418
|
-
warningFiredRef.current = true;
|
|
38419
|
-
onWarning?.();
|
|
38420
|
-
}
|
|
38421
|
-
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38422
|
-
dangerFiredRef.current = true;
|
|
38423
|
-
onDanger?.();
|
|
38424
|
-
}
|
|
38613
|
+
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38614
|
+
dangerFiredRef.current = true;
|
|
38615
|
+
onDanger?.();
|
|
38425
38616
|
}
|
|
38426
|
-
|
|
38427
|
-
|
|
38617
|
+
}
|
|
38618
|
+
elapsedRef.current = next;
|
|
38619
|
+
setElapsedMs(next);
|
|
38428
38620
|
rafRef.current = requestAnimationFrame(tick);
|
|
38429
38621
|
}, [mode, durationMs, warningAt, dangerAt, onComplete, onWarning, onDanger]);
|
|
38430
38622
|
useEffect59(() => {
|
|
@@ -38445,6 +38637,7 @@ function GameTimer({
|
|
|
38445
38637
|
}, []);
|
|
38446
38638
|
const reset = useCallback48(() => {
|
|
38447
38639
|
setRunning(false);
|
|
38640
|
+
elapsedRef.current = 0;
|
|
38448
38641
|
setElapsedMs(0);
|
|
38449
38642
|
setCompleted(false);
|
|
38450
38643
|
setLaps([]);
|
|
@@ -40401,6 +40594,8 @@ function RoundRobinScheduler({
|
|
|
40401
40594
|
theme: theme5 = "slate",
|
|
40402
40595
|
darkMode,
|
|
40403
40596
|
minTeams = 3,
|
|
40597
|
+
maxTeams,
|
|
40598
|
+
nameMaxLength,
|
|
40404
40599
|
defaultTeams = [],
|
|
40405
40600
|
resumeRounds,
|
|
40406
40601
|
onTeamsChange,
|
|
@@ -40423,39 +40618,41 @@ function RoundRobinScheduler({
|
|
|
40423
40618
|
useEffect62(() => {
|
|
40424
40619
|
onTeamsChange?.(teams);
|
|
40425
40620
|
}, [teams, onTeamsChange]);
|
|
40426
|
-
const
|
|
40427
|
-
|
|
40428
|
-
if (names.length === 0) return;
|
|
40429
|
-
setTeams((prev) => {
|
|
40621
|
+
const mergeNames = useCallback51(
|
|
40622
|
+
(prev, incoming) => {
|
|
40430
40623
|
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40431
40624
|
const next = [...prev];
|
|
40432
|
-
for (const
|
|
40433
|
-
if (
|
|
40434
|
-
|
|
40435
|
-
next.push(name);
|
|
40436
|
-
}
|
|
40437
|
-
}
|
|
40438
|
-
return next;
|
|
40439
|
-
});
|
|
40440
|
-
setInput("");
|
|
40441
|
-
setRounds([]);
|
|
40442
|
-
}, []);
|
|
40443
|
-
const importTeams = useCallback51((incoming) => {
|
|
40444
|
-
if (incoming.length === 0) return;
|
|
40445
|
-
setTeams((prev) => {
|
|
40446
|
-
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40447
|
-
const next = [...prev];
|
|
40448
|
-
for (const name of incoming) {
|
|
40625
|
+
for (const rawName of incoming) {
|
|
40626
|
+
if (maxTeams != null && next.length >= maxTeams) break;
|
|
40627
|
+
const name = nameMaxLength != null ? rawName.slice(0, nameMaxLength) : rawName;
|
|
40449
40628
|
const key = name.toLowerCase();
|
|
40450
|
-
if (!existing.has(key)) {
|
|
40629
|
+
if (name.length > 0 && !existing.has(key)) {
|
|
40451
40630
|
existing.add(key);
|
|
40452
40631
|
next.push(name);
|
|
40453
40632
|
}
|
|
40454
40633
|
}
|
|
40455
40634
|
return next;
|
|
40456
|
-
}
|
|
40457
|
-
|
|
40458
|
-
|
|
40635
|
+
},
|
|
40636
|
+
[maxTeams, nameMaxLength]
|
|
40637
|
+
);
|
|
40638
|
+
const addTeams = useCallback51(
|
|
40639
|
+
(raw) => {
|
|
40640
|
+
const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
40641
|
+
if (names.length === 0) return;
|
|
40642
|
+
setTeams((prev) => mergeNames(prev, names));
|
|
40643
|
+
setInput("");
|
|
40644
|
+
setRounds([]);
|
|
40645
|
+
},
|
|
40646
|
+
[mergeNames]
|
|
40647
|
+
);
|
|
40648
|
+
const importTeams = useCallback51(
|
|
40649
|
+
(incoming) => {
|
|
40650
|
+
if (incoming.length === 0) return;
|
|
40651
|
+
setTeams((prev) => mergeNames(prev, incoming));
|
|
40652
|
+
setRounds([]);
|
|
40653
|
+
},
|
|
40654
|
+
[mergeNames]
|
|
40655
|
+
);
|
|
40459
40656
|
const handleKeyDown = useCallback51(
|
|
40460
40657
|
(e) => {
|
|
40461
40658
|
if (e.key === "Enter") {
|
|
@@ -40949,6 +41146,8 @@ function Scoreboard({
|
|
|
40949
41146
|
onTeamsChange,
|
|
40950
41147
|
onRoundAdvance,
|
|
40951
41148
|
onNewGame,
|
|
41149
|
+
onReset,
|
|
41150
|
+
nameMaxLength,
|
|
40952
41151
|
labels,
|
|
40953
41152
|
ariaLabel = "Scoreboard",
|
|
40954
41153
|
className
|
|
@@ -41023,7 +41222,8 @@ function Scoreboard({
|
|
|
41023
41222
|
setRound(1);
|
|
41024
41223
|
setHistory([]);
|
|
41025
41224
|
setHistoryOpen(false);
|
|
41026
|
-
|
|
41225
|
+
onReset?.();
|
|
41226
|
+
}, [onReset]);
|
|
41027
41227
|
const newGame = useCallback52(() => {
|
|
41028
41228
|
setTeams(createDefaultTeams(seedCount, L.teamNamePrefix));
|
|
41029
41229
|
setRound(1);
|
|
@@ -41245,6 +41445,7 @@ function Scoreboard({
|
|
|
41245
41445
|
{
|
|
41246
41446
|
type: "text",
|
|
41247
41447
|
value: team.name,
|
|
41448
|
+
maxLength: nameMaxLength,
|
|
41248
41449
|
onChange: (e) => updateName(index, e.target.value),
|
|
41249
41450
|
style: nameInputStyle,
|
|
41250
41451
|
"aria-label": `Team ${index + 1} name`
|
|
@@ -43343,6 +43544,7 @@ export {
|
|
|
43343
43544
|
CommentSystem,
|
|
43344
43545
|
Container,
|
|
43345
43546
|
ConversionKPI,
|
|
43547
|
+
D6_FACE_PLACEMENTS,
|
|
43346
43548
|
DashboardGrid,
|
|
43347
43549
|
DashboardLayout,
|
|
43348
43550
|
DashboardWidget,
|
|
@@ -43583,6 +43785,7 @@ export {
|
|
|
43583
43785
|
createFormStore,
|
|
43584
43786
|
createOptimizedStore,
|
|
43585
43787
|
cssAnimations,
|
|
43788
|
+
d6LandingRotation,
|
|
43586
43789
|
dailyTrendingConfig,
|
|
43587
43790
|
detectAuthProvider,
|
|
43588
43791
|
detectDelimiter,
|