@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/web/index.js CHANGED
@@ -30754,17 +30754,13 @@ function DiceRoller({
30754
30754
  const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
30755
30755
  const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
30756
30756
  for (let i = 0; i < clampedCount; i++) {
30757
- if (sides === 6) {
30758
- writeCubeRotation(
30759
- i,
30760
- (Math.random() - 0.5) * 720,
30761
- (Math.random() - 0.5) * 720,
30762
- (Math.random() - 0.5) * 720,
30763
- false
30764
- );
30765
- } else {
30766
- writeCubeRotation(i, 0, 0, (Math.random() - 0.5) * 720, false);
30767
- }
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
+ );
30768
30764
  const el = dieWrapperRefs.current[i];
30769
30765
  if (el) el.style.transition = "none";
30770
30766
  const shadow = shadowRefs.current[i];
@@ -30825,8 +30821,10 @@ function DiceRoller({
30825
30821
  const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30826
30822
  writeCubeRotation(i, lx, ly, lz, true, tilt);
30827
30823
  } else {
30824
+ const lx = (Math.random() > 0.5 ? 1 : -1) * 720;
30825
+ const ly = (Math.random() > 0.5 ? 1 : -1) * 360;
30828
30826
  const lz = (Math.random() > 0.5 ? 1 : -1) * 720 + tilt;
30829
- writeCubeRotation(i, 0, 0, lz, true);
30827
+ writeCubeRotation(i, lx, ly, lz, true);
30830
30828
  }
30831
30829
  }
30832
30830
  });
