@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.
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import * as RxContextMenu from '@radix-ui/react-context-menu';
9
- import { AnimatePresence, m, LazyMotion, domMax, useReducedMotion, useMotionValue, animate, useAnimationFrame, useSpring, useTransform, LayoutGroup, useScroll, useMotionValueEvent } from 'motion/react';
9
+ import { AnimatePresence, m, LazyMotion, domMax, useReducedMotion, useAnimationFrame, useMotionValue, animate, useSpring, useTransform, LayoutGroup, useScroll, useMotionValueEvent } from 'motion/react';
10
10
  import { cornerRadius } from '@bug-on/m3-tokens';
11
11
  import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
12
12
  import { Slot } from '@radix-ui/react-slot';
@@ -5689,7 +5689,7 @@ function generateWavyCircularPath(center, radius, amplitude, wavelength) {
5689
5689
  if (i === 0) d += `M ${xAt(t0).toFixed(2)} ${yAt(t0).toFixed(2)}`;
5690
5690
  d += ` C ${cp1x.toFixed(2)} ${cp1y.toFixed(2)}, ${cp2x.toFixed(2)} ${cp2y.toFixed(2)}, ${xAt(t1).toFixed(2)} ${yAt(t1).toFixed(2)}`;
5691
5691
  }
5692
- return d;
5692
+ return `${d} Z`;
5693
5693
  }
5694
5694
  function getSinePath(startX, endX, phase, wl, amp) {
5695
5695
  if (startX >= endX) return "";
@@ -5721,6 +5721,14 @@ function getSinePath(startX, endX, phase, wl, amp) {
5721
5721
  }
5722
5722
  return d;
5723
5723
  }
