@bug-on/m3-expressive 1.2.6 → 1.2.7

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.
@@ -5,7 +5,7 @@ import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import * as RxContextMenu from '@radix-ui/react-context-menu';
8
- import { AnimatePresence, m, LazyMotion, domMax, useMotionValue, animate, useAnimationFrame, useReducedMotion, LayoutGroup, useScroll, useMotionValueEvent, useTransform } from 'motion/react';
8
+ import { AnimatePresence, m, LazyMotion, domMax, useAnimationFrame, useMotionValue, animate, useReducedMotion, LayoutGroup, useScroll, useMotionValueEvent, useTransform } from 'motion/react';
9
9
  import { cornerRadius } from '@bug-on/m3-tokens';
10
10
  import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
11
11
  import { Slot } from '@radix-ui/react-slot';
@@ -6315,7 +6315,7 @@ function generateWavyCircularPath(center, radius, amplitude, wavelength) {
6315
6315
  if (i === 0) d += `M ${xAt(t0).toFixed(2)} ${yAt(t0).toFixed(2)}`;
6316
6316
  d += ` C ${cp1x.toFixed(2)} ${cp1y.toFixed(2)}, ${cp2x.toFixed(2)} ${cp2y.toFixed(2)}, ${xAt(t1).toFixed(2)} ${yAt(t1).toFixed(2)}`;
6317
6317
  }
6318
- return d;
6318
+ return `${d} Z`;
6319
6319
  }
6320
6320
  function getSinePath(startX, endX, phase, wl, amp) {
6321
6321
  if (startX >= endX) return "";
@@ -6347,6 +6347,14 @@ function getSinePath(startX, endX, phase, wl, amp) {
6347
6347
  }
6348
6348
  return d;
6349
6349
  }