@@ -30985,60 +30983,115 @@ function DiceRoller({
30985
30983
  )) : (() => {
30986
30984
  const shape = POLY_SHAPES[sides];
30987
30985
  const shown = results?.[d] ?? sides;
30988
- return /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(
30989
- "svg",
30990
- {
30991
- viewBox: "0 0 100 100",
30992
- width: "100%",
30993
- height: "100%",
30994
- style: { display: "block", overflow: "visible" },
30995
- "aria-hidden": "true",
30996
- children: [
30997
- /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
30998
- "polygon",
30999
- {
31000
- points: shape.points,
31001
- fill: colors.face,
31002
- stroke: colors.faceBorder,
31003
- strokeWidth: 2.5,
31004
- strokeLinejoin: "round",
31005
- style: { transition: "fill 0.3s, stroke 0.3s" }
31006
- }
31007
- ),
31008
- /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31009
- "polygon",
31010
- {
31011
- points: shape.points,
31012
- fill: "none",
31013
- stroke: colors.faceBorder,
31014
- strokeWidth: 1.5,
31015
- strokeLinejoin: "round",
31016
- opacity: 0.55,
31017
- transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31018
- }
31019
- ),
31020
- /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31021
- "text",
31022
- {
31023
- ref: getNumeralSetter(d),
31024
- x: 50,
31025
- y: shape.textY,
31026
- textAnchor: "middle",
31027
- dominantBaseline: "central",
31028
- fontSize: 100 * shape.fontScale,
31029
- fontWeight: 800,
31030
- fill: colors.pip,
31031
- style: {
31032
- fontVariantNumeric: "tabular-nums",
31033
- transition: "fill 0.3s",
31034
- userSelect: "none"
31035
- },
31036
- children: formatDieValue(shown, sides)
31037
- }
31038
- )
31039
- ]
31040
- }
31041
- );
30986
+ const cardFaceStyle = {
30987
+ position: "absolute",
30988
+ inset: 0,
30989
+ display: "block",
30990
+ overflow: "visible",
30991
+ backfaceVisibility: "hidden"
30992
+ };
30993
+ return /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(import_jsx_runtime113.Fragment, { children: [
30994
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(
30995
+ "svg",
30996
+ {
30997
+ viewBox: "0 0 100 100",
30998
+ width: "100%",
30999
+ height: "100%",
31000
+ style: cardFaceStyle,
31001
+ "aria-hidden": "true",
31002
+ children: [
31003
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31004
+ "polygon",
31005
+ {
31006
+ points: shape.points,
31007
+ fill: colors.face,
31008
+ stroke: colors.faceBorder,
31009
+ strokeWidth: 2.5,
31010
+ strokeLinejoin: "round",
31011
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31012
+ }
31013
+ ),
31014
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31015
+ "polygon",
31016
+ {
31017
+ points: shape.points,
31018
+ fill: "none",
31019
+ stroke: colors.faceBorder,
31020
+ strokeWidth: 1.5,
31021
+ strokeLinejoin: "round",
31022
+ opacity: 0.55,
31023
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31024
+ }
31025
+ ),
31026
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31027
+ "text",
31028
+ {
31029
+ ref: getNumeralSetter(d),
31030
+ x: 50,
31031
+ y: shape.textY,
31032
+ textAnchor: "middle",
31033
+ dominantBaseline: "central",
31034
+ fontSize: 100 * shape.fontScale,
31035
+ fontWeight: 800,
31036
+ fill: colors.pip,
31037
+ style: {
31038
+ fontVariantNumeric: "tabular-nums",
31039
+ transition: "fill 0.3s",
31040
+ userSelect: "none"
31041
+ },
31042
+ children: formatDieValue(shown, sides)
31043
+ }
31044
+ )
31045
+ ]
31046
+ }
31047
+ ),
31048
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsxs)(
31049
+ "svg",
31050
+ {
31051
+ viewBox: "0 0 100 100",
31052
+ width: "100%",
31053
+ height: "100%",
31054
+ style: {
31055
+ ...cardFaceStyle,
31056
+ transform: "rotateY(180deg)"
31057
+ },
31058
+ "aria-hidden": "true",
31059
+ children: [
31060
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31061
+ "polygon",
31062
+ {
31063
+ points: shape.points,
31064
+ fill: colors.face,
31065
+ stroke: colors.faceBorder,
31066
+ strokeWidth: 2.5,
31067
+ strokeLinejoin: "round",
31068
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31069
+ }
31070
+ ),
31071
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31072
+ "polygon",
31073
+ {
31074
+ points: shape.points,
31075
+ fill: "none",
31076
+ stroke: colors.faceBorder,
31077
+ strokeWidth: 1.5,
31078
+ strokeLinejoin: "round",
31079
+ opacity: 0.55,
31080
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31081
+ }
31082
+ ),
31083
+ /* @__PURE__ */ (0, import_jsx_runtime113.jsx)(
31084
+ "polygon",
31085
+ {
31086
+ points: shape.points,
31087
+ fill: "#000",
31088
+ opacity: 0.14
31089
+ }
31090
+ )
31091
+ ]
31092
+ }
31093
+ )
31094
+ ] });
31042
31095
  })()
31043
31096
  }
31044
31097
  )
