@digilogiclabs/saas-factory-ui 2.7.1 → 2.8.1

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
@@ -30871,17 +30871,13 @@ function DiceRoller({
30871
30871
  const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
30872
30872
  const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
30873
30873
  for (let i = 0; i < clampedCount; i++) {
30874
- if (sides === 6) {
30875
- writeCubeRotation(
30876
- i,
30877
- (Math.random() - 0.5) * 720,
30878
- (Math.random() - 0.5) * 720,
30879
- (Math.random() - 0.5) * 720,
30880
- false
30881
- );
30882
- } else {
30883
- writeCubeRotation(i, 0, 0, (Math.random() - 0.5) * 720, false);
30884
- }
30874
+ writeCubeRotation(
30875
+ i,
30876
+ (Math.random() - 0.5) * 720,
30877
+ (Math.random() - 0.5) * 720,
30878
+ (Math.random() - 0.5) * 720,
30879
+ false
30880
+ );
30885
30881
  const el = dieWrapperRefs.current[i];
30886
30882
  if (el) el.style.transition = "none";
30887
30883
  const shadow = shadowRefs.current[i];
@@ -30942,8 +30938,10 @@ function DiceRoller({
30942
30938
  const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30943
30939
  writeCubeRotation(i, lx, ly, lz, true, tilt);
30944
30940
  } else {
30941
+ const lx = (Math.random() > 0.5 ? 1 : -1) * 720;
30942
+ const ly = (Math.random() > 0.5 ? 1 : -1) * 360;
30945
30943
  const lz = (Math.random() > 0.5 ? 1 : -1) * 720 + tilt;
30946
- writeCubeRotation(i, 0, 0, lz, true);
30944
+ writeCubeRotation(i, lx, ly, lz, true);
30947
30945
  }
30948
30946
  }
30949
30947
  });
@@ -31102,60 +31100,115 @@ function DiceRoller({
31102
31100
  )) : (() => {
31103
31101
  const shape = POLY_SHAPES[sides];
31104
31102
  const shown = results?.[d] ?? sides;
31105
- return /* @__PURE__ */ jsxs86(
31106
- "svg",
31107
- {
31108
- viewBox: "0 0 100 100",
31109
- width: "100%",
31110
- height: "100%",
31111
- style: { display: "block", overflow: "visible" },
31112
- "aria-hidden": "true",
31113
- children: [
31114
- /* @__PURE__ */ jsx114(
31115
- "polygon",
31116
- {
31117
- points: shape.points,
31118
- fill: colors.face,
31119
- stroke: colors.faceBorder,
31120
- strokeWidth: 2.5,
31121
- strokeLinejoin: "round",
31122
- style: { transition: "fill 0.3s, stroke 0.3s" }
31123
- }
31124
- ),
31125
- /* @__PURE__ */ jsx114(
31126
- "polygon",
31127
- {
31128
- points: shape.points,
31129
- fill: "none",
31130
- stroke: colors.faceBorder,
31131
- strokeWidth: 1.5,
31132
- strokeLinejoin: "round",
31133
- opacity: 0.55,
31134
- transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31135
- }
31136
- ),
31137
- /* @__PURE__ */ jsx114(
31138
- "text",
31139
- {
31140
- ref: getNumeralSetter(d),
31141
- x: 50,
31142
- y: shape.textY,
31143
- textAnchor: "middle",
31144
- dominantBaseline: "central",
31145
- fontSize: 100 * shape.fontScale,
31146
- fontWeight: 800,
31147
- fill: colors.pip,
31148
- style: {
31149
- fontVariantNumeric: "tabular-nums",
31150
- transition: "fill 0.3s",
31151
- userSelect: "none"
31152
- },
31153
- children: formatDieValue(shown, sides)
31154
- }
31155
- )
31156
- ]
31157
- }
31158
- );
31103
+ const cardFaceStyle = {
31104
+ position: "absolute",
31105
+ inset: 0,
31106
+ display: "block",
31107
+ overflow: "visible",
31108
+ backfaceVisibility: "hidden"
31109
+ };
31110
+ return /* @__PURE__ */ jsxs86(Fragment30, { children: [
31111
+ /* @__PURE__ */ jsxs86(
31112
+ "svg",
31113
+ {
31114
+ viewBox: "0 0 100 100",
31115
+ width: "100%",
31116
+ height: "100%",
31117
+ style: cardFaceStyle,
31118
+ "aria-hidden": "true",
31119
+ children: [
31120
+ /* @__PURE__ */ jsx114(
31121
+ "polygon",
31122
+ {
31123
+ points: shape.points,
31124
+ fill: colors.face,
31125
+ stroke: colors.faceBorder,
31126
+ strokeWidth: 2.5,
31127
+ strokeLinejoin: "round",
31128
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31129
+ }
31130
+ ),
31131
+ /* @__PURE__ */ jsx114(
31132
+ "polygon",
31133
+ {
31134
+ points: shape.points,
31135
+ fill: "none",
31136
+ stroke: colors.faceBorder,
31137
+ strokeWidth: 1.5,
31138
+ strokeLinejoin: "round",
31139
+ opacity: 0.55,
31140
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31141
+ }
31142
+ ),
31143
+ /* @__PURE__ */ jsx114(
31144
+ "text",
31145
+ {
31146
+ ref: getNumeralSetter(d),
31147
+ x: 50,
31148
+ y: shape.textY,
31149
+ textAnchor: "middle",
31150
+ dominantBaseline: "central",
31151
+ fontSize: 100 * shape.fontScale,
31152
+ fontWeight: 800,
31153
+ fill: colors.pip,
31154
+ style: {
31155
+ fontVariantNumeric: "tabular-nums",
31156
+ transition: "fill 0.3s",
31157
+ userSelect: "none"
31158
+ },
31159
+ children: formatDieValue(shown, sides)
31160
+ }
31161
+ )
31162
+ ]
31163
+ }
31164
+ ),
31165
+ /* @__PURE__ */ jsxs86(
31166
+ "svg",
31167
+ {
31168
+ viewBox: "0 0 100 100",
31169
+ width: "100%",
31170
+ height: "100%",
31171
+ style: {
31172
+ ...cardFaceStyle,
31173
+ transform: "rotateY(180deg)"
31174
+ },
31175
+ "aria-hidden": "true",
31176
+ children: [
31177
+ /* @__PURE__ */ jsx114(
31178
+ "polygon",
31179
+ {
31180
+ points: shape.points,
31181
+ fill: colors.face,
31182
+ stroke: colors.faceBorder,
31183
+ strokeWidth: 2.5,
31184
+ strokeLinejoin: "round",
31185
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31186
+ }
31187
+ ),
31188
+ /* @__PURE__ */ jsx114(
31189
+ "polygon",
31190
+ {
31191
+ points: shape.points,
31192
+ fill: "none",
31193
+ stroke: colors.faceBorder,
31194
+ strokeWidth: 1.5,
31195
+ strokeLinejoin: "round",
31196
+ opacity: 0.55,
31197
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31198
+ }
31199
+ ),
31200
+ /* @__PURE__ */ jsx114(
31201
+ "polygon",
31202
+ {
31203
+ points: shape.points,
31204
+ fill: "#000",
31205
+ opacity: 0.14
31206
+ }
31207
+ )
31208
+ ]
31209
+ }
31210
+ )
31211
+ ] });
31159
31212
  })()
31160
31213
  }