6350
+ var GLOBAL_ROTATION_DURATION = 6e3;
6351
+ var GLOBAL_ROTATION_TARGET = 1080;
6352
+ var ADDITIONAL_ROTATION_CYCLE = 1500;
6353
+ var ADDITIONAL_ROTATION_STEP = 90;
6354
+ var ADDITIONAL_ROTATION_EASE_DURATION = 500;
6355
+ var DEFAULT_MIN_PROGRESS = 0.1;
6356
+ var DEFAULT_MAX_PROGRESS = 0.8;
6357
+ var PROGRESS_CYCLE_DURATION = 1500;
6350
6358
  var CircularProgress = React37.forwardRef(
6351
6359
  (_a, ref) => {
6352
6360
  var _b = _a, {
@@ -6360,6 +6368,10 @@ var CircularProgress = React37.forwardRef(
6360
6368
  crawlerSpeed = 1,
6361
6369
  color,
6362
6370
  trackColor,
6371
+ showTrack = "auto",
6372
+ minProgress = DEFAULT_MIN_PROGRESS,
6373
+ maxProgress = DEFAULT_MAX_PROGRESS,
6374
+ amplitudeRange,
6363
6375
  className,
6364
6376
  "aria-label": ariaLabel
6365
6377
  } = _b, restProps = __objRest(_b, [
@@ -6373,6 +6385,10 @@ var CircularProgress = React37.forwardRef(
6373
6385
  "crawlerSpeed",
6374
6386
  "color",
6375
6387
  "trackColor",
6388
+ "showTrack",
6389
+ "minProgress",
6390
+ "maxProgress",
6391
+ "amplitudeRange",
6376
6392
  "className",
6377
6393
  "aria-label"
6378
6394
  ]);
@@ -6383,6 +6399,7 @@ var CircularProgress = React37.forwardRef(
6383
6399
  const activeColor = color || "var(--md-sys-color-indicator-active)";
6384
6400
  const bgTrackColor = trackColor || "var(--md-sys-color-indicator-track)";
6385
6401
  const isWavy = shape === "wavy";
6402
+ const shouldShowIndeterminateTrack = showTrack === "auto" ? isWavy : showTrack;
6386
6403
  const BASELINE_SIZE = 48;
6387
6404
  const scaleFactor = size / BASELINE_SIZE;
6388
6405
  const effectiveAmplitude = React37.useMemo(
@@ -6393,6 +6410,10 @@ var CircularProgress = React37.forwardRef(
6393
6410
  () => wavelength != null ? wavelength : 15 * scaleFactor,
6394
6411
  [wavelength, scaleFactor]
6395
6412
  );
6413
+ const resolvedAmplitudeRange = React37.useMemo(
6414
+ () => amplitudeRange != null ? amplitudeRange : [0, effectiveAmplitude],
6415
+ [amplitudeRange, effectiveAmplitude]
6416
+ );
6396
6417
  const wavyActivePath = React37.useMemo(
6397
6418
  () => isWavy ? generateWavyCircularPath(
6398
6419
  center,
@@ -6412,6 +6433,145 @@ var CircularProgress = React37.forwardRef(
6412
6433
  const trackLength = isDeterminate ? Math.max(1e-3, 1 - activeAngularFraction - 2 * gapForTrack) : 1;
6413
6434
  const ActiveCircleElem = m.circle;
6414
6435
  const ActivePathElem = m.path;
6436
+ const indeterminateSvgRef = React37.useRef(null);
6437
+ const indeterminateTrackRef = React37.useRef(null);
6438
+ const indeterminateActiveRef = React37.useRef(null);
6439
+ const indeterminateWavyTrackPathRef = React37.useRef(null);
6440
+ const indeterminateWavyActivePathRef = React37.useRef(null);
6441
+ const cachedPathLengthRef = React37.useRef(0);
6442
+ React37.useLayoutEffect(() => {
6443
+ if (!isWavy || !wavyActivePath) {
6444
+ cachedPathLengthRef.current = circumference;
6445
+ return;
6446
+ }
6447
+ const el = indeterminateActiveRef.current;
6448
+ if (el && "getTotalLength" in el) {
6449
+ try {
6450
+ const len = el.getTotalLength();
6451
+ if (len > 0) {
6452
+ cachedPathLengthRef.current = len;
6453
+ return;
6454
+ }
6455
+ } catch (e) {
6456
+ }
6457
+ }
6458
+ cachedPathLengthRef.current = circumference;
6459
+ }, [isWavy, circumference, wavyActivePath]);
6460
+ useAnimationFrame((time) => {
6461
+ if (isDeterminate) return;
6462
+ const safeCrawlerSpeed = Math.max(0.1, crawlerSpeed);
6463
+ const scaledTime = time * safeCrawlerSpeed;
6464
+ const globalCycle = scaledTime % GLOBAL_ROTATION_DURATION;
6465
+ const globalAngle = globalCycle / GLOBAL_ROTATION_DURATION * GLOBAL_ROTATION_TARGET;
6466
+ const additionalFullCycles = Math.floor(
6467
+ scaledTime / ADDITIONAL_ROTATION_CYCLE
6468
+ );
6469
+ const additionalCycleTime = scaledTime % ADDITIONAL_ROTATION_CYCLE;
6470
+ const additionalEaseT = Math.min(
6471
+ 1,
6472
+ additionalCycleTime / ADDITIONAL_ROTATION_EASE_DURATION
6473
+ );
6474
+ const additionalAngle = (additionalFullCycles + easeInOutCubic(additionalEaseT)) * ADDITIONAL_ROTATION_STEP;
6475
+ const totalRotation = globalAngle + additionalAngle;
6476
+ if (indeterminateSvgRef.current) {
6477
+ indeterminateSvgRef.current.style.transform = `rotate(${totalRotation - 90}deg)`;
6478
+ }
6479
+ const progressFullCycle = PROGRESS_CYCLE_DURATION * 2;
6480
+ const progressCycleTime = scaledTime % progressFullCycle;
6481
+ let progress;
6482
+ if (progressCycleTime < PROGRESS_CYCLE_DURATION) {
6483
+ const t = progressCycleTime / PROGRESS_CYCLE_DURATION;
6484
+ progress = minProgress + (maxProgress - minProgress) * easeInOutCubic(t);
6485
+ } else {
6486
+ const t = (progressCycleTime - PROGRESS_CYCLE_DURATION) / PROGRESS_CYCLE_DURATION;
6487
+ progress = maxProgress - (maxProgress - minProgress) * easeInOutCubic(t);
6488
+ }
6489
+ if (isWavy) {
6490
+ const amplitudeT = (progress - minProgress) / (maxProgress - minProgress);
6491
+ const currentAmplitude = resolvedAmplitudeRange[0] + (resolvedAmplitudeRange[1] - resolvedAmplitudeRange[0]) * amplitudeT;
6492
+ const dynamicPath = generateWavyCircularPath(
6493
+ center,
6494
+ radius,
6495
+ currentAmplitude,
6496
+ effectiveWavelength
6497
+ );
6498
+ if (indeterminateWavyActivePathRef.current) {
6499
+ indeterminateWavyActivePathRef.current.setAttribute("d", dynamicPath);
6500
+ }
6501
+ if (indeterminateWavyTrackPathRef.current) {
6502
+ indeterminateWavyTrackPathRef.current.setAttribute("d", dynamicPath);
6503
+ }
6504
+ const pathEl = indeterminateWavyActivePathRef.current;
6505
+ let totalLen = cachedPathLengthRef.current || circumference;
6506
+ if (pathEl) {
6507
+ try {
6508
+ const len = pathEl.getTotalLength();
6509
+ if (len > 0) totalLen = len;
6510
+ } catch (e) {
6511
+ }
6512
+ }
6513
+ const gapFrac = (gapSize + trackHeight) / totalLen;
6514
+ const activeLen = totalLen * progress;
6515
+ const activeOff = 0;
6516
+ if (indeterminateWavyActivePathRef.current) {
6517
+ indeterminateWavyActivePathRef.current.setAttribute(
6518
+ "stroke-dasharray",
6519
+ `${activeLen} ${totalLen}`
6520
+ );
6521
+ indeterminateWavyActivePathRef.current.setAttribute(
6522
+ "stroke-dashoffset",
6523
+ `${activeOff}`
6524
+ );
6525
+ }
6526
+ if (shouldShowIndeterminateTrack && indeterminateWavyTrackPathRef.current) {
6527
+ const trackStartFrac = progress + gapFrac;
6528
+ const trackLen = Math.max(
6529
+ 1e-3,
6530
+ totalLen * (1 - progress - 2 * gapFrac)
6531
+ );
6532
+ const trackOff = -totalLen * trackStartFrac;
6533
+ indeterminateWavyTrackPathRef.current.setAttribute(
6534
+ "stroke-dasharray",
6535
+ `${trackLen} ${totalLen}`
6536
+ );
6537
+ indeterminateWavyTrackPathRef.current.setAttribute(
6538
+ "stroke-dashoffset",
6539
+ `${trackOff}`
6540
+ );
6541
+ }
6542
+ } else {
6543
+ const totalLen = circumference;
6544
+ const activeLen = totalLen * progress;
6545
+ const activeOff = 0;
6546
+ if (indeterminateActiveRef.current) {
6547
+ indeterminateActiveRef.current.setAttribute(
6548
+ "stroke-dasharray",
6549
+ `${activeLen} ${totalLen}`
6550
+ );
6551
+ indeterminateActiveRef.current.setAttribute(
6552
+ "stroke-dashoffset",
6553
+ `${activeOff}`
6554
+ );
6555
+ }
6556
+ if (shouldShowIndeterminateTrack && indeterminateTrackRef.current) {
6557
+ const gapFrac = (gapSize + trackHeight) / totalLen;
6558
+ const trackStartFrac = progress + gapFrac;
6559
+ const trackLen = Math.max(
6560
+ 1e-3,
6561
+ totalLen * (1 - progress - 2 * gapFrac)
6562
+ );
6563
+ const trackOff = -totalLen * trackStartFrac;
6564
+ indeterminateTrackRef.current.setAttribute(
6565
+ "stroke-dasharray",
6566
+ `${trackLen} ${totalLen}`
6567
+ );
6568
+ indeterminateTrackRef.current.setAttribute(
6569
+ "stroke-dashoffset",
6570
+ `${trackOff}`
6571
+ );
6572
+ }
6573
+ }
6574
+ });
6415
6575
  return /* @__PURE__ */ jsx(
6416
6576
  "div",
6417
6577
  __spreadProps(__spreadValues({
@@ -6488,9 +6648,10 @@ var CircularProgress = React37.forwardRef(
6488
6648
  ]
6489
6649
  }
6490
6650
  ),
6491
- !isDeterminate && /* @__PURE__ */ jsxs(
6492
- m.svg,
6651
+ !isDeterminate && /* @__PURE__ */ jsx(
6652
+ "svg",
6493
6653
  {
6654
+ ref: indeterminateSvgRef,
6494
6655
  width: size,
6495
6656
  height: size,
6496
6657
  viewBox: `0 0 ${size} ${size}`,
@@ -6499,84 +6660,60 @@ var CircularProgress = React37.forwardRef(
6499
6660
  position: "absolute",
6500
6661
  inset: 0,
6501
6662
  overflow: "visible",
6502
- transformOrigin: "center"
6503
- },
6504
- animate: { rotate: [0, 360] },
6505
- transition: {
6506
- duration: 2 / Math.max(0.1, crawlerSpeed),
6507
- repeat: Number.POSITIVE_INFINITY,
6508
- ease: "linear"
6663
+ transformOrigin: "center",
6664
+ transform: "rotate(-90deg)"
6509
6665
  },
6510
- children: [
6511
- /* @__PURE__ */ jsx(
6512
- m.circle,
6666
+ children: isWavy ? /* @__PURE__ */ jsxs(Fragment, { children: [
6667
+ shouldShowIndeterminateTrack && /* @__PURE__ */ jsx(
6668
+ "path",
6513
6669
  {
6514
- cx: center,
6515
- cy: center,
6516
- r: radius,
6670
+ ref: indeterminateWavyTrackPathRef,
6671
+ d: wavyActivePath != null ? wavyActivePath : "",
6517
6672
  fill: "none",
6518
6673
  stroke: bgTrackColor,
6519
6674
  strokeWidth: trackHeight,
6520
- strokeLinecap: "round",
6521
- animate: {
6522
- pathLength: [
6523
- Math.max(1e-3, 0.9 - 2 * gapForTrack),
6524
- Math.max(1e-3, 0.25 - 2 * gapForTrack),
6525
- Math.max(1e-3, 0.9 - 2 * gapForTrack)
6526
- ],
6527
- pathOffset: [
6528
- 0.1 + gapForTrack,
6529
- 0.75 + gapForTrack,
6530
- 0.1 + gapForTrack
6531
- ]
6532
- },
6533
- transition: {
6534
- duration: 2 / Math.max(0.1, crawlerSpeed),
6535
- repeat: Number.POSITIVE_INFINITY,
6536
- ease: [0.4, 0, 0.2, 1]
6537
- }
6675
+ strokeLinecap: "round"
6538
6676
  }
6539
6677
  ),
6540
- isWavy ? /* @__PURE__ */ jsx(
6541
- ActivePathElem,
6678
+ /* @__PURE__ */ jsx(
6679
+ "path",
6542
6680
  {
6681
+ ref: indeterminateWavyActivePathRef,
6543
6682
  d: wavyActivePath != null ? wavyActivePath : "",
6544
6683
  fill: "none",
6545
6684
  stroke: activeColor,
6546
6685
  strokeWidth: trackHeight,
6547
- strokeLinecap: "round",
6548
- animate: {
6549
- pathLength: [0.1, 0.75, 0.1],
6550
- pathOffset: [0, 0.65, 1]
6551
- },
6552
- transition: {
6553
- duration: 2 / Math.max(0.1, crawlerSpeed),
6554
- repeat: Number.POSITIVE_INFINITY,
6555
- ease: [0.4, 0, 0.2, 1]
6556
- }
6686
+ strokeLinecap: "round"
6557
6687
  }
6558
- ) : /* @__PURE__ */ jsx(
6559
- ActiveCircleElem,
6688
+ )
6689
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6690
+ shouldShowIndeterminateTrack && /* @__PURE__ */ jsx(
6691
+ "circle",
6560
6692
  {
6693
+ ref: indeterminateTrackRef,
6694
+ cx: center,
6695
+ cy: center,
6696
+ r: radius,
6697
+ fill: "none",
6698
+ stroke: bgTrackColor,
6699
+ strokeWidth: trackHeight,
6700
+ strokeLinecap: "round"
6701
+ }
6702
+ ),
6703
+ /* @__PURE__ */ jsx(
6704
+ "circle",
6705
+ {
6706
+ ref: indeterminateActiveRef,
6561
6707
  cx: center,
6562
6708
  cy: center,
6563
6709
  r: radius,
6564
6710
  fill: "none",
6565
6711
  stroke: activeColor,
6566
6712
  strokeWidth: trackHeight,
6567
- strokeLinecap: "round",
6568
- animate: {
6569
- pathLength: [0.1, 0.75, 0.1],
6570
- pathOffset: [0, 0.65, 1]
6571
- },
6572
- transition: {
6573
- duration: 2 / Math.max(0.1, crawlerSpeed),
6574
- repeat: Number.POSITIVE_INFINITY,
6575
- ease: [0.4, 0, 0.2, 1]
6576
- }
6713
+ strokeLinecap: "round"
6577
6714
  }
6578
6715
  )
6579
- ]
6716
+ ] })
6580
6717
  }
6581
6718
  )
6582
6719
  ] })
@@ -6782,7 +6919,7 @@ var WavyLinearTrack = React37.memo(function WavyLinearTrack2({
6782
6919
  currentAmp
6783
6920
  );
6784
6921
  } else if (fraction === 0) {
6785
- activePathD = `M ${capWidth} 0 L ${capWidth + 0.01} 0`;
6922
+ activePathD = "";
6786
6923
  }
6787
6924
  const trackStart = adjHead + totalGap;
6788
6925
  if (trackStart < width - capWidth) {
@@ -6814,20 +6951,20 @@ var WavyLinearTrack = React37.memo(function WavyLinearTrack2({
6814
6951
  activeLines.push({ tail: l1T, head: l1H });
6815
6952
  activeLines.push({ tail: l2T, head: l2H });
6816
6953
  }
6817
- const segments = activeLines.map((line) => {
6818
- const barTail = line.tail * width;
6819
- const barHead = line.head * width;
6954
+ const activeSegments = activeLines.map((line) => {
6955
+ const rawTail = line.tail * width;
6956
+ const rawHead = line.head * width;
6820
6957
  const adjTail = Math.max(
6821
6958
  capWidth,
6822
- Math.min(width - capWidth, barTail)
6959
+ Math.min(width - capWidth, rawTail)
6823
6960
  );
6824
6961
  const adjHead = Math.max(
6825
6962
  capWidth,
6826
- Math.min(width - capWidth, barHead)
6963
+ Math.min(width - capWidth, rawHead)
6827
6964
  );
6828
6965
  return { adjTail, adjHead };
6829
6966
  }).filter((seg) => seg.adjHead - seg.adjTail > 0.1);
6830
- activePathD = segments.map(
6967
+ activePathD = activeSegments.map(
6831
6968
  (seg) => getSinePath(
6832
6969
  seg.adjTail,
6833
6970
  seg.adjHead,
@@ -6836,13 +6973,24 @@ var WavyLinearTrack = React37.memo(function WavyLinearTrack2({
6836
6973
  currentAmp
6837
6974
  )
6838
6975
  ).join(" ");
6976
+ const validActiveLines = activeLines.filter(
6977
+ (line) => line.head > line.tail && line.head * width > 0 && line.tail * width < width
6978
+ ).sort((a, b) => a.tail - b.tail);
6839
6979
  let currentTrackX = capWidth;
6840
- for (const seg of segments) {
6841
- const trackEnd = seg.adjTail - totalGap;
6980
+ for (const line of validActiveLines) {
6981
+ const blockStart = line.tail * width - totalGap;
6982
+ const blockEnd = line.head * width + totalGap;
6983
+ const trackEnd = Math.min(width - capWidth, blockStart);
6842
6984
  if (trackEnd > currentTrackX) {
6843
- trackD += `${getSinePath(currentTrackX, trackEnd, phase, activeWavelength, trackAmp)} `;
6985
+ trackD += `${getSinePath(
6986
+ currentTrackX,
6987
+ trackEnd,
6988
+ phase,
6989
+ activeWavelength,
6990
+ trackAmp
6991
+ )} `;
6844
6992
  }
6845
- currentTrackX = Math.max(currentTrackX, seg.adjHead + totalGap);
6993
+ currentTrackX = Math.max(currentTrackX, blockEnd);
6846
6994
  }
6847
6995
  if (currentTrackX < width - capWidth) {
6848
6996
  trackD += getSinePath(
@@ -6855,9 +7003,9 @@ var WavyLinearTrack = React37.memo(function WavyLinearTrack2({
6855
7003
  }
6856
7004
  }
6857
7005
  if (activePathRef.current)
6858
- activePathRef.current.setAttribute("d", activePathD);
7006
+ activePathRef.current.setAttribute("d", activePathD || "");
6859
7007
  if (trackPathRef.current)
6860
- trackPathRef.current.setAttribute("d", trackD.trim());
7008
+ trackPathRef.current.setAttribute("d", trackD.trim() || "");
6861
7009
  });
6862
7010
  return /* @__PURE__ */ jsx(
6863
7011
  "div",