@digilogiclabs/saas-factory-ui 1.16.0 → 1.16.2

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
@@ -30292,6 +30292,8 @@ var SHOW_ROT = {
30292
30292
  6: { x: 90, y: 0 }
30293
30293
  };
30294
30294
  var MAX_COUNT = 6;
30295
+ var TUMBLE_MS = 950;
30296
+ var SETTLE_MS = 1100;
30295
30297
  function simulateDice(arenaW, arenaH, diceSize, starts, numDice) {
30296
30298
  const pad = diceSize * 0.55;
30297
30299
  const minX = pad;
@@ -30304,17 +30306,20 @@ function simulateDice(arenaW, arenaH, diceSize, starts, numDice) {
30304
30306
  for (let i = 0; i < numDice; i++) {
30305
30307
  const s = starts[i] ?? { x: arenaW / 2, y: arenaH / 2 };
30306
30308
  bodies.push({
30307
- x: clamp(s.x + (Math.random() - 0.5) * arenaW * 0.2, minX, maxX),
30308
- y: clamp(s.y + (Math.random() - 0.5) * arenaH * 0.2, minY, maxY),
30309
- vx: (Math.random() - 0.5) * arenaW * 0.9,
30310
- vy: (Math.random() - 0.5) * arenaH * 0.9
30309
+ x: clamp(s.x + (Math.random() - 0.5) * arenaW * 0.25, minX, maxX),
30310
+ y: clamp(s.y + (Math.random() - 0.5) * arenaH * 0.25, minY, maxY),
30311
+ // Minimum baseline velocity so small arenas still bounce visibly
30312
+ // instead of drifting a few pixels. The `|| 1` guard makes sure
30313
+ // we never get a near-zero initial velocity from `random - 0.5`.
30314
+ vx: (Math.sign(Math.random() - 0.5) || 1) * (0.5 + Math.random() * 0.5) * arenaW * 1.4,
30315
+ vy: (Math.sign(Math.random() - 0.5) || 1) * (0.5 + Math.random() * 0.5) * arenaH * 1.6
30311
30316
  });
30312
30317
  }
30313
- const steps = 24;
30318
+ const steps = 32;
30314
30319
  const dt = 2 / steps;
30315
- const friction = 0.86;
30316
- const wallRestitution = -0.55;
30317
- const diceRestitution = 0.7;
30320
+ const friction = 0.9;
30321
+ const wallRestitution = -0.72;
30322
+ const diceRestitution = 0.8;
30318
30323
  const frames = [];
30319
30324
  for (let s = 0; s < steps; s++) {
30320
30325
  for (const b of bodies) {
@@ -30495,11 +30500,13 @@ function DiceRoller({
30495
30500
  const [rolling, setRolling] = (0, import_react66.useState)(false);
30496
30501
  const [results, setResults] = (0, import_react66.useState)(null);
30497
30502
  const [history, setHistory] = (0, import_react66.useState)([]);
30498
- const [rotations, setRotations] = (0, import_react66.useState)(
30499
- () => Array.from({ length: MAX_COUNT }, () => ({ x: 0, y: 0, z: 0, tr: true }))
30500
- );
30501
- const [positions, setPositions] = (0, import_react66.useState)(null);
30503
+ const dieWrapperRefs = (0, import_react66.useRef)([]);
30504
+ const cubeRefs = (0, import_react66.useRef)([]);
30505
+ const shadowRefs = (0, import_react66.useRef)([]);
30506
+ const currentPositionsRef = (0, import_react66.useRef)(null);
30507
+ const rollingRef = (0, import_react66.useRef)(false);
30502
30508
  const timersRef = (0, import_react66.useRef)([]);
30509
+ const rafHandleRef = (0, import_react66.useRef)(null);
30503
30510
  const arenaRef = (0, import_react66.useRef)(null);
30504
30511
  const arena = useArenaBounds(arenaRef);
30505
30512
  const colors = (0, import_react66.useMemo)(() => {
@@ -30568,15 +30575,54 @@ function DiceRoller({
30568
30575
  })),
30569
30576
  []
30570
30577
  );
30578
+ const writeDiePosition = (0, import_react66.useCallback)(
30579
+ (i, x, y) => {
30580
+ const el = dieWrapperRefs.current[i];
30581
+ if (!el) return;
30582
+ el.style.transform = `translate3d(${x - half}px, ${y - half}px, 0)`;
30583
+ },
30584
+ [half]
30585
+ );
30586
+ const writeCubeRotation = (0, import_react66.useCallback)(
30587
+ (i, rx, ry, rz, withTransition) => {
30588
+ const el = cubeRefs.current[i];
30589
+ if (!el) return;
30590
+ el.style.transition = withTransition ? "transform 0.95s cubic-bezier(0.12,0.8,0.22,1)" : "none";
30591
+ el.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;
30592
+ },
30593
+ []
30594
+ );
30571
30595
  (0, import_react66.useEffect)(() => {
30596
+ const w = arenaRef.current?.offsetWidth ?? arena.w;
30597
+ const h = arenaRef.current?.offsetHeight ?? arenaHeight;
30598
+ if (w === 0 || h === 0) return;
30599
+ const initial = defaultPositions(w, h, clampedCount);
30600
+ currentPositionsRef.current = initial;
30601
+ for (let i = 0; i < clampedCount; i++) {
30602
+ const pos = initial[i];
30603
+ const el = dieWrapperRefs.current[i];
30604
+ if (el) {
30605
+ el.style.transition = "transform 0.35s cubic-bezier(0.25,0.46,0.45,0.94)";
30606
+ el.style.transform = `translate3d(${pos.x - half}px, ${pos.y - half}px, 0)`;
30607
+ }
30608
+ const cube = cubeRefs.current[i];
30609
+ if (cube) {
30610
+ cube.style.transition = "none";
30611
+ cube.style.transform = "rotateX(0deg) rotateY(0deg) rotateZ(0deg)";
30612
+ }
30613
+ }
30572
30614
  setResults(null);
30573
- setPositions(null);
30574
- setRotations(
30575
- Array.from({ length: MAX_COUNT }, () => ({ x: 0, y: 0, z: 0, tr: true }))
30576
- );
30577
- }, [clampedCount, effectiveSize]);
30615
+ }, [
30616
+ clampedCount,
30617
+ effectiveSize,
30618
+ arena.w,
30619
+ arenaHeight,
30620
+ defaultPositions,
30621
+ half
30622
+ ]);
30578
30623
  const roll = (0, import_react66.useCallback)(() => {
30579
- if (rolling) return;
30624
+ if (rollingRef.current) return;
30625
+ rollingRef.current = true;
30580
30626
  setRolling(true);
30581
30627
  const vals = Array.from(
30582
30628
  { length: clampedCount },
@@ -30584,21 +30630,29 @@ function DiceRoller({
30584
30630
  );
30585
30631
  timersRef.current.forEach((t) => clearTimeout(t));
30586
30632
  timersRef.current = [];
30633
+ if (rafHandleRef.current != null) {
30634
+ cancelAnimationFrame(rafHandleRef.current);
30635
+ rafHandleRef.current = null;
30636
+ }
30587
30637
  const w = arenaRef.current?.offsetWidth ?? 400;
30588
30638
  const h = arenaRef.current?.offsetHeight ?? 260;
30589
- const starts = positions ?? defaultPositions(w, h, clampedCount);
30639
+ const starts = currentPositionsRef.current ?? defaultPositions(w, h, clampedCount);
30590
30640
  if (reducedMotion) {
30591
- setPositions(defaultPositions(w, h, clampedCount));
30592
- setRotations((prev) => {
30593
- const n = [...prev];
30594
- for (let i = 0; i < clampedCount; i++) {
30595
- const tgt = SHOW_ROT[vals[i]];
30596
- n[i] = { x: tgt.x, y: tgt.y, z: 0, tr: false };
30641
+ const final = defaultPositions(w, h, clampedCount);
30642
+ currentPositionsRef.current = final;
30643
+ for (let i = 0; i < clampedCount; i++) {
30644
+ const p = final[i];
30645
+ const el = dieWrapperRefs.current[i];
30646
+ if (el) {
30647
+ el.style.transition = "transform 0.2s ease-out";
30648
+ el.style.transform = `translate3d(${p.x - half}px, ${p.y - half}px, 0)`;
30597
30649
  }
30598
- return n;
30599
- });
30650
+ const tgt = SHOW_ROT[vals[i]];
30651
+ writeCubeRotation(i, tgt.x, tgt.y, 0, true);
30652
+ }
30600
30653
  setResults(vals);
30601
30654
  setRolling(false);
30655
+ rollingRef.current = false;
30602
30656
  const total2 = vals.reduce((a, b) => a + b, 0);
30603
30657
  onRoll?.(vals, total2);
30604
30658
  if (showHistory) {
@@ -30607,60 +30661,84 @@ function DiceRoller({
30607
30661
  return;
30608
30662
  }
30609
30663
  const frames = simulateDice(w, h, effectiveSize, starts, clampedCount);
30610
- setRotations((prev) => {
30611
- const n = [...prev];
30612
- for (let i = 0; i < clampedCount; i++) {
30613
- n[i] = {
30614
- x: (Math.random() - 0.5) * 720,
30615
- y: (Math.random() - 0.5) * 720,
30616
- z: (Math.random() - 0.5) * 720,
30617
- tr: false
30618
- };
30664
+ for (let i = 0; i < clampedCount; i++) {
30665
+ writeCubeRotation(
30666
+ i,
30667
+ (Math.random() - 0.5) * 720,
30668
+ (Math.random() - 0.5) * 720,
30669
+ (Math.random() - 0.5) * 720,
30670
+ false
30671
+ );
30672
+ const el = dieWrapperRefs.current[i];
30673
+ if (el) el.style.transition = "none";
30674
+ const shadow = shadowRefs.current[i];
30675
+ if (shadow) shadow.style.opacity = "0.2";
30676
+ }
30677
+ if (dieWrapperRefs.current[0]) {
30678
+ dieWrapperRefs.current[0].offsetHeight;
30679
+ }
30680
+ const playbackMs = TUMBLE_MS;
30681
+ const startTime = typeof performance !== "undefined" ? performance.now() : Date.now();
30682
+ const tick = (now) => {
30683
+ const elapsed = now - startTime;
30684
+ const progress = Math.max(0, Math.min(1, elapsed / playbackMs));
30685
+ const idx = Math.min(
30686
+ frames.length - 1,
30687
+ Math.floor(progress * frames.length)
30688
+ );
30689
+ const frame = frames[idx];
30690
+ if (frame) {
30691
+ for (let i = 0; i < clampedCount; i++) {
30692
+ const p = frame[i];
30693
+ if (p) writeDiePosition(i, p.x, p.y);
30694
+ }
30695
+ currentPositionsRef.current = frame.slice(0, clampedCount);
30619
30696
  }
30620
- return n;
30621
- });
30622
- const stepMs = 40;
30623
- for (let s = 0; s < frames.length; s++) {
30624
- const timer = setTimeout(() => {
30625
- setPositions(frames[s].slice(0, clampedCount));
30626
- }, s * stepMs);
30627
- timersRef.current.push(timer);
30628
- }
30697
+ if (progress < 1) {
30698
+ rafHandleRef.current = requestAnimationFrame(tick);
30699
+ } else {
30700
+ rafHandleRef.current = null;
30701
+ for (let i = 0; i < clampedCount; i++) {
30702
+ const el = dieWrapperRefs.current[i];
30703
+ if (el)
30704
+ el.style.transition = "transform 0.35s cubic-bezier(0.25,0.46,0.45,0.94)";
30705
+ const shadow = shadowRefs.current[i];
30706
+ if (shadow) shadow.style.opacity = "0.85";
30707
+ }
30708
+ }
30709
+ };
30710
+ rafHandleRef.current = requestAnimationFrame(tick);
30629
30711
  requestAnimationFrame(() => {
30630
30712
  requestAnimationFrame(() => {
30631
- setRotations((prev) => {
30632
- const n = [...prev];
30633
- for (let i = 0; i < clampedCount; i++) {
30634
- const tgt = SHOW_ROT[vals[i]];
30635
- n[i] = {
30636
- x: tgt.x + (Math.random() > 0.5 ? 720 : -720),
30637
- y: tgt.y,
30638
- z: (Math.random() > 0.5 ? 1 : -1) * 360,
30639
- tr: true
30640
- };
30641
- }
30642
- return n;
30643
- });
30713
+ for (let i = 0; i < clampedCount; i++) {
30714
+ const tgt = SHOW_ROT[vals[i]];
30715
+ const lx = tgt.x + (Math.random() > 0.5 ? 720 : -720);
30716
+ const ly = tgt.y;
30717
+ const lz = (Math.random() > 0.5 ? 1 : -1) * 360;
30718
+ writeCubeRotation(i, lx, ly, lz, true);
30719
+ }
30644
30720
  });
30645
30721
  });
30646
30722
  const settleTimer = setTimeout(() => {
30647
30723
  setResults(vals);
30648
30724
  setRolling(false);
30725
+ rollingRef.current = false;
30649
30726
  const total2 = vals.reduce((a, b) => a + b, 0);
30650
30727
  onRoll?.(vals, total2);
30651
30728
  if (showHistory) {
30652
30729
  setHistory((prev) => [{ vals, total: total2 }, ...prev].slice(0, historyMax));
30653
30730
  }
30654
- }, 1050);
30731
+ }, SETTLE_MS);
30655
30732
  timersRef.current.push(settleTimer);
30656
30733
  }, [
30657
- rolling,
30658
30734
  clampedCount,
30659
- positions,
30660
30735
  defaultPositions,
30661
30736
  effectiveSize,
30737
+ half,
30662
30738
  reducedMotion,
30663
30739
  onRoll,
30740
+ writeCubeRotation,
30741
+ writeDiePosition,
30664
30742
  showHistory,
30665
30743
  historyMax
30666
30744
  ]);
@@ -30679,10 +30757,13 @@ function DiceRoller({
30679
30757
  () => () => {
30680
30758
  timersRef.current.forEach((t) => clearTimeout(t));
30681
30759
  timersRef.current = [];
30760
+ if (rafHandleRef.current != null) {
30761
+ cancelAnimationFrame(rafHandleRef.current);
30762
+ rafHandleRef.current = null;
30763
+ }
30682
30764
  },
30683
30765
  []
30684
30766
  );
30685
- const activePositions = positions ?? defaultPositions(arena.w, arenaHeight, clampedCount);
30686
30767
  const total = results ? results.reduce((a, b) => a + b, 0) : null;
30687
30768
  return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
30688
30769
  "div",
@@ -30710,27 +30791,22 @@ function DiceRoller({
30710
30791
  cursor: trigger === "click" ? "pointer" : void 0
30711
30792
  },
30712
30793
  children: Array.from({ length: clampedCount }, (_, d) => {
30713
- const rot = rotations[d] ?? { x: 0, y: 0, z: 0, tr: true };
30714
- const pos = activePositions[d] ?? {
30715
- x: arena.w / 2,
30716
- y: arenaHeight / 2
30717
- };
30718
- const translate = `translate3d(${pos.x - half}px, ${pos.y - half}px, 0)`;
30719
30794
  return /* @__PURE__ */ (0, import_jsx_runtime114.jsxs)(
30720
30795
  "div",
30721
30796
  {
30797
+ ref: (el) => {
30798
+ dieWrapperRefs.current[d] = el;
30799
+ },
30722
30800
  style: {
30723
30801
  position: "absolute",
30724
30802
  left: 0,
30725
30803
  top: 0,
30726
30804
  width: effectiveSize,
30727
30805
  height: effectiveSize,
30728
- transform: translate,
30729
30806
  // Parent must preserve 3D so the inner cube's rotateX/Y/Z
30730
30807
  // still renders with depth — otherwise adding a transform
30731
30808
  // to the wrapper would flatten its children into 2D.
30732
30809
  transformStyle: "preserve-3d",
30733
- transition: rolling ? "transform 0.04s linear" : "transform 0.35s cubic-bezier(0.25,0.46,0.45,0.94)",
30734
30810
  willChange: "transform",
30735
30811
  zIndex: 2,
30736
30812
  perspective: 700
@@ -30739,6 +30815,9 @@ function DiceRoller({
30739
30815
  /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
30740
30816
  "div",
30741
30817
  {
30818
+ ref: (el) => {
30819
+ shadowRefs.current[d] = el;
30820
+ },
30742
30821
  style: {
30743
30822
  position: "absolute",
30744
30823
  bottom: -6,
@@ -30748,7 +30827,7 @@ function DiceRoller({
30748
30827
  background: `radial-gradient(ellipse,${colors.shadow} 0%,transparent 70%)`,
30749
30828
  borderRadius: "50%",
30750
30829
  pointerEvents: "none",
30751
- opacity: rolling ? 0.2 : 0.85,
30830
+ opacity: 0.85,
30752
30831
  transition: "opacity 0.3s"
30753
30832
  }
30754
30833
  }
@@ -30756,13 +30835,14 @@ function DiceRoller({
30756
30835
  /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(
30757
30836
  "div",
30758
30837
  {
30838
+ ref: (el) => {
30839
+ cubeRefs.current[d] = el;
30840
+ },
30759
30841
  style: {
30760
30842
  width: "100%",
30761
30843
  height: "100%",
30762
30844
  position: "relative",
30763
30845
  transformStyle: "preserve-3d",
30764
- transition: rot.tr ? "transform 0.95s cubic-bezier(0.12,0.8,0.22,1)" : "none",
30765
- transform: `rotateX(${rot.x}deg) rotateY(${rot.y}deg) rotateZ(${rot.z}deg)`,
30766
30846
  willChange: "transform"
30767
30847
  },
30768
30848
  children: [1, 2, 3, 4, 5, 6].map((val, fi) => /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(