@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.js CHANGED
@@ -30925,17 +30925,13 @@ function DiceRoller({
30925
30925
  const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
30926
30926
  const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
30927
30927
  for (let i = 0; i < clampedCount; i++) {
30928
- if (sides === 6) {
30929
- writeCubeRotation(
30930
- i,
30931
- (Math.random() - 0.5) * 720,
30932
- (Math.random() - 0.5) * 720,
30933
- (Math.random() - 0.5) * 720,
30934
- false
30935
- );
30936
- } else {
30937
- writeCubeRotation(i, 0, 0, (Math.random() - 0.5) * 720, false);
30938
- }
30928
+ writeCubeRotation(
30929
+ i,
30930
+ (Math.random() - 0.5) * 720,
30931
+ (Math.random() - 0.5) * 720,
30932
+ (Math.random() - 0.5) * 720,
30933
+ false
30934
+ );
30939
30935
  const el = dieWrapperRefs.current[i];
30940
30936
  if (el) el.style.transition = "none";
30941
30937
  const shadow = shadowRefs.current[i];
@@ -30996,8 +30992,10 @@ function DiceRoller({
30996
30992
  const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30997
30993
  writeCubeRotation(i, lx, ly, lz, true, tilt);
30998
30994
  } else {
30995
+ const lx = (Math.random() > 0.5 ? 1 : -1) * 720;
30996
+ const ly = (Math.random() > 0.5 ? 1 : -1) * 360;
30999
30997
  const lz = (Math.random() > 0.5 ? 1 : -1) * 720 + tilt;
31000
- writeCubeRotation(i, 0, 0, lz, true);
30998
+ writeCubeRotation(i, lx, ly, lz, true);
31001
30999
  }
31002
31000
  }
31003
31001
  });
@@ -31156,60 +31154,115 @@ function DiceRoller({
31156
31154
  )) : (() => {
31157
31155
  const shape = POLY_SHAPES[sides];
31158
31156
  const shown = results?.[d] ?? sides;
31159
- return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
31160
- "svg",
31161
- {
31162
- viewBox: "0 0 100 100",
31163
- width: "100%",
31164
- height: "100%",
31165
- style: { display: "block", overflow: "visible" },
31166
- "aria-hidden": "true",
31167
- children: [
31168
- /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31169
- "polygon",
31170
- {
31171
- points: shape.points,
31172
- fill: colors.face,
31173
- stroke: colors.faceBorder,
31174
- strokeWidth: 2.5,
31175
- strokeLinejoin: "round",
31176
- style: { transition: "fill 0.3s, stroke 0.3s" }
31177
- }
31178
- ),
31179
- /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31180
- "polygon",
31181
- {
31182
- points: shape.points,
31183
- fill: "none",
31184
- stroke: colors.faceBorder,
31185
- strokeWidth: 1.5,
31186
- strokeLinejoin: "round",
31187
- opacity: 0.55,
31188
- transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31189
- }
31190
- ),
31191
- /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31192
- "text",
31193
- {
31194
- ref: getNumeralSetter(d),
31195
- x: 50,
31196
- y: shape.textY,
31197
- textAnchor: "middle",
31198
- dominantBaseline: "central",
31199
- fontSize: 100 * shape.fontScale,
31200
- fontWeight: 800,
31201
- fill: colors.pip,
31202
- style: {
31203
- fontVariantNumeric: "tabular-nums",
31204
- transition: "fill 0.3s",
31205
- userSelect: "none"
31206
- },
31207
- children: formatDieValue(shown, sides)
31208
- }
31209
- )
31210
- ]
31211
- }
31212
- );
31157
+ const cardFaceStyle = {
31158
+ position: "absolute",
31159
+ inset: 0,
31160
+ display: "block",
31161
+ overflow: "visible",
31162
+ backfaceVisibility: "hidden"
31163
+ };
31164
+ return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(import_jsx_runtime114.Fragment, { children: [
31165
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
31166
+ "svg",
31167
+ {
31168
+ viewBox: "0 0 100 100",
31169
+ width: "100%",
31170
+ height: "100%",
31171
+ style: cardFaceStyle,
31172
+ "aria-hidden": "true",
31173
+ children: [
31174
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31175
+ "polygon",
31176
+ {
31177
+ points: shape.points,
31178
+ fill: colors.face,
31179
+ stroke: colors.faceBorder,
31180
+ strokeWidth: 2.5,
31181
+ strokeLinejoin: "round",
31182
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31183
+ }
31184
+ ),
31185
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31186
+ "polygon",
31187
+ {
31188
+ points: shape.points,
31189
+ fill: "none",
31190
+ stroke: colors.faceBorder,
31191
+ strokeWidth: 1.5,
31192
+ strokeLinejoin: "round",
31193
+ opacity: 0.55,
31194
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31195
+ }
31196
+ ),
31197
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31198
+ "text",
31199
+ {
31200
+ ref: getNumeralSetter(d),
31201
+ x: 50,
31202
+ y: shape.textY,
31203
+ textAnchor: "middle",
31204
+ dominantBaseline: "central",
31205
+ fontSize: 100 * shape.fontScale,
31206
+ fontWeight: 800,
31207
+ fill: colors.pip,
31208
+ style: {
31209
+ fontVariantNumeric: "tabular-nums",
31210
+ transition: "fill 0.3s",
31211
+ userSelect: "none"
31212
+ },
31213
+ children: formatDieValue(shown, sides)
31214
+ }
31215
+ )
31216
+ ]
31217
+ }
31218
+ ),
31219
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
31220
+ "svg",
31221
+ {
31222
+ viewBox: "0 0 100 100",
31223
+ width: "100%",
31224
+ height: "100%",
31225
+ style: {
31226
+ ...cardFaceStyle,
31227
+ transform: "rotateY(180deg)"
31228
+ },
31229
+ "aria-hidden": "true",
31230
+ children: [
31231
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31232
+ "polygon",
31233
+ {
31234
+ points: shape.points,
31235
+ fill: colors.face,
31236
+ stroke: colors.faceBorder,
31237
+ strokeWidth: 2.5,
31238
+ strokeLinejoin: "round",
31239
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31240
+ }
31241
+ ),
31242
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31243
+ "polygon",
31244
+ {
31245
+ points: shape.points,
31246
+ fill: "none",
31247
+ stroke: colors.faceBorder,
31248
+ strokeWidth: 1.5,
31249
+ strokeLinejoin: "round",
31250
+ opacity: 0.55,
31251
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31252
+ }
31253
+ ),
31254
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31255
+ "polygon",
31256
+ {
31257
+ points: shape.points,
31258
+ fill: "#000",
31259
+ opacity: 0.14
31260
+ }
31261
+ )
31262
+ ]
31263
+ }
31264
+ )
31265
+ ] });
31213
31266
  })()
