@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/index.mjs
CHANGED
|
@@ -30665,7 +30665,6 @@ function DiceRoller({
|
|
|
30665
30665
|
}) {
|
|
30666
30666
|
const clampedCount = Math.max(1, Math.min(MAX_COUNT, count2));
|
|
30667
30667
|
const dark = useDarkMode(darkMode);
|
|
30668
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
30669
30668
|
const [rolling, setRolling] = useState70(false);
|
|
30670
30669
|
const [results, setResults] = useState70(null);
|
|
30671
30670
|
const [history, setHistory] = useState70([]);
|
|
@@ -30802,6 +30801,14 @@ function DiceRoller({
|
|
|
30802
30801
|
[]
|
|
30803
30802
|
);
|
|
30804
30803
|
useEffect54(() => {
|
|
30804
|
+
if (timersRef.current.length > 0) {
|
|
30805
|
+
timersRef.current.forEach((t) => clearTimeout(t));
|
|
30806
|
+
timersRef.current = [];
|
|
30807
|
+
}
|
|
30808
|
+
if (rollingRef.current) {
|
|
30809
|
+
rollingRef.current = false;
|
|
30810
|
+
setRolling(false);
|
|
30811
|
+
}
|
|
30805
30812
|
const rawW = arenaRef.current?.offsetWidth ?? 0;
|
|
30806
30813
|
const rawH = arenaRef.current?.offsetHeight ?? 0;
|
|
30807
30814
|
const w = rawW > 20 ? rawW : arena.w > 20 ? arena.w : 400;
|
|
@@ -30958,7 +30965,6 @@ function DiceRoller({
|
|
|
30958
30965
|
defaultPositions,
|
|
30959
30966
|
effectiveSize,
|
|
30960
30967
|
half,
|
|
30961
|
-
reducedMotion,
|
|
30962
30968
|
onRoll,
|
|
30963
30969
|
writeCubeRotation,
|
|
30964
30970
|
writeDiePosition,
|
|
@@ -32984,6 +32990,9 @@ function CoinFlipper({
|
|
|
32984
32990
|
}, [flipping, onFlip, historyMax]);
|
|
32985
32991
|
useEffect56(() => {
|
|
32986
32992
|
if (flipRef) flipRef.current = flip;
|
|
32993
|
+
return () => {
|
|
32994
|
+
if (flipRef && flipRef.current === flip) flipRef.current = null;
|
|
32995
|
+
};
|
|
32987
32996
|
}, [flip, flipRef]);
|
|
32988
32997
|
useEffect56(() => {
|
|
32989
32998
|
if (autoFlip) {
|
|
@@ -33881,6 +33890,8 @@ function RandomPlayerPicker({
|
|
|
33881
33890
|
const particleTimer = useRef42(null);
|
|
33882
33891
|
const popTimer = useRef42(null);
|
|
33883
33892
|
const tickInterval = useRef42(null);
|
|
33893
|
+
const pendingPopIdxRef = useRef42(null);
|
|
33894
|
+
const removeWinnersRef = useRef42(removeWinners);
|
|
33884
33895
|
const tickAudioRef = useRef42(null);
|
|
33885
33896
|
const winAudioRef = useRef42(null);
|
|
33886
33897
|
const containerRef = useRef42(null);
|
|
@@ -33919,10 +33930,27 @@ function RandomPlayerPicker({
|
|
|
33919
33930
|
winAudioRef.current = null;
|
|
33920
33931
|
};
|
|
33921
33932
|
}, [winSoundUrl, soundVolume]);
|
|
33933
|
+
useEffect57(() => {
|
|
33934
|
+
removeWinnersRef.current = removeWinners;
|
|
33935
|
+
}, [removeWinners]);
|
|
33922
33936
|
useEffect57(() => {
|
|
33923
33937
|
const ids = participants.map((p) => p.id).join("|");
|
|
33924
33938
|
const structuralChange = ids !== prevIdsRef.current;
|
|
33925
33939
|
if (structuralChange) {
|
|
33940
|
+
if (winnerTimer.current) {
|
|
33941
|
+
clearTimeout(winnerTimer.current);
|
|
33942
|
+
winnerTimer.current = null;
|
|
33943
|
+
}
|
|
33944
|
+
if (tickInterval.current) {
|
|
33945
|
+
clearTimeout(tickInterval.current);
|
|
33946
|
+
tickInterval.current = null;
|
|
33947
|
+
}
|
|
33948
|
+
if (popTimer.current) {
|
|
33949
|
+
clearTimeout(popTimer.current);
|
|
33950
|
+
popTimer.current = null;
|
|
33951
|
+
}
|
|
33952
|
+
pendingPopIdxRef.current = null;
|
|
33953
|
+
setSpinning(false);
|
|
33926
33954
|
setPool(participants);
|
|
33927
33955
|
setHistory([]);
|
|
33928
33956
|
setWinner(null);
|
|
@@ -33979,33 +34007,50 @@ function RandomPlayerPicker({
|
|
|
33979
34007
|
[dark]
|
|
33980
34008
|
);
|
|
33981
34009
|
const spin = useCallback47(() => {
|
|
33982
|
-
if (spinning
|
|
34010
|
+
if (spinning) return;
|
|
34011
|
+
let activePool = pool;
|
|
34012
|
+
if (popTimer.current) {
|
|
34013
|
+
clearTimeout(popTimer.current);
|
|
34014
|
+
popTimer.current = null;
|
|
34015
|
+
const pendingIdx = pendingPopIdxRef.current;
|
|
34016
|
+
pendingPopIdxRef.current = null;
|
|
34017
|
+
if (pendingIdx != null && pendingIdx >= 0 && pendingIdx < pool.length && removeWinnersRef.current) {
|
|
34018
|
+
activePool = pool.filter((_, i) => i !== pendingIdx);
|
|
34019
|
+
setPool(activePool);
|
|
34020
|
+
setWinner(null);
|
|
34021
|
+
}
|
|
34022
|
+
}
|
|
34023
|
+
const activeN = activePool.length;
|
|
34024
|
+
if (activeN < 2) return;
|
|
34025
|
+
const activeAnglePerWedge = 2 * Math.PI / activeN;
|
|
34026
|
+
const activeRotation = rotation;
|
|
34027
|
+
const activeReelY = reelY;
|
|
33983
34028
|
onSpinStart?.();
|
|
33984
|
-
const winnerIdx = weightedIndex(
|
|
34029
|
+
const winnerIdx = weightedIndex(activePool);
|
|
33985
34030
|
const minRev = minRevolutions + intensityCfg.revsBoost;
|
|
33986
34031
|
const maxRev = maxRevolutions + intensityCfg.revsBoost;
|
|
33987
34032
|
const minFullRevs = Math.ceil(minRev);
|
|
33988
34033
|
const maxFullRevs = Math.max(minFullRevs, Math.floor(maxRev));
|
|
33989
34034
|
const revolutions = minFullRevs + Math.floor(Math.random() * (maxFullRevs - minFullRevs + 1));
|
|
33990
|
-
const wedgeMidRad = winnerIdx *
|
|
34035
|
+
const wedgeMidRad = winnerIdx * activeAnglePerWedge + activeAnglePerWedge / 2;
|
|
33991
34036
|
const wedgeMidDeg = wedgeMidRad * 180 / Math.PI;
|
|
33992
|
-
const wheelWobble = (Math.random() - 0.5) * (
|
|
33993
|
-
const currentMod = (
|
|
34037
|
+
const wheelWobble = (Math.random() - 0.5) * (activeAnglePerWedge * 180 / Math.PI) * 0.6;
|
|
34038
|
+
const currentMod = (activeRotation % 360 + 360) % 360;
|
|
33994
34039
|
const targetMod = ((-wedgeMidDeg + wheelWobble) % 360 + 360) % 360;
|
|
33995
34040
|
let deltaMod = targetMod - currentMod;
|
|
33996
34041
|
if (deltaMod < 0) deltaMod += 360;
|
|
33997
|
-
const finalRotation =
|
|
34042
|
+
const finalRotation = activeRotation + deltaMod + revolutions * 360;
|
|
33998
34043
|
const centerOffsetRows = (reelVisibleRows - 1) / 2;
|
|
33999
34044
|
const centerOffsetPx = centerOffsetRows * reelRowHeight;
|
|
34000
34045
|
const currentCenterRow = Math.round(
|
|
34001
|
-
(
|
|
34046
|
+
(activeReelY + centerOffsetPx) / reelRowHeight
|
|
34002
34047
|
);
|
|
34003
|
-
const currentCenterMod = mod(currentCenterRow,
|
|
34004
|
-
const targetRowOffset = (winnerIdx - currentCenterMod +
|
|
34005
|
-
const reelRevRows = Math.round(revolutions *
|
|
34006
|
-
const finalReelY =
|
|
34007
|
-
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight,
|
|
34008
|
-
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx <
|
|
34048
|
+
const currentCenterMod = mod(currentCenterRow, activeN);
|
|
34049
|
+
const targetRowOffset = (winnerIdx - currentCenterMod + activeN) % activeN;
|
|
34050
|
+
const reelRevRows = Math.round(revolutions * activeN);
|
|
34051
|
+
const finalReelY = activeReelY + (reelRevRows + targetRowOffset) * reelRowHeight;
|
|
34052
|
+
const settledWinnerIdx = mode === "reel" ? reelIndexAtCenter(finalReelY, centerOffsetPx, reelRowHeight, activeN) : wheelIndexAtPointer(finalRotation, activeN);
|
|
34053
|
+
const finalWinnerIdx = settledWinnerIdx >= 0 && settledWinnerIdx < activePool.length ? settledWinnerIdx : winnerIdx;
|
|
34009
34054
|
const effectiveDuration = reducedMotion ? 250 : Math.round(spinDuration * intensityCfg.durationMult);
|
|
34010
34055
|
setSpinning(true);
|
|
34011
34056
|
setWinner(null);
|
|
@@ -34018,7 +34063,7 @@ function RandomPlayerPicker({
|
|
|
34018
34063
|
if ((onTick || tickAudioRef.current) && !reducedMotion) {
|
|
34019
34064
|
const wedges = mode === "reel" ? Math.max(1, reelRevRows + targetRowOffset) : (() => {
|
|
34020
34065
|
const totalDelta = deltaMod + revolutions * 360;
|
|
34021
|
-
const wedgeDeg =
|
|
34066
|
+
const wedgeDeg = activeAnglePerWedge * 180 / Math.PI;
|
|
34022
34067
|
return Math.max(
|
|
34023
34068
|
1,
|
|
34024
34069
|
Math.round(totalDelta / Math.max(wedgeDeg, 1))
|
|
@@ -34050,7 +34095,7 @@ function RandomPlayerPicker({
|
|
|
34050
34095
|
schedule();
|
|
34051
34096
|
}
|
|
34052
34097
|
winnerTimer.current = setTimeout(() => {
|
|
34053
|
-
const picked =
|
|
34098
|
+
const picked = activePool[finalWinnerIdx];
|
|
34054
34099
|
if (!picked) {
|
|
34055
34100
|
setSpinning(false);
|
|
34056
34101
|
return;
|
|
@@ -34096,7 +34141,11 @@ function RandomPlayerPicker({
|
|
|
34096
34141
|
particleTimer.current = setTimeout(() => setParticles([]), 2400);
|
|
34097
34142
|
}
|
|
34098
34143
|
if (removeWinners) {
|
|
34144
|
+
pendingPopIdxRef.current = finalWinnerIdx;
|
|
34099
34145
|
popTimer.current = setTimeout(() => {
|
|
34146
|
+
popTimer.current = null;
|
|
34147
|
+
pendingPopIdxRef.current = null;
|
|
34148
|
+
if (!removeWinnersRef.current) return;
|
|
34100
34149
|
setPool((p) => p.filter((_, i) => i !== finalWinnerIdx));
|
|
34101
34150
|
setWinner(null);
|
|
34102
34151
|
setRotation(0);
|
|
@@ -34107,8 +34156,6 @@ function RandomPlayerPicker({
|
|
|
34107
34156
|
}, [
|
|
34108
34157
|
pool,
|
|
34109
34158
|
spinning,
|
|
34110
|
-
n,
|
|
34111
|
-
anglePerWedge,
|
|
34112
34159
|
rotation,
|
|
34113
34160
|
reelY,
|
|
34114
34161
|
mode,
|
|
@@ -34144,6 +34191,7 @@ function RandomPlayerPicker({
|
|
|
34144
34191
|
[]
|
|
34145
34192
|
);
|
|
34146
34193
|
useEffect57(() => {
|
|
34194
|
+
if (trigger === "external") return;
|
|
34147
34195
|
const el = containerRef.current;
|
|
34148
34196
|
if (!el) return;
|
|
34149
34197
|
const h = (e) => {
|
|
@@ -34154,8 +34202,22 @@ function RandomPlayerPicker({
|
|
|
34154
34202
|
};
|
|
34155
34203
|
el.addEventListener("keydown", h);
|
|
34156
34204
|
return () => el.removeEventListener("keydown", h);
|
|
34157
|
-
}, [spin]);
|
|
34205
|
+
}, [spin, trigger]);
|
|
34158
34206
|
const reset = useCallback47(() => {
|
|
34207
|
+
if (winnerTimer.current) {
|
|
34208
|
+
clearTimeout(winnerTimer.current);
|
|
34209
|
+
winnerTimer.current = null;
|
|
34210
|
+
}
|
|
34211
|
+
if (tickInterval.current) {
|
|
34212
|
+
clearTimeout(tickInterval.current);
|
|
34213
|
+
tickInterval.current = null;
|
|
34214
|
+
}
|
|
34215
|
+
if (popTimer.current) {
|
|
34216
|
+
clearTimeout(popTimer.current);
|
|
34217
|
+
popTimer.current = null;
|
|
34218
|
+
}
|
|
34219
|
+
pendingPopIdxRef.current = null;
|
|
34220
|
+
setSpinning(false);
|
|
34159
34221
|
setPool(participants);
|
|
34160
34222
|
setHistory([]);
|
|
34161
34223
|
setWinner(null);
|
|
@@ -38628,27 +38690,28 @@ function GameTimer({
|
|
|
38628
38690
|
const now = performance.now();
|
|
38629
38691
|
const delta = now - lastTickRef.current;
|
|
38630
38692
|
lastTickRef.current = now;
|
|
38631
|
-
|
|
38632
|
-
|
|
38633
|
-
|
|
38634
|
-
|
|
38635
|
-
|
|
38636
|
-
|
|
38637
|
-
|
|
38693
|
+
const next = elapsedRef.current + delta;
|
|
38694
|
+
if (mode === "countdown" && next >= durationMs) {
|
|
38695
|
+
elapsedRef.current = durationMs;
|
|
38696
|
+
setElapsedMs(durationMs);
|
|
38697
|
+
setRunning(false);
|
|
38698
|
+
setCompleted(true);
|
|
38699
|
+
onComplete?.();
|
|
38700
|
+
return;
|
|
38701
|
+
}
|
|
38702
|
+
if (mode === "countdown") {
|
|
38703
|
+
const secLeft = Math.ceil((durationMs - next) / 1e3);
|
|
38704
|
+
if (secLeft <= warningAt && !warningFiredRef.current) {
|
|
38705
|
+
warningFiredRef.current = true;
|
|
38706
|
+
onWarning?.();
|
|
38638
38707
|
}
|
|
38639
|
-
if (
|
|
38640
|
-
|
|
38641
|
-
|
|
38642
|
-
warningFiredRef.current = true;
|
|
38643
|
-
onWarning?.();
|
|
38644
|
-
}
|
|
38645
|
-
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38646
|
-
dangerFiredRef.current = true;
|
|
38647
|
-
onDanger?.();
|
|
38648
|
-
}
|
|
38708
|
+
if (secLeft <= dangerAt && !dangerFiredRef.current) {
|
|
38709
|
+
dangerFiredRef.current = true;
|
|
38710
|
+
onDanger?.();
|
|
38649
38711
|
}
|
|
38650
|
-
|
|
38651
|
-
|
|
38712
|
+
}
|
|
38713
|
+
elapsedRef.current = next;
|
|
38714
|
+
setElapsedMs(next);
|
|
38652
38715
|
rafRef.current = requestAnimationFrame(tick);
|
|
38653
38716
|
}, [mode, durationMs, warningAt, dangerAt, onComplete, onWarning, onDanger]);
|
|
38654
38717
|
useEffect61(() => {
|
|
@@ -38669,6 +38732,7 @@ function GameTimer({
|
|
|
38669
38732
|
}, []);
|
|
38670
38733
|
const reset = useCallback51(() => {
|
|
38671
38734
|
setRunning(false);
|
|
38735
|
+
elapsedRef.current = 0;
|
|
38672
38736
|
setElapsedMs(0);
|
|
38673
38737
|
setCompleted(false);
|
|
38674
38738
|
setLaps([]);
|
|
@@ -40830,6 +40894,8 @@ function RoundRobinScheduler({
|
|
|
40830
40894
|
theme: theme5 = "slate",
|
|
40831
40895
|
darkMode,
|
|
40832
40896
|
minTeams = 3,
|
|
40897
|
+
maxTeams,
|
|
40898
|
+
nameMaxLength,
|
|
40833
40899
|
defaultTeams = [],
|
|
40834
40900
|
resumeRounds,
|
|
40835
40901
|
onTeamsChange,
|
|
@@ -40852,39 +40918,41 @@ function RoundRobinScheduler({
|
|
|
40852
40918
|
useEffect64(() => {
|
|
40853
40919
|
onTeamsChange?.(teams);
|
|
40854
40920
|
}, [teams, onTeamsChange]);
|
|
40855
|
-
const
|
|
40856
|
-
|
|
40857
|
-
if (names.length === 0) return;
|
|
40858
|
-
setTeams((prev) => {
|
|
40859
|
-
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40860
|
-
const next = [...prev];
|
|
40861
|
-
for (const name of names) {
|
|
40862
|
-
if (!existing.has(name.toLowerCase())) {
|
|
40863
|
-
existing.add(name.toLowerCase());
|
|
40864
|
-
next.push(name);
|
|
40865
|
-
}
|
|
40866
|
-
}
|
|
40867
|
-
return next;
|
|
40868
|
-
});
|
|
40869
|
-
setInput("");
|
|
40870
|
-
setRounds([]);
|
|
40871
|
-
}, []);
|
|
40872
|
-
const importTeams = useCallback54((incoming) => {
|
|
40873
|
-
if (incoming.length === 0) return;
|
|
40874
|
-
setTeams((prev) => {
|
|
40921
|
+
const mergeNames = useCallback54(
|
|
40922
|
+
(prev, incoming) => {
|
|
40875
40923
|
const existing = new Set(prev.map((t) => t.toLowerCase()));
|
|
40876
40924
|
const next = [...prev];
|
|
40877
|
-
for (const
|
|
40925
|
+
for (const rawName of incoming) {
|
|
40926
|
+
if (maxTeams != null && next.length >= maxTeams) break;
|
|
40927
|
+
const name = nameMaxLength != null ? rawName.slice(0, nameMaxLength) : rawName;
|
|
40878
40928
|
const key = name.toLowerCase();
|
|
40879
|
-
if (!existing.has(key)) {
|
|
40929
|
+
if (name.length > 0 && !existing.has(key)) {
|
|
40880
40930
|
existing.add(key);
|
|
40881
40931
|
next.push(name);
|
|
40882
40932
|
}
|
|
40883
40933
|
}
|
|
40884
40934
|
return next;
|
|
40885
|
-
}
|
|
40886
|
-
|
|
40887
|
-
|
|
40935
|
+
},
|
|
40936
|
+
[maxTeams, nameMaxLength]
|
|
40937
|
+
);
|
|
40938
|
+
const addTeams = useCallback54(
|
|
40939
|
+
(raw) => {
|
|
40940
|
+
const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
40941
|
+
if (names.length === 0) return;
|
|
40942
|
+
setTeams((prev) => mergeNames(prev, names));
|
|
40943
|
+
setInput("");
|
|
40944
|
+
setRounds([]);
|
|
40945
|
+
},
|
|
40946
|
+
[mergeNames]
|
|
40947
|
+
);
|
|
40948
|
+
const importTeams = useCallback54(
|
|
40949
|
+
(incoming) => {
|
|
40950
|
+
if (incoming.length === 0) return;
|
|
40951
|
+
setTeams((prev) => mergeNames(prev, incoming));
|
|
40952
|
+
setRounds([]);
|
|
40953
|
+
},
|
|
40954
|
+
[mergeNames]
|
|
40955
|
+
);
|
|
40888
40956
|
const handleKeyDown = useCallback54(
|
|
40889
40957
|
(e) => {
|
|
40890
40958
|
if (e.key === "Enter") {
|
|
@@ -41378,6 +41446,8 @@ function Scoreboard({
|
|
|
41378
41446
|
onTeamsChange,
|
|
41379
41447
|
onRoundAdvance,
|
|
41380
41448
|
onNewGame,
|
|
41449
|
+
onReset,
|
|
41450
|
+
nameMaxLength,
|
|
41381
41451
|
labels,
|
|
41382
41452
|
ariaLabel = "Scoreboard",
|
|
41383
41453
|
className
|
|
@@ -41452,7 +41522,8 @@ function Scoreboard({
|
|
|
41452
41522
|
setRound(1);
|
|
41453
41523
|
setHistory([]);
|
|
41454
41524
|
setHistoryOpen(false);
|
|
41455
|
-
|
|
41525
|
+
onReset?.();
|
|
41526
|
+
}, [onReset]);
|
|
41456
41527
|
const newGame = useCallback55(() => {
|
|
41457
41528
|
setTeams(createDefaultTeams(seedCount, L.teamNamePrefix));
|
|
41458
41529
|
setRound(1);
|
|
@@ -41674,6 +41745,7 @@ function Scoreboard({
|
|
|
41674
41745
|
{
|
|
41675
41746
|
type: "text",
|
|
41676
41747
|
value: team.name,
|
|
41748
|
+
maxLength: nameMaxLength,
|
|
41677
41749
|
onChange: (e) => updateName(index, e.target.value),
|
|
41678
41750
|
style: nameInputStyle,
|
|
41679
41751
|
"aria-label": `Team ${index + 1} name`
|