5724
+ var GLOBAL_ROTATION_DURATION = 6e3;
5725
+ var GLOBAL_ROTATION_TARGET = 1080;
5726
+ var ADDITIONAL_ROTATION_CYCLE = 1500;
5727
+ var ADDITIONAL_ROTATION_STEP = 90;
5728
+ var ADDITIONAL_ROTATION_EASE_DURATION = 500;
5729
+ var DEFAULT_MIN_PROGRESS = 0.1;
5730
+ var DEFAULT_MAX_PROGRESS = 0.8;
5731
+ var PROGRESS_CYCLE_DURATION = 1500;
5724
5732
  var CircularProgress = React62.forwardRef(
5725
5733
  (_a, ref) => {
5726
5734
  var _b = _a, {
@@ -5734,6 +5742,10 @@ var CircularProgress = React62.forwardRef(
5734
5742
  crawlerSpeed = 1,
5735
5743
  color,
5736
5744
  trackColor,
5745
+ showTrack = "auto",
5746
+ minProgress = DEFAULT_MIN_PROGRESS,
5747
+ maxProgress = DEFAULT_MAX_PROGRESS,
5748
+ amplitudeRange,
5737
5749
  className,
5738
5750
  "aria-label": ariaLabel
5739
5751
  } = _b, restProps = __objRest(_b, [
@@ -5747,6 +5759,10 @@ var CircularProgress = React62.forwardRef(
5747
5759
  "crawlerSpeed",
5748
5760
  "color",
5749
5761
  "trackColor",
5762
+ "showTrack",
5763
+ "minProgress",
5764
+ "maxProgress",
5765
+ "amplitudeRange",
5750
5766
  "className",
5751
5767
  "aria-label"
5752
5768
  ]);
@@ -5757,6 +5773,7 @@ var CircularProgress = React62.forwardRef(
5757
5773
  const activeColor = color || "var(--md-sys-color-indicator-active)";
5758
5774
  const bgTrackColor = trackColor || "var(--md-sys-color-indicator-track)";
5759
5775
  const isWavy = shape === "wavy";
5776
+ const shouldShowIndeterminateTrack = showTrack === "auto" ? isWavy : showTrack;
5760
5777
  const BASELINE_SIZE = 48;
5761
5778
  const scaleFactor = size / BASELINE_SIZE;
5762
5779
  const effectiveAmplitude = React62.useMemo(
@@ -5767,6 +5784,10 @@ var CircularProgress = React62.forwardRef(
5767
5784
  () => wavelength != null ? wavelength : 15 * scaleFactor,
5768
5785
  [wavelength, scaleFactor]
5769
5786
  );
5787
+ const resolvedAmplitudeRange = React62.useMemo(
5788
+ () => amplitudeRange != null ? amplitudeRange : [0, effectiveAmplitude],
5789
+ [amplitudeRange, effectiveAmplitude]
5790
+ );
5770
5791
  const wavyActivePath = React62.useMemo(
5771
5792
  () => isWavy ? generateWavyCircularPath(
5772
5793
  center,
@@ -5786,6 +5807,145 @@ var CircularProgress = React62.forwardRef(
5786
5807
  const trackLength = isDeterminate ? Math.max(1e-3, 1 - activeAngularFraction - 2 * gapForTrack) : 1;
5787
5808
  const ActiveCircleElem = m.circle;
5788
5809
  const ActivePathElem = m.path;
5810
+ const indeterminateSvgRef = React62.useRef(null);
5811
+ const indeterminateTrackRef = React62.useRef(null);
5812
+ const indeterminateActiveRef = React62.useRef(null);
5813
+ const indeterminateWavyTrackPathRef = React62.useRef(null);
5814
+ const indeterminateWavyActivePathRef = React62.useRef(null);
5815
+ const cachedPathLengthRef = React62.useRef(0);
5816
+ React62.useLayoutEffect(() => {
5817
+ if (!isWavy || !wavyActivePath) {
5818
+ cachedPathLengthRef.current = circumference;
5819
+ return;
5820
+ }
5821
+ const el = indeterminateActiveRef.current;
5822
+ if (el && "getTotalLength" in el) {
5823
+ try {
5824
+ const len = el.getTotalLength();
5825
+ if (len > 0) {
5826
+ cachedPathLengthRef.current = len;
5827
+ return;
5828
+ }
5829
+ } catch (e) {
5830
+ }
5831
+ }
5832
+ cachedPathLengthRef.current = circumference;
5833
+ }, [isWavy, circumference, wavyActivePath]);
5834
+ useAnimationFrame((time) => {
5835
+ if (isDeterminate) return;
5836
+ const safeCrawlerSpeed = Math.max(0.1, crawlerSpeed);
5837
+ const scaledTime = time * safeCrawlerSpeed;
5838
+ const globalCycle = scaledTime % GLOBAL_ROTATION_DURATION;
5839
+ const globalAngle = globalCycle / GLOBAL_ROTATION_DURATION * GLOBAL_ROTATION_TARGET;
5840
+ const additionalFullCycles = Math.floor(
5841
+ scaledTime / ADDITIONAL_ROTATION_CYCLE
5842
+ );
5843
+ const additionalCycleTime = scaledTime % ADDITIONAL_ROTATION_CYCLE;
5844
+ const additionalEaseT = Math.min(
5845
+ 1,
5846
+ additionalCycleTime / ADDITIONAL_ROTATION_EASE_DURATION
5847
+ );
5848
+ const additionalAngle = (additionalFullCycles + easeInOutCubic(additionalEaseT)) * ADDITIONAL_ROTATION_STEP;
5849
+ const totalRotation = globalAngle + additionalAngle;
5850
+ if (indeterminateSvgRef.current) {
5851
+ indeterminateSvgRef.current.style.transform = `rotate(${totalRotation - 90}deg)`;
5852
+ }
5853
+ const progressFullCycle = PROGRESS_CYCLE_DURATION * 2;
5854
+ const progressCycleTime = scaledTime % progressFullCycle;
5855
+ let progress;
5856
+ if (progressCycleTime < PROGRESS_CYCLE_DURATION) {
5857
+ const t = progressCycleTime / PROGRESS_CYCLE_DURATION;
5858
+ progress = minProgress + (maxProgress - minProgress) * easeInOutCubic(t);
5859
+ } else {
5860
+ const t = (progressCycleTime - PROGRESS_CYCLE_DURATION) / PROGRESS_CYCLE_DURATION;
5861
+ progress = maxProgress - (maxProgress - minProgress) * easeInOutCubic(t);
5862
+ }
5863
+ if (isWavy) {
5864
+ const amplitudeT = (progress - minProgress) / (maxProgress - minProgress);
5865
+ const currentAmplitude = resolvedAmplitudeRange[0] + (resolvedAmplitudeRange[1] - resolvedAmplitudeRange[0]) * amplitudeT;
5866
+ const dynamicPath = generateWavyCircularPath(
5867
+ center,
5868
+ radius,
5869
+ currentAmplitude,
5870
+ effectiveWavelength
5871
+ );
5872
+ if (indeterminateWavyActivePathRef.current) {
5873
+ indeterminateWavyActivePathRef.current.setAttribute("d", dynamicPath);
5874
+ }
5875
+ if (indeterminateWavyTrackPathRef.current) {
5876
+ indeterminateWavyTrackPathRef.current.setAttribute("d", dynamicPath);
5877
+ }
5878
+ const pathEl = indeterminateWavyActivePathRef.current;
5879
+ let totalLen = cachedPathLengthRef.current || circumference;
5880
+ if (pathEl) {
5881
+ try {
5882
+ const len = pathEl.getTotalLength();
5883
+ if (len > 0) totalLen = len;
5884
+ } catch (e) {
5885
+ }
5886
+ }
5887
+ const gapFrac = (gapSize + trackHeight) / totalLen;
5888
+ const activeLen = totalLen * progress;
5889
+ const activeOff = 0;
5890
+ if (indeterminateWavyActivePathRef.current) {
5891
+ indeterminateWavyActivePathRef.current.setAttribute(
5892
+ "stroke-dasharray",
5893
+ `${activeLen} ${totalLen}`
5894
+ );
5895
+ indeterminateWavyActivePathRef.current.setAttribute(
5896
+ "stroke-dashoffset",
5897
+ `${activeOff}`
5898
+ );
5899
+ }
5900
+ if (shouldShowIndeterminateTrack && indeterminateWavyTrackPathRef.current) {
5901
+ const trackStartFrac = progress + gapFrac;
5902
+ const trackLen = Math.max(
5903
+ 1e-3,
5904
+ totalLen * (1 - progress - 2 * gapFrac)
5905
+ );
5906
+ const trackOff = -totalLen * trackStartFrac;
5907
+ indeterminateWavyTrackPathRef.current.setAttribute(
5908
+ "stroke-dasharray",
5909
+ `${trackLen} ${totalLen}`
5910
+ );
5911
+ indeterminateWavyTrackPathRef.current.setAttribute(
5912
+ "stroke-dashoffset",
5913
+ `${trackOff}`
5914
+ );
5915
+ }
5916
+ } else {
5917
+ const totalLen = circumference;
5918
+ const activeLen = totalLen * progress;
5919
+ const activeOff = 0;
5920
+ if (indeterminateActiveRef.current) {
5921
+ indeterminateActiveRef.current.setAttribute(
5922
+ "stroke-dasharray",
5923
+ `${activeLen} ${totalLen}`
5924
+ );
5925
+ indeterminateActiveRef.current.setAttribute(
5926
+ "stroke-dashoffset",
5927
+ `${activeOff}`
5928
+ );
5929
+ }
5930
+ if (shouldShowIndeterminateTrack && indeterminateTrackRef.current) {
5931
+ const gapFrac = (gapSize + trackHeight) / totalLen;
5932
+ const trackStartFrac = progress + gapFrac;
5933
+ const trackLen = Math.max(
5934
+ 1e-3,
5935
+ totalLen * (1 - progress - 2 * gapFrac)
5936
+ );
5937
+ const trackOff = -totalLen * trackStartFrac;
5938
+ indeterminateTrackRef.current.setAttribute(
5939
+ "stroke-dasharray",
5940
+ `${trackLen} ${totalLen}`
5941
+ );
5942
+ indeterminateTrackRef.current.setAttribute(
5943
+ "stroke-dashoffset",
5944
+ `${trackOff}`
5945
+ );
5946
+ }
5947
+ }
5948
+ });
5789
5949
  return /* @__PURE__ */ jsx(
5790
5950
  "div",
5791
5951
  __spreadProps(__spreadValues({
@@ -5862,9 +6022,10 @@ var CircularProgress = React62.forwardRef(
5862
6022
  ]
5863
6023
  }
5864
6024
  ),
5865
- !isDeterminate && /* @__PURE__ */ jsxs(
5866
- m.svg,
6025
+ !isDeterminate && /* @__PURE__ */ jsx(
6026
+ "svg",
5867
6027
  {
6028
+ ref: indeterminateSvgRef,
5868
6029
  width: size,
5869
6030
  height: size,
5870
6031
  viewBox: `0 0 ${size} ${size}`,
@@ -5873,84 +6034,60 @@ var CircularProgress = React62.forwardRef(
5873
6034
  position: "absolute",
5874
6035
  inset: 0,
5875
6036
  overflow: "visible",
5876
- transformOrigin: "center"
5877
- },
5878
- animate: { rotate: [0, 360] },
5879
- transition: {
5880
- duration: 2 / Math.max(0.1, crawlerSpeed),
5881
- repeat: Number.POSITIVE_INFINITY,
5882
- ease: "linear"
6037
+ transformOrigin: "center",
6038
+ transform: "rotate(-90deg)"
5883
6039
  },
5884
- children: [
5885
- /* @__PURE__ */ jsx(
5886
- m.circle,
6040
+ children: isWavy ? /* @__PURE__ */ jsxs(Fragment, { children: [
6041
+ shouldShowIndeterminateTrack && /* @__PURE__ */ jsx(
6042
+ "path",
5887
6043
  {
5888
- cx: center,
5889
- cy: center,
5890
- r: radius,
6044
+ ref: indeterminateWavyTrackPathRef,
6045
+ d: wavyActivePath != null ? wavyActivePath : "",
5891
6046
  fill: "none",
5892
6047
  stroke: bgTrackColor,
5893
6048
  strokeWidth: trackHeight,
5894
- strokeLinecap: "round",
5895
- animate: {
5896
- pathLength: [
5897
- Math.max(1e-3, 0.9 - 2 * gapForTrack),
5898
- Math.max(1e-3, 0.25 - 2 * gapForTrack),
5899
- Math.max(1e-3, 0.9 - 2 * gapForTrack)
5900
- ],
5901
- pathOffset: [
5902
- 0.1 + gapForTrack,
5903
- 0.75 + gapForTrack,
5904
- 0.1 + gapForTrack
5905
- ]
5906
- },
5907
- transition: {
5908
- duration: 2 / Math.max(0.1, crawlerSpeed),
5909
- repeat: Number.POSITIVE_INFINITY,
5910
- ease: [0.4, 0, 0.2, 1]
5911
- }
6049
+ strokeLinecap: "round"
5912
6050
  }
5913
6051
  ),
5914
- isWavy ? /* @__PURE__ */ jsx(
5915
- ActivePathElem,
6052
+ /* @__PURE__ */ jsx(
6053
+ "path",
5916
6054
  {
6055
+ ref: indeterminateWavyActivePathRef,
5917
6056
  d: wavyActivePath != null ? wavyActivePath : "",
5918
6057
  fill: "none",
5919
6058
  stroke: activeColor,
5920
6059
  strokeWidth: trackHeight,
5921
- strokeLinecap: "round",
5922
- animate: {
5923
- pathLength: [0.1, 0.75, 0.1],
5924
- pathOffset: [0, 0.65, 1]
5925
- },
5926
- transition: {
5927
- duration: 2 / Math.max(0.1, crawlerSpeed),
5928
- repeat: Number.POSITIVE_INFINITY,
5929
- ease: [0.4, 0, 0.2, 1]
5930
- }
6060
+ strokeLinecap: "round"
5931
6061
  }
5932
- ) : /* @__PURE__ */ jsx(
5933
- ActiveCircleElem,
6062
+ )
6063
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6064
+ shouldShowIndeterminateTrack && /* @__PURE__ */ jsx(
6065
+ "circle",
6066
+ {
6067
+ ref: indeterminateTrackRef,
6068
+ cx: center,
6069
+ cy: center,
6070
+ r: radius,
6071
+ fill: "none",
6072
+ stroke: bgTrackColor,
6073
+ strokeWidth: trackHeight,
6074
+ strokeLinecap: "round"
6075
+ }
6076
+ ),
6077
+ /* @__PURE__ */ jsx(
6078
+ "circle",
5934
6079
  {
6080
+ ref: indeterminateActiveRef,
5935
6081
  cx: center,
5936
6082
  cy: center,
5937
6083
  r: radius,
5938
6084
  fill: "none",
5939
6085
  stroke: activeColor,
5940
6086
  strokeWidth: trackHeight,
5941
- strokeLinecap: "round",
5942
- animate: {
5943
- pathLength: [0.1, 0.75, 0.1],
5944
- pathOffset: [0, 0.65, 1]
5945
- },
5946
- transition: {
5947
- duration: 2 / Math.max(0.1, crawlerSpeed),
5948
- repeat: Number.POSITIVE_INFINITY,
5949
- ease: [0.4, 0, 0.2, 1]
5950
- }
6087
+ strokeLinecap: "round"
5951
6088
  }
5952
6089
  )
5953
- ]
6090
+ ] })
5954
6091
  }
5955
6092
  )
5956
6093
  ] })
@@ -6156,7 +6293,7 @@ var WavyLinearTrack = React62.memo(function WavyLinearTrack2({
6156
6293
  currentAmp
6157
6294
  );
6158
6295
  } else if (fraction === 0) {
6159
- activePathD = `M ${capWidth} 0 L ${capWidth + 0.01} 0`;
6296
+ activePathD = "";
6160
6297
  }
6161
6298
  const trackStart = adjHead + totalGap;
6162
6299
  if (trackStart < width - capWidth) {
@@ -6188,20 +6325,20 @@ var WavyLinearTrack = React62.memo(function WavyLinearTrack2({
6188
6325
  activeLines.push({ tail: l1T, head: l1H });
6189
6326
  activeLines.push({ tail: l2T, head: l2H });
6190
6327
  }
6191
- const segments = activeLines.map((line) => {
6192
- const barTail = line.tail * width;
6193
- const barHead = line.head * width;
6328
+ const activeSegments = activeLines.map((line) => {
6329
+ const rawTail = line.tail * width;
6330
+ const rawHead = line.head * width;
6194
6331
  const adjTail = Math.max(
6195
6332
  capWidth,
6196
- Math.min(width - capWidth, barTail)
6333
+ Math.min(width - capWidth, rawTail)
6197
6334
  );
6198
6335
  const adjHead = Math.max(
6199
6336
  capWidth,
6200
- Math.min(width - capWidth, barHead)
6337
+ Math.min(width - capWidth, rawHead)
6201
6338
  );
6202
6339
  return { adjTail, adjHead };
6203
6340
  }).filter((seg) => seg.adjHead - seg.adjTail > 0.1);
6204
- activePathD = segments.map(
6341
+ activePathD = activeSegments.map(
6205
6342
  (seg) => getSinePath(
6206
6343
  seg.adjTail,
6207
6344
  seg.adjHead,
@@ -6210,13 +6347,24 @@ var WavyLinearTrack = React62.memo(function WavyLinearTrack2({
6210
6347
  currentAmp
6211
6348
  )
6212
6349
  ).join(" ");
6350
+ const validActiveLines = activeLines.filter(
6351
+ (line) => line.head > line.tail && line.head * width > 0 && line.tail * width < width
6352
+ ).sort((a, b) => a.tail - b.tail);
6213
6353
  let currentTrackX = capWidth;
6214
- for (const seg of segments) {
6215
- const trackEnd = seg.adjTail - totalGap;
6354
+ for (const line of validActiveLines) {
6355
+ const blockStart = line.tail * width - totalGap;
6356
+ const blockEnd = line.head * width + totalGap;
6357
+ const trackEnd = Math.min(width - capWidth, blockStart);
6216
6358
  if (trackEnd > currentTrackX) {
6217
- trackD += `${getSinePath(currentTrackX, trackEnd, phase, activeWavelength, trackAmp)} `;
6359
+ trackD += `${getSinePath(
6360
+ currentTrackX,
6361
+ trackEnd,
6362
+ phase,
6363
+ activeWavelength,
6364
+ trackAmp
6365
+ )} `;
6218
6366
  }
6219
- currentTrackX = Math.max(currentTrackX, seg.adjHead + totalGap);
6367
+ currentTrackX = Math.max(currentTrackX, blockEnd);
6220
6368
  }
6221
6369
  if (currentTrackX < width - capWidth) {
6222
6370
  trackD += getSinePath(
@@ -6229,9 +6377,9 @@ var WavyLinearTrack = React62.memo(function WavyLinearTrack2({
6229
6377
  }
6230
6378
  }
6231
6379
  if (activePathRef.current)
6232
- activePathRef.current.setAttribute("d", activePathD);
6380
+ activePathRef.current.setAttribute("d", activePathD || "");
6233
6381
  if (trackPathRef.current)
6234
- trackPathRef.current.setAttribute("d", trackD.trim());
6382
+ trackPathRef.current.setAttribute("d", trackD.trim() || "");
6235
6383
  });
6236
6384
  return /* @__PURE__ */ jsx(
6237
6385
  "div",