@digilogiclabs/saas-factory-ui 2.1.0 → 2.3.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.js CHANGED
@@ -282,6 +282,7 @@ __export(index_exports, {
282
282
  CommentSystem: () => CommentSystem,
283
283
  Container: () => Container,
284
284
  ConversionKPI: () => ConversionKPI,
285
+ D6_FACE_PLACEMENTS: () => D6_FACE_PLACEMENTS,
285
286
  DISTANCES: () => DISTANCES,
286
287
  DURATIONS: () => DURATIONS,
287
288
  DashboardGrid: () => DashboardGrid,
@@ -571,6 +572,7 @@ __export(index_exports, {
571
572
  createOptimizedStore: () => createOptimizedStore,
572
573
  createSlideVariant: () => createSlideVariant,
573
574
  createTransition: () => createTransition,
575
+ d6LandingRotation: () => d6LandingRotation,
574
576
  dailyTrendingConfig: () => dailyTrendingConfig,
575
577
  detectAuthProvider: () => detectAuthProvider,
576
578
  detectDelimiter: () => detectDelimiter,
@@ -30515,14 +30517,35 @@ var PIP_POS = {
30515
30517
  [75, 75]
30516
30518
  ]
30517
30519
  };
30518
- var SHOW_ROT = {
30520
+ var D6_FACE_PLACEMENTS = {
30519
30521
  1: { x: 0, y: 0 },
30520
- 2: { x: 0, y: 180 },
30521
- 3: { x: 0, y: -90 },
30522
- 4: { x: 0, y: 90 },
30523
- 5: { x: -90, y: 0 },
30524
- 6: { x: 90, y: 0 }
30522
+ 2: { x: 0, y: 90 },
30523
+ 3: { x: 90, y: 0 },
30524
+ 4: { x: -90, y: 0 },
30525
+ 5: { x: 0, y: -90 },
30526
+ 6: { x: 0, y: 180 }
30525
30527
  };
30528
+ function d6LandingRotation(value) {
30529
+ const p = D6_FACE_PLACEMENTS[value];
30530
+ return {
30531
+ x: Math.abs(p.x) === 180 ? 180 : -p.x || 0,
30532
+ y: Math.abs(p.y) === 180 ? 180 : -p.y || 0
30533
+ };
30534
+ }
30535
+ var POLY_SHAPES = {
30536
+ 4: { points: "50,8 93,86 7,86", textY: 62, fontScale: 0.3 },
30537
+ 8: { points: "50,4 96,50 50,96 4,50", textY: 51, fontScale: 0.33 },
30538
+ 10: { points: "50,4 93,44 50,96 7,44", textY: 47, fontScale: 0.3 },
30539
+ 12: { points: "50,4 95,37 78,93 22,93 5,37", textY: 54, fontScale: 0.33 },
30540
+ 20: {
30541
+ points: "50,3 91,26 91,74 50,97 9,74 9,26",
30542
+ textY: 51,
30543
+ fontScale: 0.33
30544
+ }
30545
+ };
30546
+ function formatDieValue(v, sides) {
30547
+ return sides > 8 && (v === 6 || v === 9) ? `${v}.` : String(v);
30548
+ }
30526
30549
  var MAX_COUNT = 6;
30527
30550
  var TUMBLE_MS = 950;
30528
30551
  var SETTLE_MS = 1100;
@@ -30674,6 +30697,7 @@ function Face({ value, pipColor, pipShadow, pipDiameter }) {
30674
30697
  }
30675
30698
  function DiceRoller({
30676
30699
  count: count2 = 2,
30700
+ sides = 6,
30677
30701
  theme: theme5 = "red",
30678
30702
  darkMode,
30679
30703
  size = 80,
@@ -30702,6 +30726,7 @@ function DiceRoller({
30702
30726
  const dieWrapperRefs = (0, import_react68.useRef)([]);
30703
30727
  const cubeRefs = (0, import_react68.useRef)([]);
30704
30728
  const shadowRefs = (0, import_react68.useRef)([]);
30729
+ const numeralRefs = (0, import_react68.useRef)([]);
30705
30730
  const currentPositionsRef = (0, import_react68.useRef)(null);
30706
30731
  const rollingRef = (0, import_react68.useRef)(false);
30707
30732
  const dieSetters = (0, import_react68.useRef)([]);
@@ -30731,6 +30756,15 @@ function DiceRoller({
30731
30756
  }
30732
30757
  return shadowSetters.current[i];
30733
30758
  };
30759
+ const numeralSetters = (0, import_react68.useRef)([]);
30760
+ const getNumeralSetter = (i) => {
30761
+ if (!numeralSetters.current[i]) {
30762
+ numeralSetters.current[i] = (el) => {
30763
+ numeralRefs.current[i] = el;
30764
+ };
30765
+ }
30766
+ return numeralSetters.current[i];
30767
+ };
30734
30768
  const timersRef = (0, import_react68.useRef)([]);
30735
30769
  const rafHandleRef = (0, import_react68.useRef)(null);
30736
30770
  const arenaRef = (0, import_react68.useRef)(null);
@@ -30783,15 +30817,15 @@ function DiceRoller({
30783
30817
  const pipDiameter = Math.round(effectiveSize * 0.2);
30784
30818
  const faceRadius = Math.round(effectiveSize * 0.07);
30785
30819
  const arenaHeight = arenaHeightProp ?? Math.max(effectiveSize * 3, 200);
30786
- const faceTransforms = (0, import_react68.useMemo)(
30787
- () => [
30788
- `translateZ(${half}px)`,
30789
- `rotateY(180deg) translateZ(${half}px)`,
30790
- `rotateY(-90deg) translateZ(${half}px)`,
30791
- `rotateY(90deg) translateZ(${half}px)`,
30792
- `rotateX(90deg) translateZ(${half}px)`,
30793
- `rotateX(-90deg) translateZ(${half}px)`
30794
- ],
30820
+ const faceTransformFor = (0, import_react68.useCallback)(
30821
+ (value) => {
30822
+ const p = D6_FACE_PLACEMENTS[value];
30823
+ const parts = [];
30824
+ if (p.x !== 0) parts.push(`rotateX(${p.x}deg)`);
30825
+ if (p.y !== 0) parts.push(`rotateY(${p.y}deg)`);
30826
+ parts.push(`translateZ(${half}px)`);
30827
+ return parts.join(" ");
30828
+ },
30795
30829
  [half]
30796
30830
  );
30797
30831
  const defaultPositions = (0, import_react68.useCallback)(
@@ -30813,11 +30847,11 @@ function DiceRoller({
30813
30847
  [half]
30814
30848
  );
30815
30849
  const writeCubeRotation = (0, import_react68.useCallback)(
30816
- (i, rx, ry, rz, withTransition) => {
30850
+ (i, rx, ry, rz, withTransition, tiltZ = 0) => {
30817
30851
  const el = cubeRefs.current[i];
30818
30852
  if (!el) return;
30819
30853
  el.style.transition = withTransition ? "transform 0.95s cubic-bezier(0.12,0.8,0.22,1)" : "none";
30820
- el.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
30854
+ el.style.transform = `${tiltZ ? `rotateZ(${tiltZ}deg) ` : ""}rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
30821
30855
  },
30822
30856
  []
30823
30857
  );
@@ -30847,19 +30881,23 @@ function DiceRoller({
30847
30881
  setResults(null);
30848
30882
  }, [
30849
30883
  clampedCount,
30884
+ sides,
30850
30885
  effectiveSize,
30851
30886
  arena.w,
30852
30887
  arenaHeight,
30853
30888
  defaultPositions,
30854
30889
  half
30855
30890
  ]);
30891
+ (0, import_react68.useEffect)(() => {
30892
+ setHistory([]);
30893
+ }, [sides]);
30856
30894
  const roll = (0, import_react68.useCallback)(() => {
30857
30895
  if (rollingRef.current) return;
30858
30896
  rollingRef.current = true;
30859
30897
  setRolling(true);
30860
30898
  const vals = Array.from(
30861
30899
  { length: clampedCount },
30862
- () => Math.floor(Math.random() * 6) + 1
30900
+ () => Math.floor(Math.random() * sides) + 1
30863
30901
  );
30864
30902
  timersRef.current.forEach((t) => clearTimeout(t));
30865
30903
  timersRef.current = [];
@@ -30874,13 +30912,17 @@ function DiceRoller({
30874
30912
  const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
30875
30913
  const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
30876
30914
  for (let i = 0; i < clampedCount; i++) {
30877
- writeCubeRotation(
30878
- i,
30879
- (Math.random() - 0.5) * 720,
30880
- (Math.random() - 0.5) * 720,
30881
- (Math.random() - 0.5) * 720,
30882
- false
30883
- );
30915
+ if (sides === 6) {
30916
+ writeCubeRotation(
30917
+ i,
30918
+ (Math.random() - 0.5) * 720,
30919
+ (Math.random() - 0.5) * 720,
30920
+ (Math.random() - 0.5) * 720,
30921
+ false
30922
+ );
30923
+ } else {
30924
+ writeCubeRotation(i, 0, 0, (Math.random() - 0.5) * 720, false);
30925
+ }
30884
30926
  const el = dieWrapperRefs.current[i];
30885
30927
  if (el) el.style.transition = "none";
30886
30928
  const shadow = shadowRefs.current[i];
@@ -30913,18 +30955,47 @@ function DiceRoller({
30913
30955
  }, capturedStep * stepMs);
30914
30956
  timersRef.current.push(timer);
30915
30957
  }
30958
+ if (sides !== 6) {
30959
+ const flickerTicks = 8;
30960
+ const flickerStep = Math.max(60, Math.floor(TUMBLE_MS / flickerTicks));
30961
+ for (let f = 1; f <= flickerTicks; f++) {
30962
+ const t = setTimeout(() => {
30963
+ for (let i = 0; i < clampedCount; i++) {
30964
+ const el = numeralRefs.current[i];
30965
+ if (el)
30966
+ el.textContent = formatDieValue(
30967
+ Math.floor(Math.random() * sides) + 1,
30968
+ sides
30969
+ );
30970
+ }
30971
+ }, f * flickerStep);
30972
+ timersRef.current.push(t);
30973
+ }
30974
+ }
30916
30975
  requestAnimationFrame(() => {
30917
30976
  requestAnimationFrame(() => {
30918
30977
  for (let i = 0; i < clampedCount; i++) {
30919
- const tgt = SHOW_ROT[vals[i]];
30920
- const lx = tgt.x + (Math.random() > 0.5 ? 720 : -720);
30921
- const ly = tgt.y;
30922
- const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30923
- writeCubeRotation(i, lx, ly, lz, true);
30978
+ const tilt = (Math.random() - 0.5) * 18;
30979
+ if (sides === 6) {
30980
+ const tgt = d6LandingRotation(vals[i]);
30981
+ const lx = tgt.x + (Math.random() > 0.5 ? 720 : -720);
30982
+ const ly = tgt.y;
30983
+ const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30984
+ writeCubeRotation(i, lx, ly, lz, true, tilt);
30985
+ } else {
30986
+ const lz = (Math.random() > 0.5 ? 1 : -1) * 720 + tilt;
30987
+ writeCubeRotation(i, 0, 0, lz, true);
30988
+ }
30924
30989
  }
30925
30990
  });
30926
30991
  });
30927
30992
  const settleTimer = setTimeout(() => {
30993
+ if (sides !== 6) {
30994
+ for (let i = 0; i < clampedCount; i++) {
30995
+ const el = numeralRefs.current[i];
30996
+ if (el) el.textContent = formatDieValue(vals[i], sides);
30997
+ }
30998
+ }
30928
30999
  setResults(vals);
30929
31000
  setRolling(false);
30930
31001
  rollingRef.current = false;
@@ -30937,6 +31008,7 @@ function DiceRoller({
30937
31008
  timersRef.current.push(settleTimer);
30938
31009
  }, [
30939
31010
  clampedCount,
31011
+ sides,
30940
31012
  defaultPositions,
30941
31013
  effectiveSize,
30942
31014
  half,
@@ -30982,7 +31054,7 @@ function DiceRoller({
30982
31054
  {
30983
31055
  ref: arenaRef,
30984
31056
  role: "img",
30985
- "aria-label": ariaLabel ?? `${clampedCount} dice`,
31057
+ "aria-label": ariaLabel ?? `${clampedCount} ${sides === 6 ? "dice" : `${sides}-sided dice`}`,
30986
31058
  "aria-live": "polite",
30987
31059
  style: {
30988
31060
  position: "relative",
@@ -31045,7 +31117,7 @@ function DiceRoller({
31045
31117
  transformStyle: "preserve-3d",
31046
31118
  willChange: "transform"
31047
31119
  },
31048
- children: [1, 2, 3, 4, 5, 6].map((val, fi) => /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31120
+ children: sides === 6 ? [1, 2, 3, 4, 5, 6].map((val) => /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31049
31121
  "div",
31050
31122
  {
31051
31123
  style: {
@@ -31055,7 +31127,7 @@ function DiceRoller({
31055
31127
  background: colors.face,
31056
31128
  border: `1px solid ${colors.faceBorder}`,
31057
31129
  borderRadius: faceRadius,
31058
- transform: faceTransforms[fi],
31130
+ transform: faceTransformFor(val),
31059
31131
  transition: "background 0.3s, border-color 0.3s"
31060
31132
  },
31061
31133
  children: /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
@@ -31069,7 +31141,64 @@ function DiceRoller({
31069
31141
  )
31070
31142
  },
31071
31143
  val
31072
- ))
31144
+ )) : (() => {
31145
+ const shape = POLY_SHAPES[sides];
31146
+ const shown = results?.[d] ?? sides;
31147
+ return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
31148
+ "svg",
31149
+ {
31150
+ viewBox: "0 0 100 100",
31151
+ width: "100%",
31152
+ height: "100%",
31153
+ style: { display: "block", overflow: "visible" },
31154
+ "aria-hidden": "true",
31155
+ children: [
31156
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31157
+ "polygon",
31158
+ {
31159
+ points: shape.points,
31160
+ fill: colors.face,
31161
+ stroke: colors.faceBorder,
31162
+ strokeWidth: 2.5,
31163
+ strokeLinejoin: "round",
31164
+ style: { transition: "fill 0.3s, stroke 0.3s" }
31165
+ }
31166
+ ),
31167
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31168
+ "polygon",
31169
+ {
31170
+ points: shape.points,
31171
+ fill: "none",
31172
+ stroke: colors.faceBorder,
31173
+ strokeWidth: 1.5,
31174
+ strokeLinejoin: "round",
31175
+ opacity: 0.55,
31176
+ transform: "translate(50 50) scale(0.76) translate(-50 -50)"
31177
+ }
31178
+ ),
31179
+ /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
31180
+ "text",
31181
+ {
31182
+ ref: getNumeralSetter(d),
31183
+ x: 50,
31184
+ y: shape.textY,
31185
+ textAnchor: "middle",
31186
+ dominantBaseline: "central",
31187
+ fontSize: 100 * shape.fontScale,
31188
+ fontWeight: 800,
31189
+ fill: colors.pip,
31190
+ style: {
31191
+ fontVariantNumeric: "tabular-nums",
31192
+ transition: "fill 0.3s",
31193
+ userSelect: "none"
31194
+ },
31195
+ children: formatDieValue(shown, sides)
31196
+ }
31197
+ )
31198
+ ]
31199
+ }
31200
+ );
31201
+ })()
31073
31202
  }
31074
31203
  )
31075
31204
  ] }, d);
@@ -40659,6 +40788,27 @@ function generateSchedule(teams, roundLabel) {
40659
40788
  }
40660
40789
  return rounds;
40661
40790
  }
40791
+ function hydrateResumeRounds(resume, teams) {
40792
+ if (!resume?.length || teams.length < 2) return [];
40793
+ const expected = teams.length % 2 === 0 ? teams.length - 1 : teams.length;
40794
+ if (resume.length !== expected) return [];
40795
+ const roster = new Set(teams.map((t) => t.toLowerCase()));
40796
+ for (const round of resume) {
40797
+ for (const m of round.matchups) {
40798
+ for (const side of [m.home, m.away]) {
40799
+ if (side !== BYE_TOKEN && !roster.has(side.toLowerCase())) return [];
40800
+ }
40801
+ }
40802
+ }
40803
+ return resume.map((round) => ({
40804
+ label: round.label,
40805
+ matchups: round.matchups.map((m) => ({
40806
+ home: m.home,
40807
+ away: m.away,
40808
+ isBye: m.home === BYE_TOKEN || m.away === BYE_TOKEN
40809
+ }))
40810
+ }));
40811
+ }
40662
40812
  var DEFAULT_LABELS4 = {
40663
40813
  inputPlaceholder: "Team or player name (comma-separated for batch)",
40664
40814
  addButton: "Add",
@@ -40679,6 +40829,7 @@ function RoundRobinScheduler({
40679
40829
  darkMode,
40680
40830
  minTeams = 3,
40681
40831
  defaultTeams = [],
40832
+ resumeRounds,
40682
40833
  onTeamsChange,
40683
40834
  onGenerate,
40684
40835
  labels,
@@ -40692,7 +40843,9 @@ function RoundRobinScheduler({
40692
40843
  const L = { ...DEFAULT_LABELS4, ...labels };
40693
40844
  const [teams, setTeams] = (0, import_react77.useState)(defaultTeams);
40694
40845
  const [input, setInput] = (0, import_react77.useState)("");
40695
- const [rounds, setRounds] = (0, import_react77.useState)([]);
40846
+ const [rounds, setRounds] = (0, import_react77.useState)(
40847
+ () => hydrateResumeRounds(resumeRounds, defaultTeams)
40848
+ );
40696
40849
  const inputRef = (0, import_react77.useRef)(null);
40697
40850
  (0, import_react77.useEffect)(() => {
40698
40851
  onTeamsChange?.(teams);
@@ -41213,6 +41366,8 @@ function Scoreboard({
41213
41366
  maxTeams = 8,
41214
41367
  scoreButtons = [-1, 1, 5, 10],
41215
41368
  defaultTeams,
41369
+ initialRound = 1,
41370
+ initialHistory,
41216
41371
  onTeamsChange,
41217
41372
  onRoundAdvance,
41218
41373
  onNewGame,
@@ -41228,8 +41383,12 @@ function Scoreboard({
41228
41383
  const [teams, setTeams] = (0, import_react78.useState)(
41229
41384
  () => defaultTeams && defaultTeams.length >= minTeams ? defaultTeams.slice(0, maxTeams) : createDefaultTeams(seedCount, L.teamNamePrefix)
41230
41385
  );
41231
- const [round, setRound] = (0, import_react78.useState)(1);
41232
- const [history, setHistory] = (0, import_react78.useState)([]);
41386
+ const [round, setRound] = (0, import_react78.useState)(
41387
+ () => Number.isFinite(initialRound) ? Math.max(1, Math.floor(initialRound)) : 1
41388
+ );
41389
+ const [history, setHistory] = (0, import_react78.useState)(
41390
+ () => initialHistory && initialHistory.length > 0 ? initialHistory.slice() : []
41391
+ );
41233
41392
  const [historyOpen, setHistoryOpen] = (0, import_react78.useState)(false);
41234
41393
  const rootRef = (0, import_react78.useRef)(null);
41235
41394
  const [containerWidth, setContainerWidth] = (0, import_react78.useState)(0);