@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.
package/dist/index.mjs CHANGED
@@ -31237,9 +31237,26 @@ function standardSeeding(participants) {
31237
31237
  const sorted = [...participants].sort(
31238
31238
  (a, b) => (a.seed ?? 999) - (b.seed ?? 999)
31239
31239
  );
31240
+ const n = sorted.length;
31240
31241
  const pairs = [];
31241
- for (let i = 0; i < sorted.length / 2; i++) {
31242
- pairs.push([sorted[i], sorted[sorted.length - 1 - i]]);
31242
+ if (n < 2 || (n & n - 1) !== 0) {
31243
+ for (let i = 0; i + 1 < n; i += 2) {
31244
+ pairs.push([sorted[i], sorted[i + 1]]);
31245
+ }
31246
+ return pairs;
31247
+ }
31248
+ let order = [1, 2];
31249
+ while (order.length < n) {
31250
+ const total = order.length * 2 + 1;
31251
+ const next = [];
31252
+ for (const r of order) {
31253
+ next.push(r);
31254
+ next.push(total - r);
31255
+ }
31256
+ order = next;
31257
+ }
31258
+ for (let i = 0; i < order.length; i += 2) {
31259
+ pairs.push([sorted[order[i] - 1], sorted[order[i + 1] - 1]]);
31243
31260
  }
31244
31261
  return pairs;
31245
31262
  }
@@ -31593,6 +31610,7 @@ function BracketGenerator({
31593
31610
  theme: theme5 = "blue",
31594
31611
  darkMode,
31595
31612
  seedingStrategy = "standard",
31613
+ resumeMatches,
31596
31614
  onMatchComplete,
31597
31615
  onChampion,
31598
31616
  onStateChange,
@@ -31671,6 +31689,47 @@ function BracketGenerator({
31671
31689
  );
31672
31690
  const [miniMapHidden, setMiniMapHidden] = useState71(false);
31673
31691
  const miniMapDragRef = useRef40(false);
31692
+ const resumeRef = useRef40(resumeMatches);
31693
+ const hydrateFromResume = useCallback45(() => {
31694
+ const resume = resumeRef.current;
31695
+ if (!resume?.length) return null;
31696
+ const n = effectiveParticipants.length;
31697
+ if (n < 2 || (n & n - 1) !== 0) return null;
31698
+ const rounds = Math.log2(n);
31699
+ if (resume.length !== n - 1) return null;
31700
+ const byId = new Map(effectiveParticipants.map((p) => [p.id, p]));
31701
+ const resolve = (id) => {
31702
+ if (!id) return null;
31703
+ const found = byId.get(id);
31704
+ if (found) return found;
31705
+ if (id.startsWith("__bye_")) {
31706
+ return { id, name: "BYE", seed: 999, isBye: true };
31707
+ }
31708
+ return void 0;
31709
+ };
31710
+ const matches = [];
31711
+ for (const rm of resume) {
31712
+ if (rm.round < 0 || rm.round >= rounds) return null;
31713
+ const a = resolve(rm.aId);
31714
+ const b = resolve(rm.bId);
31715
+ const winner = resolve(rm.winnerId);
31716
+ if (a === void 0 || b === void 0 || winner === void 0)
31717
+ return null;
31718
+ matches.push({
31719
+ id: rm.id,
31720
+ round: rm.round,
31721
+ slot: rm.slot,
31722
+ a,
31723
+ b,
31724
+ scoreA: rm.scoreA,
31725
+ scoreB: rm.scoreB,
31726
+ winner
31727
+ });
31728
+ }
31729
+ matches.sort((x, y) => x.round - y.round || x.slot - y.slot);
31730
+ const finalMatch = matches.find((m) => m.round === rounds - 1);
31731
+ return { matches, rounds, champion: finalMatch?.winner ?? null };
31732
+ }, [effectiveParticipants]);
31674
31733
  const seedBracket = useCallback45(() => {
31675
31734
  const { matches, rounds } = buildBracket(
31676
31735
  effectiveParticipants,
@@ -31781,12 +31840,47 @@ function BracketGenerator({
31781
31840
  onStateChange?.(next);
31782
31841
  prevBracketStateRef.current = next;
31783
31842
  }, [bracketState, onMatchComplete, onChampion, onStateChange]);
31843
+ const structuralKey = useMemo29(
31844
+ () => `${seedingStrategy}|${effectiveParticipants.map((p) => `${p.id}:${p.seed ?? ""}`).join(",")}`,
31845
+ [effectiveParticipants, seedingStrategy]
31846
+ );
31847
+ const seededKeyRef = useRef40(null);
31848
+ useEffect55(() => {
31849
+ if (seededKeyRef.current === structuralKey) {
31850
+ setBracketState((prev) => {
31851
+ if (!prev.matches.length) return prev;
31852
+ const byId = new Map(effectiveParticipants.map((p) => [p.id, p]));
31853
+ const swap = (p) => p && !p.isBye ? byId.get(p.id) ?? p : p;
31854
+ let changed = false;
31855
+ const matches = prev.matches.map((m) => {
31856
+ const a = swap(m.a);
31857
+ const b = swap(m.b);
31858
+ const winner = swap(m.winner);
31859
+ if (a === m.a && b === m.b && winner === m.winner) return m;
31860
+ changed = true;
31861
+ return { ...m, a, b, winner };
31862
+ });
31863
+ if (!changed) return prev;
31864
+ return { ...prev, matches, champion: swap(prev.champion) };
31865
+ });
31866
+ return;
31867
+ }
31868
+ seededKeyRef.current = structuralKey;
31869
+ if (autoRef.current) clearTimeout(autoRef.current);
31870
+ setSimulating(false);
31871
+ const resumed = hydrateFromResume();
31872
+ resumeRef.current = void 0;
31873
+ if (resumed) {
31874
+ setBracketState(resumed);
31875
+ } else {
31876
+ seedBracket();
31877
+ }
31878
+ }, [structuralKey, effectiveParticipants, hydrateFromResume, seedBracket]);
31784
31879
  useEffect55(() => {
31785
- seedBracket();
31786
31880
  return () => {
31787
31881
  if (autoRef.current) clearTimeout(autoRef.current);
31788
31882
  };
31789
- }, [seedBracket]);
31883
+ }, []);
31790
31884
  useLayoutEffect2(() => {
31791
31885
  if (contentSize.w > 0) {
31792
31886
  const timer = setTimeout(fit, 50);