31214
31267
  }
31215
31268
  )
@@ -31957,32 +32010,26 @@ function BracketGenerator({
31957
32010
  const autoPlay = (0, import_react69.useCallback)(() => {
31958
32011
  if (simulating) {
31959
32012
  if (autoRef.current) clearTimeout(autoRef.current);
32013
+ autoRef.current = null;
31960
32014
  setSimulating(false);
31961
32015
  return;
31962
32016
  }
31963
32017
  setSimulating(true);
31964
- const tick = () => {
31965
- setBracketState((prev) => {
31966
- const next = prev.matches.find((m) => m.a && m.b && !m.winner);
31967
- if (!next) {
31968
- setSimulating(false);
31969
- return prev;
31970
- }
31971
- const completed = simulateMatch(next);
31972
- if (!completed) return prev;
31973
- let matches = prev.matches.map(
31974
- (m) => m.id === completed.id ? completed : m
31975
- );
31976
- matches = propagateWinner(matches, completed);
31977
- const finalMatch = matches.find((m) => m.round === prev.rounds - 1);
31978
- const champion = finalMatch?.winner || null;
31979
- if (!champion) autoRef.current = setTimeout(tick, simulateDelayMs);
31980
- else setSimulating(false);
31981
- return { ...prev, matches, champion };
31982
- });
32018
+ simulateNext();
32019
+ }, [simulating, simulateNext]);
32020
+ (0, import_react69.useEffect)(() => {
32021
+ if (!simulating) return;
32022
+ const hasNext = bracketState.matches.some((m) => m.a && m.b && !m.winner);
32023
+ if (bracketState.champion || !hasNext) {
32024
+ setSimulating(false);
32025
+ return;
32026
+ }
32027
+ autoRef.current = setTimeout(simulateNext, simulateDelayMs);
32028
+ return () => {
32029
+ if (autoRef.current) clearTimeout(autoRef.current);
32030
+ autoRef.current = null;
31983
32031
  };
31984
- tick();
31985
- }, [simulating, simulateDelayMs]);
32032
+ }, [simulating, bracketState, simulateDelayMs, simulateNext]);
31986
32033
  const advanceWinner = (0, import_react69.useCallback)(
31987
32034
  (matchId, winnerSlot) => {
31988
32035
  setBracketState((prev) => {
@@ -39773,8 +39820,8 @@ function RosterImport({
39773
39820
  maxNames,
39774
39821
  maxFileBytes,
39775
39822
  onClose: () => setOpen(false),
39776
- onImport: (names) => {
39777
- onImport(names);
39823
+ onImport: (names, info) => {
39824
+ onImport(names, info);
39778
39825
  setOpen(false);
39779
39826
  }
39780
39827
  }
@@ -39840,6 +39887,11 @@ function RosterImportModal({
39840
39887
  }),
39841
39888
  [table, column, skipHeader, maxNames]
39842
39889
  );
39890
+ const extractedTotal = (0, import_react75.useMemo)(
39891
+ () => extractRoster(table, { column, skipHeader }),
39892
+ [table, column, skipHeader]
39893
+ );
39894
+ const trimmedCount = Math.max(0, extractedTotal.length - extracted.length);
39843
39895
  const handleFile = (0, import_react75.useCallback)(
39844
39896
  async (e) => {
39845
39897
  setFileError(null);
@@ -40217,7 +40269,10 @@ function RosterImportModal({
40217
40269
  "button",
40218
40270
  {
40219
40271
  type: "button",
40220
- onClick: () => onImport(extracted),
40272
+ onClick: () => onImport(extracted, {
40273
+ trimmedCount,
40274
+ totalCount: extractedTotal.length
40275
+ }),
40221
40276
  disabled: !canImport,
40222
40277
  style: primaryBtn(!canImport),
40223
40278
  children: confirmLabel
@@ -40421,6 +40476,19 @@ function IconUsers({ size = 40 }) {
40421
40476
  }
40422
40477
  );
40423
40478
  }
40479
+ function mergeNames(prev, incoming, max) {
40480
+ const seen = new Set(prev.map((n) => n.toLowerCase()));
40481
+ const room = Math.max(0, max - prev.length);
40482
+ const deduped = [];
40483
+ for (const n of incoming) {
40484
+ const key = n.toLowerCase();
40485
+ if (seen.has(key)) continue;
40486
+ seen.add(key);
40487
+ deduped.push(n);
40488
+ if (deduped.length >= room) break;
40489
+ }
40490
+ return deduped.length > 0 ? [...prev, ...deduped] : prev;
40491
+ }
40424
40492
  function splitIntoTeams(names, count2) {
40425
40493
  const shuffled = shuffle(names);
40426
40494
  const teams = Array.from({ length: count2 }, () => []);
@@ -40494,29 +40562,14 @@ function TeamGenerator({
40494
40562
  const trimmed = input.trim();
40495
40563
  if (!trimmed) return;
40496
40564
  const newNames = trimmed.split(/[,\n]+/).map((n) => n.trim()).filter((n) => n.length > 0);
40497
- setNames((prev) => {
40498
- const room = Math.max(0, maxPlayers - prev.length);
40499
- return [...prev, ...newNames.slice(0, room)];
40500
- });
40565
+ setNames((prev) => mergeNames(prev, newNames, maxPlayers));
40501
40566
  setInput("");
40502
40567
  inputRef.current?.focus();
40503
40568
  }, [input, maxPlayers]);
40504
40569
  const importNames = (0, import_react76.useCallback)(
40505
40570
  (incoming) => {
40506
40571
  if (incoming.length === 0) return;
40507
- setNames((prev) => {
40508
- const seen = new Set(prev.map((n) => n.toLowerCase()));
40509
- const room = Math.max(0, maxPlayers - prev.length);
40510
- const deduped = [];
40511
- for (const n of incoming) {
40512
- const key = n.toLowerCase();
40513
- if (seen.has(key)) continue;
40514
- seen.add(key);
40515
- deduped.push(n);
40516
- if (deduped.length >= room) break;
40517
- }
40518
- return deduped.length > 0 ? [...prev, ...deduped] : prev;
40519
- });
40572
+ setNames((prev) => mergeNames(prev, incoming, maxPlayers));
40520
40573
  },
40521
40574
  [maxPlayers]
40522
40575
  );
@@ -41136,7 +41189,7 @@ function RoundRobinScheduler({
41136
41189
  (0, import_react77.useEffect)(() => {
41137
41190
  onTeamsChange?.(teams);
41138
41191
  }, [teams, onTeamsChange]);
41139
- const mergeNames = (0, import_react77.useCallback)(
41192
+ const mergeNames2 = (0, import_react77.useCallback)(
41140
41193
  (prev, incoming) => {
41141
41194
  const existing = new Set(prev.map((t) => t.toLowerCase()));
41142
41195
  const next = [...prev];
@@ -41162,20 +41215,20 @@ function RoundRobinScheduler({
41162
41215
  const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
41163
41216
  if (names.length === 0) return;
41164
41217
  if (!gateDiscard("add")) return;
41165
- setTeams((prev) => mergeNames(prev, names));
41218
+ setTeams((prev) => mergeNames2(prev, names));
41166
41219
  setInput("");
41167
41220
  setRounds([]);
41168
41221
  },
41169
- [mergeNames, gateDiscard]
41222
+ [mergeNames2, gateDiscard]
41170
41223
  );
41171
41224
  const importTeams = (0, import_react77.useCallback)(
41172
41225
  (incoming) => {
41173
41226
  if (incoming.length === 0) return;
41174
41227
  if (!gateDiscard("import")) return;
41175
- setTeams((prev) => mergeNames(prev, incoming));
41228
+ setTeams((prev) => mergeNames2(prev, incoming));
41176
41229
  setRounds([]);
41177
41230
  },
41178
- [mergeNames, gateDiscard]
41231
+ [mergeNames2, gateDiscard]
41179
41232
  );
41180
41233
  const handleKeyDown = (0, import_react77.useCallback)(
41181
41234
  (e) => {
@@ -41675,6 +41728,8 @@ function Scoreboard({
41675
41728
  onBeforeReset,
41676
41729
  onBeforeNewGame,
41677
41730
  nameMaxLength,
41731
+ scoreMin = -9999,
41732
+ scoreMax = 9999,
41678
41733
  labels,
41679
41734
  ariaLabel = "Scoreboard",
41680
41735
  className
@@ -41718,11 +41773,19 @@ function Scoreboard({
41718
41773
  (0, import_react78.useEffect)(() => {
41719
41774
  onTeamsChange?.(teams);
41720
41775
  }, [teams, onTeamsChange]);
41721
- const updateScore = (0, import_react78.useCallback)((index, delta) => {
41722
- setTeams(
41723
- (prev) => prev.map((t, i) => i === index ? { ...t, score: t.score + delta } : t)
41724
- );
41725
- }, []);
41776
+ const updateScore = (0, import_react78.useCallback)(
41777
+ (index, delta) => {
41778
+ setTeams(
41779
+ (prev) => prev.map(
41780
+ (t, i) => i === index ? {
41781
+ ...t,
41782
+ score: Math.min(scoreMax, Math.max(scoreMin, t.score + delta))
41783
+ } : t
41784
+ )
41785
+ );
41786
+ },
41787
+ [scoreMin, scoreMax]
41788
+ );
41726
41789
  const updateName = (0, import_react78.useCallback)((index, name) => {
41727
41790
  setTeams((prev) => prev.map((t, i) => i === index ? { ...t, name } : t));
41728
41791
  }, []);