31161
31214
  )
@@ -31910,32 +31963,26 @@ function BracketGenerator({
31910
31963
  const autoPlay = useCallback45(() => {
31911
31964
  if (simulating) {
31912
31965
  if (autoRef.current) clearTimeout(autoRef.current);
31966
+ autoRef.current = null;
31913
31967
  setSimulating(false);
31914
31968
  return;
31915
31969
  }
31916
31970
  setSimulating(true);
31917
- const tick = () => {
31918
- setBracketState((prev) => {
31919
- const next = prev.matches.find((m) => m.a && m.b && !m.winner);
31920
- if (!next) {
31921
- setSimulating(false);
31922
- return prev;
31923
- }
31924
- const completed = simulateMatch(next);
31925
- if (!completed) return prev;
31926
- let matches = prev.matches.map(
31927
- (m) => m.id === completed.id ? completed : m
31928
- );
31929
- matches = propagateWinner(matches, completed);
31930
- const finalMatch = matches.find((m) => m.round === prev.rounds - 1);
31931
- const champion = finalMatch?.winner || null;
31932
- if (!champion) autoRef.current = setTimeout(tick, simulateDelayMs);
31933
- else setSimulating(false);
31934
- return { ...prev, matches, champion };
31935
- });
31971
+ simulateNext();
31972
+ }, [simulating, simulateNext]);
31973
+ useEffect55(() => {
31974
+ if (!simulating) return;
31975
+ const hasNext = bracketState.matches.some((m) => m.a && m.b && !m.winner);
31976
+ if (bracketState.champion || !hasNext) {
31977
+ setSimulating(false);
31978
+ return;
31979
+ }
31980
+ autoRef.current = setTimeout(simulateNext, simulateDelayMs);
31981
+ return () => {
31982
+ if (autoRef.current) clearTimeout(autoRef.current);
31983
+ autoRef.current = null;
31936
31984
  };
31937
- tick();
31938
- }, [simulating, simulateDelayMs]);
31985
+ }, [simulating, bracketState, simulateDelayMs, simulateNext]);
31939
31986
  const advanceWinner = useCallback45(
31940
31987
  (matchId, winnerSlot) => {
31941
31988
  setBracketState((prev) => {
@@ -39770,8 +39817,8 @@ function RosterImport({
39770
39817
  maxNames,
39771
39818
  maxFileBytes,
39772
39819
  onClose: () => setOpen(false),
39773
- onImport: (names) => {
39774
- onImport(names);
39820
+ onImport: (names, info) => {
39821
+ onImport(names, info);
39775
39822
  setOpen(false);
39776
39823
  }
39777
39824
  }
@@ -39837,6 +39884,11 @@ function RosterImportModal({
39837
39884
  }),
39838
39885
  [table, column, skipHeader, maxNames]
39839
39886
  );
39887
+ const extractedTotal = useMemo36(
39888
+ () => extractRoster(table, { column, skipHeader }),
39889
+ [table, column, skipHeader]
39890
+ );
39891
+ const trimmedCount = Math.max(0, extractedTotal.length - extracted.length);
39840
39892
  const handleFile = useCallback52(
39841
39893
  async (e) => {
39842
39894
  setFileError(null);
@@ -40214,7 +40266,10 @@ function RosterImportModal({
40214
40266
  "button",
40215
40267
  {
40216
40268
  type: "button",
40217
- onClick: () => onImport(extracted),
40269
+ onClick: () => onImport(extracted, {
40270
+ trimmedCount,
40271
+ totalCount: extractedTotal.length
40272
+ }),
40218
40273
  disabled: !canImport,
40219
40274
  style: primaryBtn(!canImport),
40220
40275
  children: confirmLabel
@@ -40418,6 +40473,19 @@ function IconUsers({ size = 40 }) {
40418
40473
  }
40419
40474
  );
40420
40475
  }
40476
+ function mergeNames(prev, incoming, max) {
40477
+ const seen = new Set(prev.map((n) => n.toLowerCase()));
40478
+ const room = Math.max(0, max - prev.length);
40479
+ const deduped = [];
40480
+ for (const n of incoming) {
40481
+ const key = n.toLowerCase();
40482
+ if (seen.has(key)) continue;
40483
+ seen.add(key);
40484
+ deduped.push(n);
40485
+ if (deduped.length >= room) break;
40486
+ }
40487
+ return deduped.length > 0 ? [...prev, ...deduped] : prev;
40488
+ }
40421
40489
  function splitIntoTeams(names, count2) {
40422
40490
  const shuffled = shuffle(names);
40423
40491
  const teams = Array.from({ length: count2 }, () => []);
@@ -40491,29 +40559,14 @@ function TeamGenerator({
40491
40559
  const trimmed = input.trim();
40492
40560
  if (!trimmed) return;
40493
40561
  const newNames = trimmed.split(/[,\n]+/).map((n) => n.trim()).filter((n) => n.length > 0);
40494
- setNames((prev) => {
40495
- const room = Math.max(0, maxPlayers - prev.length);
40496
- return [...prev, ...newNames.slice(0, room)];
40497
- });
40562
+ setNames((prev) => mergeNames(prev, newNames, maxPlayers));
40498
40563
  setInput("");
40499
40564
  inputRef.current?.focus();
40500
40565
  }, [input, maxPlayers]);
40501
40566
  const importNames = useCallback53(
40502
40567
  (incoming) => {
40503
40568
  if (incoming.length === 0) return;
40504
- setNames((prev) => {
40505
- const seen = new Set(prev.map((n) => n.toLowerCase()));
40506
- const room = Math.max(0, maxPlayers - prev.length);
40507
- const deduped = [];
40508
- for (const n of incoming) {
40509
- const key = n.toLowerCase();
40510
- if (seen.has(key)) continue;
40511
- seen.add(key);
40512
- deduped.push(n);
40513
- if (deduped.length >= room) break;
40514
- }
40515
- return deduped.length > 0 ? [...prev, ...deduped] : prev;
40516
- });
40569
+ setNames((prev) => mergeNames(prev, incoming, maxPlayers));
40517
40570
  },
40518
40571
  [maxPlayers]
40519
40572
  );
@@ -41138,7 +41191,7 @@ function RoundRobinScheduler({
41138
41191
  useEffect64(() => {
41139
41192
  onTeamsChange?.(teams);
41140
41193
  }, [teams, onTeamsChange]);
41141
- const mergeNames = useCallback54(
41194
+ const mergeNames2 = useCallback54(
41142
41195
  (prev, incoming) => {
41143
41196
  const existing = new Set(prev.map((t) => t.toLowerCase()));
41144
41197
  const next = [...prev];
@@ -41164,20 +41217,20 @@ function RoundRobinScheduler({
41164
41217
  const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
41165
41218
  if (names.length === 0) return;
41166
41219
  if (!gateDiscard("add")) return;
41167
- setTeams((prev) => mergeNames(prev, names));
41220
+ setTeams((prev) => mergeNames2(prev, names));
41168
41221
  setInput("");
41169
41222
  setRounds([]);
41170
41223
  },
41171
- [mergeNames, gateDiscard]
41224
+ [mergeNames2, gateDiscard]
41172
41225
  );
41173
41226
  const importTeams = useCallback54(
41174
41227
  (incoming) => {
41175
41228
  if (incoming.length === 0) return;
41176
41229
  if (!gateDiscard("import")) return;
41177
- setTeams((prev) => mergeNames(prev, incoming));
41230
+ setTeams((prev) => mergeNames2(prev, incoming));
41178
41231
  setRounds([]);
41179
41232
  },
41180
- [mergeNames, gateDiscard]
41233
+ [mergeNames2, gateDiscard]
41181
41234
  );
41182
41235
  const handleKeyDown = useCallback54(
41183
41236
  (e) => {
@@ -41682,6 +41735,8 @@ function Scoreboard({
41682
41735
  onBeforeReset,
41683
41736
  onBeforeNewGame,
41684
41737
  nameMaxLength,
41738
+ scoreMin = -9999,
41739
+ scoreMax = 9999,
41685
41740
  labels,
41686
41741
  ariaLabel = "Scoreboard",
41687
41742
  className
@@ -41725,11 +41780,19 @@ function Scoreboard({
41725
41780
  useEffect65(() => {
41726
41781
  onTeamsChange?.(teams);
41727
41782
  }, [teams, onTeamsChange]);
41728
- const updateScore = useCallback55((index, delta) => {
41729
- setTeams(
41730
- (prev) => prev.map((t, i) => i === index ? { ...t, score: t.score + delta } : t)
41731
- );
41732
- }, []);
41783
+ const updateScore = useCallback55(
41784
+ (index, delta) => {
41785
+ setTeams(
41786
+ (prev) => prev.map(
41787
+ (t, i) => i === index ? {
41788
+ ...t,
41789
+ score: Math.min(scoreMax, Math.max(scoreMin, t.score + delta))
41790
+ } : t
41791
+ )
41792
+ );
41793
+ },
41794
+ [scoreMin, scoreMax]
41795
+ );
41733
41796
  const updateName = useCallback55((index, name) => {
41734
41797
  setTeams((prev) => prev.map((t, i) => i === index ? { ...t, name } : t));
41735
41798
  }, []);