@digilogiclabs/saas-factory-ui 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31140,9 +31140,26 @@ function standardSeeding(participants) {
31140
31140
  const sorted = [...participants].sort(
31141
31141
  (a, b) => (a.seed ?? 999) - (b.seed ?? 999)
31142
31142
  );
31143
+ const n = sorted.length;
31143
31144
  const pairs = [];
31144
- for (let i = 0; i < sorted.length / 2; i++) {
31145
- pairs.push([sorted[i], sorted[sorted.length - 1 - i]]);
31145
+ if (n < 2 || (n & n - 1) !== 0) {
31146
+ for (let i = 0; i + 1 < n; i += 2) {
31147
+ pairs.push([sorted[i], sorted[i + 1]]);
31148
+ }
31149
+ return pairs;
31150
+ }
31151
+ let order = [1, 2];
31152
+ while (order.length < n) {
31153
+ const total = order.length * 2 + 1;
31154
+ const next = [];
31155
+ for (const r of order) {
31156
+ next.push(r);
31157
+ next.push(total - r);
31158
+ }
31159
+ order = next;
31160
+ }
31161
+ for (let i = 0; i < order.length; i += 2) {
31162
+ pairs.push([sorted[order[i] - 1], sorted[order[i + 1] - 1]]);
31146
31163
  }
31147
31164
  return pairs;
31148
31165
  }
@@ -31496,6 +31513,7 @@ function BracketGenerator({
31496
31513
  theme: theme5 = "blue",
31497
31514
  darkMode,
31498
31515
  seedingStrategy = "standard",
31516
+ resumeMatches,
31499
31517
  onMatchComplete,
31500
31518
  onChampion,
31501
31519
  onStateChange,
@@ -31574,6 +31592,47 @@ function BracketGenerator({
31574
31592
  );
31575
31593
  const [miniMapHidden, setMiniMapHidden] = useState68(false);
31576
31594
  const miniMapDragRef = useRef41(false);
31595
+ const resumeRef = useRef41(resumeMatches);
31596
+ const hydrateFromResume = useCallback42(() => {
31597
+ const resume = resumeRef.current;
31598
+ if (!resume?.length) return null;
31599
+ const n = effectiveParticipants.length;
31600
+ if (n < 2 || (n & n - 1) !== 0) return null;
31601
+ const rounds = Math.log2(n);
31602
+ if (resume.length !== n - 1) return null;
31603
+ const byId = new Map(effectiveParticipants.map((p) => [p.id, p]));
31604
+ const resolve = (id) => {
31605
+ if (!id) return null;
31606
+ const found = byId.get(id);
31607
+ if (found) return found;
31608
+ if (id.startsWith("__bye_")) {
31609
+ return { id, name: "BYE", seed: 999, isBye: true };
31610
+ }
31611
+ return void 0;
31612
+ };
31613
+ const matches = [];
31614
+ for (const rm of resume) {
31615
+ if (rm.round < 0 || rm.round >= rounds) return null;
31616
+ const a = resolve(rm.aId);
31617
+ const b = resolve(rm.bId);
31618
+ const winner = resolve(rm.winnerId);
31619
+ if (a === void 0 || b === void 0 || winner === void 0)
31620
+ return null;
31621
+ matches.push({
31622
+ id: rm.id,
31623
+ round: rm.round,
31624
+ slot: rm.slot,
31625
+ a,
31626
+ b,
31627
+ scoreA: rm.scoreA,
31628
+ scoreB: rm.scoreB,
31629
+ winner
31630
+ });
31631
+ }
31632
+ matches.sort((x, y) => x.round - y.round || x.slot - y.slot);
31633
+ const finalMatch = matches.find((m) => m.round === rounds - 1);
31634
+ return { matches, rounds, champion: finalMatch?.winner ?? null };
31635
+ }, [effectiveParticipants]);
31577
31636
  const seedBracket = useCallback42(() => {
31578
31637
  const { matches, rounds } = buildBracket(
31579
31638
  effectiveParticipants,
@@ -31684,12 +31743,47 @@ function BracketGenerator({
31684
31743
  onStateChange?.(next);
31685
31744
  prevBracketStateRef.current = next;
31686
31745
  }, [bracketState, onMatchComplete, onChampion, onStateChange]);
31746
+ const structuralKey = useMemo27(
31747
+ () => `${seedingStrategy}|${effectiveParticipants.map((p) => `${p.id}:${p.seed ?? ""}`).join(",")}`,
31748
+ [effectiveParticipants, seedingStrategy]
31749
+ );
31750
+ const seededKeyRef = useRef41(null);
31751
+ useEffect53(() => {
31752
+ if (seededKeyRef.current === structuralKey) {
31753
+ setBracketState((prev) => {
31754
+ if (!prev.matches.length) return prev;
31755
+ const byId = new Map(effectiveParticipants.map((p) => [p.id, p]));
31756
+ const swap = (p) => p && !p.isBye ? byId.get(p.id) ?? p : p;
31757
+ let changed = false;
31758
+ const matches = prev.matches.map((m) => {
31759
+ const a = swap(m.a);
31760
+ const b = swap(m.b);
31761
+ const winner = swap(m.winner);
31762
+ if (a === m.a && b === m.b && winner === m.winner) return m;
31763
+ changed = true;
31764
+ return { ...m, a, b, winner };
31765
+ });
31766
+ if (!changed) return prev;
31767
+ return { ...prev, matches, champion: swap(prev.champion) };
31768
+ });
31769
+ return;
31770
+ }
31771
+ seededKeyRef.current = structuralKey;
31772
+ if (autoRef.current) clearTimeout(autoRef.current);
31773
+ setSimulating(false);
31774
+ const resumed = hydrateFromResume();
31775
+ resumeRef.current = void 0;
31776
+ if (resumed) {
31777
+ setBracketState(resumed);
31778
+ } else {
31779
+ seedBracket();
31780
+ }
31781
+ }, [structuralKey, effectiveParticipants, hydrateFromResume, seedBracket]);
31687
31782
  useEffect53(() => {
31688
- seedBracket();
31689
31783
  return () => {
31690
31784
  if (autoRef.current) clearTimeout(autoRef.current);
31691
31785
  };
31692
- }, [seedBracket]);
31786
+ }, []);
31693
31787
  useLayoutEffect2(() => {
31694
31788
  if (contentSize.w > 0) {
31695
31789
  const timer = setTimeout(fit, 50);