@@ -31786,32 +31839,26 @@ function BracketGenerator({
31786
31839
  const autoPlay = (0, import_react70.useCallback)(() => {
31787
31840
  if (simulating) {
31788
31841
  if (autoRef.current) clearTimeout(autoRef.current);
31842
+ autoRef.current = null;
31789
31843
  setSimulating(false);
31790
31844
  return;
31791
31845
  }
31792
31846
  setSimulating(true);
31793
- const tick = () => {
31794
- setBracketState((prev) => {
31795
- const next = prev.matches.find((m) => m.a && m.b && !m.winner);
31796
- if (!next) {
31797
- setSimulating(false);
31798
- return prev;
31799
- }
31800
- const completed = simulateMatch(next);
31801
- if (!completed) return prev;
31802
- let matches = prev.matches.map(
31803
- (m) => m.id === completed.id ? completed : m
31804
- );
31805
- matches = propagateWinner(matches, completed);
31806
- const finalMatch = matches.find((m) => m.round === prev.rounds - 1);
31807
- const champion = finalMatch?.winner || null;
31808
- if (!champion) autoRef.current = setTimeout(tick, simulateDelayMs);
31809
- else setSimulating(false);
31810
- return { ...prev, matches, champion };
31811
- });
31847
+ simulateNext();
31848
+ }, [simulating, simulateNext]);
31849
+ (0, import_react70.useEffect)(() => {
31850
+ if (!simulating) return;
31851
+ const hasNext = bracketState.matches.some((m) => m.a && m.b && !m.winner);
31852
+ if (bracketState.champion || !hasNext) {
31853
+ setSimulating(false);
31854
+ return;
31855
+ }
31856
+ autoRef.current = setTimeout(simulateNext, simulateDelayMs);
31857
+ return () => {
31858
+ if (autoRef.current) clearTimeout(autoRef.current);
31859
+ autoRef.current = null;
31812
31860
  };
31813
- tick();
31814
- }, [simulating, simulateDelayMs]);
31861
+ }, [simulating, bracketState, simulateDelayMs, simulateNext]);
31815
31862
  const advanceWinner = (0, import_react70.useCallback)(
31816
31863
  (matchId, winnerSlot) => {
31817
31864
  setBracketState((prev) => {
@@ -39414,8 +39461,8 @@ function RosterImport({
39414
39461
  maxNames,
39415
39462
  maxFileBytes,
39416
39463
  onClose: () => setOpen(false),
39417
- onImport: (names) => {
39418
- onImport(names);
39464
+ onImport: (names, info) => {
39465
+ onImport(names, info);
39419
39466
  setOpen(false);
39420
39467
  }
39421
39468
  }
@@ -39481,6 +39528,11 @@ function RosterImportModal({
39481
39528
  }),
39482
39529
  [table, column, skipHeader, maxNames]
39483
39530
  );
39531
+ const extractedTotal = (0, import_react77.useMemo)(
39532
+ () => extractRoster(table, { column, skipHeader }),
39533
+ [table, column, skipHeader]
39534
+ );
39535
+ const trimmedCount = Math.max(0, extractedTotal.length - extracted.length);
39484
39536
  const handleFile = (0, import_react77.useCallback)(
39485
39537
  async (e) => {
39486
39538
  setFileError(null);
@@ -39858,7 +39910,10 @@ function RosterImportModal({
39858
39910
  "button",
39859
39911
  {
39860
39912
  type: "button",
39861
- onClick: () => onImport(extracted),
39913
+ onClick: () => onImport(extracted, {
39914
+ trimmedCount,
39915
+ totalCount: extractedTotal.length
39916
+ }),
39862
39917
  disabled: !canImport,
39863
39918
  style: primaryBtn(!canImport),
39864
39919
  children: confirmLabel
@@ -40062,6 +40117,19 @@ function IconUsers({ size = 40 }) {
40062
40117
  }
40063
40118
  );
40064
40119
  }
40120
+ function mergeNames(prev, incoming, max) {
40121
+ const seen = new Set(prev.map((n) => n.toLowerCase()));
40122
+ const room = Math.max(0, max - prev.length);
40123
+ const deduped = [];
40124
+ for (const n of incoming) {
40125
+ const key = n.toLowerCase();
40126
+ if (seen.has(key)) continue;
40127
+ seen.add(key);
40128
+ deduped.push(n);
40129
+ if (deduped.length >= room) break;
40130
+ }
40131
+ return deduped.length > 0 ? [...prev, ...deduped] : prev;
40132
+ }
40065
40133
  function splitIntoTeams(names, count2) {
40066
40134
  const shuffled = shuffle(names);
40067
40135
  const teams = Array.from({ length: count2 }, () => []);
@@ -40135,29 +40203,14 @@ function TeamGenerator({
40135
40203
  const trimmed = input.trim();
40136
40204
  if (!trimmed) return;
40137
40205
  const newNames = trimmed.split(/[,\n]+/).map((n) => n.trim()).filter((n) => n.length > 0);
40138
- setNames((prev) => {
40139
- const room = Math.max(0, maxPlayers - prev.length);
40140
- return [...prev, ...newNames.slice(0, room)];
40141
- });
40206
+ setNames((prev) => mergeNames(prev, newNames, maxPlayers));
40142
40207
  setInput("");
40143
40208
  inputRef.current?.focus();
40144
40209
  }, [input, maxPlayers]);
40145
40210
  const importNames = (0, import_react78.useCallback)(
40146
40211
  (incoming) => {
40147
40212
  if (incoming.length === 0) return;
40148
- setNames((prev) => {
40149
- const seen = new Set(prev.map((n) => n.toLowerCase()));
40150
- const room = Math.max(0, maxPlayers - prev.length);
40151
- const deduped = [];
40152
- for (const n of incoming) {
40153
- const key = n.toLowerCase();
40154
- if (seen.has(key)) continue;
40155
- seen.add(key);
40156
- deduped.push(n);
40157
- if (deduped.length >= room) break;
40158
- }
40159
- return deduped.length > 0 ? [...prev, ...deduped] : prev;
40160
- });
40213
+ setNames((prev) => mergeNames(prev, incoming, maxPlayers));
40161
40214
  },
40162
40215
  [maxPlayers]
40163
40216
  );
@@ -40777,7 +40830,7 @@ function RoundRobinScheduler({
40777
40830
  (0, import_react79.useEffect)(() => {
40778
40831
  onTeamsChange?.(teams);
40779
40832
  }, [teams, onTeamsChange]);
40780
- const mergeNames = (0, import_react79.useCallback)(
40833
+ const mergeNames2 = (0, import_react79.useCallback)(
40781
40834
  (prev, incoming) => {
40782
40835
  const existing = new Set(prev.map((t) => t.toLowerCase()));
40783
40836
  const next = [...prev];
@@ -40803,20 +40856,20 @@ function RoundRobinScheduler({
40803
40856
  const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
40804
40857
  if (names.length === 0) return;
40805
40858
  if (!gateDiscard("add")) return;
40806
- setTeams((prev) => mergeNames(prev, names));
40859
+ setTeams((prev) => mergeNames2(prev, names));
40807
40860
  setInput("");
40808
40861
  setRounds([]);
40809
40862
  },
40810
- [mergeNames, gateDiscard]
40863
+ [mergeNames2, gateDiscard]
40811
40864
  );
40812
40865
  const importTeams = (0, import_react79.useCallback)(
40813
40866
  (incoming) => {
40814
40867
  if (incoming.length === 0) return;
40815
40868
  if (!gateDiscard("import")) return;
40816
- setTeams((prev) => mergeNames(prev, incoming));
40869
+ setTeams((prev) => mergeNames2(prev, incoming));
40817
40870
  setRounds([]);
40818
40871
  },
40819
- [mergeNames, gateDiscard]
40872
+ [mergeNames2, gateDiscard]
40820
40873
  );
40821
40874
  const handleKeyDown = (0, import_react79.useCallback)(
40822
40875
  (e) => {
@@ -41316,6 +41369,8 @@ function Scoreboard({
41316
41369
  onBeforeReset,
41317
41370
  onBeforeNewGame,
41318
41371
  nameMaxLength,
41372
+ scoreMin = -9999,
41373
+ scoreMax = 9999,
41319
41374
  labels,
41320
41375
  ariaLabel = "Scoreboard",
41321
41376
  className
@@ -41359,11 +41414,19 @@ function Scoreboard({
41359
41414
  (0, import_react80.useEffect)(() => {
41360
41415
  onTeamsChange?.(teams);
41361
41416
  }, [teams, onTeamsChange]);
41362
- const updateScore = (0, import_react80.useCallback)((index, delta) => {
41363
- setTeams(
41364
- (prev) => prev.map((t, i) => i === index ? { ...t, score: t.score + delta } : t)
41365
- );
41366
- }, []);
41417
+ const updateScore = (0, import_react80.useCallback)(
41418
+ (index, delta) => {
41419
+ setTeams(
41420
+ (prev) => prev.map(
41421
+ (t, i) => i === index ? {
41422
+ ...t,
41423
+ score: Math.min(scoreMax, Math.max(scoreMin, t.score + delta))
41424
+ } : t
41425
+ )
41426
+ );
41427
+ },
41428
+ [scoreMin, scoreMax]
41429
+ );
41367
41430
  const updateName = (0, import_react80.useCallback)((index, name) => {
41368
41431
  setTeams((prev) => prev.map((t, i) => i === index ? { ...t, name } : t));
41369
41432
  }, []);