@wandelbots/wandelbots-js-react-components 2.44.0-pr.feature-seperate-timer.383.16690f0 → 2.44.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.
Files changed (59) hide show
  1. package/dist/components/CycleTimer/DefaultVariant.d.ts.map +1 -1
  2. package/dist/components/CycleTimer/SmallVariant.d.ts.map +1 -1
  3. package/dist/components/CycleTimer/index.d.ts +5 -4
  4. package/dist/components/CycleTimer/index.d.ts.map +1 -1
  5. package/dist/components/CycleTimer/types.d.ts +3 -2
  6. package/dist/components/CycleTimer/types.d.ts.map +1 -1
  7. package/dist/components/CycleTimer/useTimerLogic.d.ts +2 -1
  8. package/dist/components/CycleTimer/useTimerLogic.d.ts.map +1 -1
  9. package/dist/components/ProgramControl.d.ts +1 -7
  10. package/dist/components/ProgramControl.d.ts.map +1 -1
  11. package/dist/components/ProgramStateIndicator.d.ts.map +1 -1
  12. package/dist/components/jogging/PoseCartesianValues.d.ts +5 -3
  13. package/dist/components/jogging/PoseCartesianValues.d.ts.map +1 -1
  14. package/dist/components/jogging/PoseJointValues.d.ts +5 -3
  15. package/dist/components/jogging/PoseJointValues.d.ts.map +1 -1
  16. package/dist/index.cjs +48 -48
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +5947 -6347
  21. package/dist/index.js.map +1 -1
  22. package/package.json +5 -5
  23. package/src/components/CycleTimer/DefaultVariant.tsx +2 -0
  24. package/src/components/CycleTimer/SmallVariant.tsx +5 -2
  25. package/src/components/CycleTimer/index.tsx +5 -4
  26. package/src/components/CycleTimer/types.ts +3 -1
  27. package/src/components/CycleTimer/useTimerLogic.ts +96 -40
  28. package/src/components/CycleTimer/utils.ts +3 -3
  29. package/src/components/ProgramControl.tsx +3 -31
  30. package/src/components/ProgramStateIndicator.tsx +1 -31
  31. package/src/components/jogging/PoseCartesianValues.tsx +82 -16
  32. package/src/components/jogging/PoseJointValues.tsx +82 -16
  33. package/src/i18n/locales/de/translations.json +0 -7
  34. package/src/i18n/locales/en/translations.json +0 -7
  35. package/src/index.ts +0 -1
  36. package/dist/components/Timer/Timer.d.ts +0 -3
  37. package/dist/components/Timer/Timer.d.ts.map +0 -1
  38. package/dist/components/Timer/TimerDefaultVariant.d.ts +0 -10
  39. package/dist/components/Timer/TimerDefaultVariant.d.ts.map +0 -1
  40. package/dist/components/Timer/TimerSmallVariant.d.ts +0 -11
  41. package/dist/components/Timer/TimerSmallVariant.d.ts.map +0 -1
  42. package/dist/components/Timer/index.d.ts +0 -19
  43. package/dist/components/Timer/index.d.ts.map +0 -1
  44. package/dist/components/Timer/types.d.ts +0 -36
  45. package/dist/components/Timer/types.d.ts.map +0 -1
  46. package/dist/components/Timer/useTimerAnimations.d.ts +0 -11
  47. package/dist/components/Timer/useTimerAnimations.d.ts.map +0 -1
  48. package/dist/components/Timer/useTimerLogic.d.ts +0 -20
  49. package/dist/components/Timer/useTimerLogic.d.ts.map +0 -1
  50. package/dist/components/Timer/utils.d.ts +0 -9
  51. package/dist/components/Timer/utils.d.ts.map +0 -1
  52. package/src/components/Timer/Timer.ts +0 -2
  53. package/src/components/Timer/TimerDefaultVariant.tsx +0 -140
  54. package/src/components/Timer/TimerSmallVariant.tsx +0 -140
  55. package/src/components/Timer/index.tsx +0 -101
  56. package/src/components/Timer/types.ts +0 -38
  57. package/src/components/Timer/useTimerAnimations.ts +0 -94
  58. package/src/components/Timer/useTimerLogic.ts +0 -214
  59. package/src/components/Timer/utils.ts +0 -15
@@ -1,40 +1,101 @@
1
- import { Button, Stack } from "@mui/material"
2
- import type { Joints } from "@wandelbots/nova-api/v1"
1
+ import { Button, Stack, Typography } from "@mui/material"
2
+ import type {
3
+ ConnectedMotionGroup,
4
+ MotionGroupStateResponse,
5
+ MotionStreamConnection,
6
+ } from "@wandelbots/nova-js/v1"
3
7
  import { observer } from "mobx-react-lite"
4
- import { useState } from "react"
5
- import { externalizeComponent } from "../../externalizeComponent"
8
+ import { useRef, useState } from "react"
6
9
  import { CopyableText } from "../CopyableText"
10
+ import { useAnimationFrame } from "../utils/hooks"
11
+
12
+ /** Minimal interface for what PoseJointValues needs from motion stream */
13
+ type MotionStateProvider = {
14
+ rapidlyChangingMotionState: MotionGroupStateResponse
15
+ }
16
+
17
+ /** Creates a motion state provider from either a MotionStreamConnection or ConnectedMotionGroup */
18
+ function createMotionStateProvider(
19
+ motionStream?: MotionStreamConnection,
20
+ connectedMotionGroup?: ConnectedMotionGroup,
21
+ ): MotionStateProvider | undefined {
22
+ if (motionStream) {
23
+ return motionStream
24
+ }
25
+ if (connectedMotionGroup) {
26
+ return {
27
+ rapidlyChangingMotionState:
28
+ connectedMotionGroup.rapidlyChangingMotionState,
29
+ }
30
+ }
31
+ return undefined
32
+ }
7
33
 
8
34
  export type PoseJointValuesProps = {
9
- joints: Joints
35
+ /** Either a MotionStreamConnection or ConnectedMotionGroup */
36
+ motionStream?: MotionStreamConnection
37
+ connectedMotionGroup?: ConnectedMotionGroup
10
38
  showCopyButton?: boolean
11
39
  }
12
40
 
13
- export const PoseJointValues = externalizeComponent(
14
- observer(({ joints, showCopyButton = false }: PoseJointValuesProps) => {
15
- const [copyMessage, setCopyMessage] = useState<string | null>(null)
16
- const poseString = `[${joints.joints.map((j: number) => parseFloat(j.toFixed(4))).join(", ")}]`
41
+ export const PoseJointValues = observer(
42
+ ({
43
+ motionStream,
44
+ connectedMotionGroup,
45
+ showCopyButton = false,
46
+ }: PoseJointValuesProps) => {
47
+ const poseHolderRef = useRef<HTMLDivElement>(null)
48
+ const [copyMessage, setCopyMessage] = useState("")
49
+
50
+ const activeMotionStream = createMotionStateProvider(
51
+ motionStream,
52
+ connectedMotionGroup,
53
+ )
54
+
55
+ if (!activeMotionStream) {
56
+ throw new Error(
57
+ "PoseJointValues requires either motionStream or connectedMotionGroup prop",
58
+ )
59
+ }
60
+
61
+ function getCurrentPoseString() {
62
+ if (!activeMotionStream) return ""
63
+ const { joints } =
64
+ activeMotionStream.rapidlyChangingMotionState.state.joint_position
65
+ return `[${joints.map((j: number) => parseFloat(j.toFixed(4))).join(", ")}]`
66
+ }
17
67
 
18
68
  const handleCopy = async () => {
19
69
  try {
20
- await navigator.clipboard.writeText(poseString)
70
+ await navigator.clipboard.writeText(getCurrentPoseString())
21
71
  setCopyMessage("Copied!")
22
- setTimeout(() => setCopyMessage(null), 2000)
72
+ setTimeout(() => setCopyMessage(""), 2000)
23
73
  } catch {
24
74
  setCopyMessage("Copy failed")
25
- setTimeout(() => setCopyMessage(null), 2000)
75
+ setTimeout(() => setCopyMessage(""), 2000)
26
76
  }
27
77
  }
28
78
 
79
+ useAnimationFrame(() => {
80
+ if (!poseHolderRef.current) {
81
+ return
82
+ }
83
+
84
+ const newPoseContent = getCurrentPoseString()
85
+ if (poseHolderRef.current.textContent === newPoseContent) {
86
+ return
87
+ }
88
+ poseHolderRef.current.textContent = newPoseContent
89
+ })
90
+
29
91
  return (
30
92
  <Stack
31
93
  direction="row"
32
94
  alignItems="center"
33
95
  spacing={1}
34
96
  sx={{ flexGrow: 1, minWidth: 0, overflow: "hidden" }}
35
- data-testid="pose-joint-values"
36
97
  >
37
- <CopyableText value={poseString} />
98
+ <CopyableText value={getCurrentPoseString()} ref={poseHolderRef} />
38
99
  {showCopyButton && (
39
100
  <Button
40
101
  variant="contained"
@@ -43,10 +104,15 @@ export const PoseJointValues = externalizeComponent(
43
104
  onClick={handleCopy}
44
105
  sx={{ flexShrink: 0 }}
45
106
  >
46
- { copyMessage ? copyMessage : "Copy"}
107
+ Copy
47
108
  </Button>
48
109
  )}
110
+ {copyMessage && (
111
+ <Typography variant="caption" color="success.main">
112
+ {copyMessage}
113
+ </Typography>
114
+ )}
49
115
  </Stack>
50
116
  )
51
- }),
117
+ },
52
118
  )
@@ -52,19 +52,12 @@
52
52
  "CycleTimer.CycleTime.lb": "Zykluszeit",
53
53
  "CycleTimer.Measuring.lb": "wird gemessen...",
54
54
  "CycleTimer.Determined.lb": "bestimmt",
55
- "Timer.error": "Fehler",
56
55
  "ProgramControl.Start.bt": "Start",
57
56
  "ProgramControl.Resume.bt": "Weiter",
58
57
  "ProgramControl.Retry.bt": "Wiederholen",
59
58
  "ProgramControl.Pause.bt": "Pause",
60
59
  "ProgramControl.Stop.bt": "Stopp",
61
- "ProgramStateIndicator.Preparing.lb": "Vorbereitung",
62
- "ProgramStateIndicator.Starting.lb": "Startet",
63
60
  "ProgramStateIndicator.Running.lb": "In Betrieb",
64
- "ProgramStateIndicator.Pausing.lb": "Pausiert",
65
- "ProgramStateIndicator.Stopping.lb": "Stoppt",
66
- "ProgramStateIndicator.Completed.lb": "Abgeschlossen",
67
- "ProgramStateIndicator.Failed.lb": "Fehlgeschlagen",
68
61
  "ProgramStateIndicator.Error.lb": "Fehler",
69
62
  "ProgramStateIndicator.EStop.lb": "Not-Aus",
70
63
  "ProgramStateIndicator.Idle.lb": "Leerlauf",
@@ -53,19 +53,12 @@
53
53
  "CycleTimer.CycleTime.lb": "Cycle Time",
54
54
  "CycleTimer.Measuring.lb": "measuring...",
55
55
  "CycleTimer.Determined.lb": "determined",
56
- "Timer.error": "Error",
57
56
  "ProgramControl.Start.bt": "Start",
58
57
  "ProgramControl.Resume.bt": "Resume",
59
58
  "ProgramControl.Retry.bt": "Retry",
60
59
  "ProgramControl.Pause.bt": "Pause",
61
60
  "ProgramControl.Stop.bt": "Stop",
62
- "ProgramStateIndicator.Preparing.lb": "Preparing",
63
- "ProgramStateIndicator.Starting.lb": "Starting",
64
61
  "ProgramStateIndicator.Running.lb": "Running",
65
- "ProgramStateIndicator.Pausing.lb": "Pausing",
66
- "ProgramStateIndicator.Stopping.lb": "Stopping",
67
- "ProgramStateIndicator.Completed.lb": "Completed",
68
- "ProgramStateIndicator.Failed.lb": "Failed",
69
62
  "ProgramStateIndicator.Error.lb": "Error",
70
63
  "ProgramStateIndicator.EStop.lb": "E-Stop",
71
64
  "ProgramStateIndicator.Idle.lb": "Idle",
package/src/index.ts CHANGED
@@ -4,7 +4,6 @@ export * from "./components/3d-viewport/SafetyZonesRenderer"
4
4
  export * from "./components/3d-viewport/TrajectoryRenderer"
5
5
  export * from "./components/AppHeader"
6
6
  export * from "./components/CycleTimer"
7
- export * from "./components/Timer"
8
7
  export * from "./components/DataGrid"
9
8
  export * from "./components/jogging/JoggingCartesianAxisControl"
10
9
  export * from "./components/jogging/JoggingJointRotationControl"
@@ -1,3 +0,0 @@
1
- export { Timer } from "./index";
2
- export type { TimerControls, TimerProps } from "./types";
3
- //# sourceMappingURL=Timer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Timer.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/Timer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
@@ -1,10 +0,0 @@
1
- import type { TimerState, TimerAnimationState } from "./types";
2
- interface TimerDefaultVariantProps {
3
- timerState: TimerState;
4
- animationState: TimerAnimationState;
5
- hasError: boolean;
6
- className?: string;
7
- }
8
- export declare const TimerDefaultVariant: ({ timerState, animationState, hasError, className, }: TimerDefaultVariantProps) => import("react/jsx-runtime").JSX.Element;
9
- export {};
10
- //# sourceMappingURL=TimerDefaultVariant.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TimerDefaultVariant.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/TimerDefaultVariant.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAG9D,UAAU,wBAAwB;IAChC,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,mBAAmB,CAAA;IACnC,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,mBAAmB,GAAI,sDAKjC,wBAAwB,4CAwH1B,CAAA"}
@@ -1,11 +0,0 @@
1
- import type { TimerState, TimerAnimationState } from "./types";
2
- interface TimerSmallVariantProps {
3
- timerState: TimerState;
4
- animationState: TimerAnimationState;
5
- hasError: boolean;
6
- compact: boolean;
7
- className?: string;
8
- }
9
- export declare const TimerSmallVariant: ({ timerState, animationState, hasError, compact, className, }: TimerSmallVariantProps) => import("react/jsx-runtime").JSX.Element;
10
- export {};
11
- //# sourceMappingURL=TimerSmallVariant.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TimerSmallVariant.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/TimerSmallVariant.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAG9D,UAAU,sBAAsB;IAC9B,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,mBAAmB,CAAA;IACnC,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,iBAAiB,GAAI,+DAM/B,sBAAsB,4CAuHxB,CAAA"}
@@ -1,19 +0,0 @@
1
- import type { TimerProps } from "./types";
2
- /**
3
- * A simple count-up timer component with visual progress indication
4
- *
5
- * Features:
6
- * - Count-up timer that tracks elapsed time
7
- * - Visual progress gauge that cycles every minute
8
- * - Two display variants: large circular gauge (default) or small icon with text
9
- * - Full timer control: start, pause, resume, reset functionality
10
- * - Support for starting with elapsed time (resume mid-session)
11
- * - Error state support: pauses timer and shows error styling
12
- * - Smooth progress animations with spring physics
13
- * - Fully localized with i18next
14
- * - Material-UI theming integration
15
- */
16
- export declare const Timer: (({ onTimerReady, autoStart, variant, compact, className, hasError, }: TimerProps) => import("react/jsx-runtime").JSX.Element) & {
17
- displayName: string;
18
- };
19
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAIzC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,KAAK,yEASX,UAAU;;CAoEhB,CAAA"}
@@ -1,36 +0,0 @@
1
- export interface TimerControls {
2
- start: (elapsedSeconds?: number) => void;
3
- pause: () => void;
4
- resume: () => void;
5
- reset: () => void;
6
- isPaused: () => boolean;
7
- }
8
- export interface TimerProps {
9
- /**
10
- * Callback that receives the timer control functions
11
- */
12
- onTimerReady: (controls: TimerControls) => void;
13
- /** Whether the timer should start automatically when initialized */
14
- autoStart?: boolean;
15
- /** Visual variant of the timer */
16
- variant?: "default" | "small";
17
- /** For small variant: whether to show compact display */
18
- compact?: boolean;
19
- /** Additional CSS classes */
20
- className?: string;
21
- /** Whether the timer is in an error state (pauses timer and shows error styling) */
22
- hasError?: boolean;
23
- }
24
- export interface TimerState {
25
- elapsedTime: number;
26
- isRunning: boolean;
27
- isPausedState: boolean;
28
- currentProgress: number;
29
- wasRunningBeforeError: boolean;
30
- }
31
- export interface TimerAnimationState {
32
- showPauseAnimation: boolean;
33
- showErrorAnimation: boolean;
34
- showMainText: boolean;
35
- }
36
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,YAAY,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;IAC/C,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kCAAkC;IAClC,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC7B,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,OAAO,CAAA;IAC3B,kBAAkB,EAAE,OAAO,CAAA;IAC3B,YAAY,EAAE,OAAO,CAAA;CACtB"}
@@ -1,11 +0,0 @@
1
- import type { TimerAnimationState } from "./types";
2
- export declare const useTimerAnimations: () => {
3
- animationState: TimerAnimationState;
4
- triggerPauseAnimation: () => void;
5
- triggerErrorAnimation: () => void;
6
- clearErrorAnimation: () => void;
7
- triggerFadeTransition: () => void;
8
- setInitialAnimationState: () => void;
9
- cleanup: () => void;
10
- };
11
- //# sourceMappingURL=useTimerAnimations.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useTimerAnimations.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/useTimerAnimations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,eAAO,MAAM,kBAAkB;;;;;;;;CA0F9B,CAAA"}
@@ -1,20 +0,0 @@
1
- import type { TimerState } from "./types";
2
- interface UseTimerLogicProps {
3
- autoStart: boolean;
4
- hasError: boolean;
5
- onPauseAnimation: () => void;
6
- onErrorAnimation: () => void;
7
- onClearErrorAnimation: () => void;
8
- }
9
- export declare const useTimerLogic: ({ autoStart, hasError, onPauseAnimation, onErrorAnimation, onClearErrorAnimation, }: UseTimerLogicProps) => {
10
- timerState: TimerState;
11
- controls: {
12
- start: (elapsedSeconds?: number) => void;
13
- pause: () => void;
14
- resume: () => void;
15
- reset: () => void;
16
- isPaused: () => boolean;
17
- };
18
- };
19
- export {};
20
- //# sourceMappingURL=useTimerLogic.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useTimerLogic.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/useTimerLogic.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,UAAU,kBAAkB;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,qBAAqB,EAAE,MAAM,IAAI,CAAA;CAClC;AAED,eAAO,MAAM,aAAa,GAAI,qFAM3B,kBAAkB;;;iCAyBA,MAAM;;;;;;CA0K1B,CAAA"}
@@ -1,9 +0,0 @@
1
- /**
2
- * Formats time in seconds to MM:SS format
3
- */
4
- export declare const formatTime: (seconds: number) => string;
5
- /**
6
- * Calculates progress percentage for timer (minute-based cycles)
7
- */
8
- export declare const calculateTimerProgress: (elapsedTime: number) => number;
9
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/components/Timer/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,MAI5C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,KAAG,MAE5D,CAAA"}
@@ -1,2 +0,0 @@
1
- export { Timer } from "./index"
2
- export type { TimerControls, TimerProps } from "./types"
@@ -1,140 +0,0 @@
1
- import { Box, Fade, Typography } from "@mui/material"
2
- import { Gauge } from "@mui/x-charts"
3
- import { useTheme } from "@mui/material/styles"
4
- import { useTranslation } from "react-i18next"
5
- import type { TimerState, TimerAnimationState } from "./types"
6
- import { formatTime } from "./utils"
7
-
8
- interface TimerDefaultVariantProps {
9
- timerState: TimerState
10
- animationState: TimerAnimationState
11
- hasError: boolean
12
- className?: string
13
- }
14
-
15
- export const TimerDefaultVariant = ({
16
- timerState,
17
- animationState,
18
- hasError,
19
- className,
20
- }: TimerDefaultVariantProps) => {
21
- const { t } = useTranslation()
22
- const theme = useTheme()
23
- const { elapsedTime, currentProgress } = timerState
24
- const { showErrorAnimation, showPauseAnimation, showMainText } = animationState
25
-
26
- return (
27
- <Box
28
- className={className}
29
- sx={{
30
- position: "relative",
31
- width: 264,
32
- height: 264,
33
- display: "flex",
34
- alignItems: "center",
35
- justifyContent: "center",
36
- }}
37
- >
38
- <Gauge
39
- width={264}
40
- height={264}
41
- value={currentProgress}
42
- valueMin={0}
43
- valueMax={100}
44
- innerRadius="85%"
45
- outerRadius="100%"
46
- margin={0}
47
- skipAnimation={true}
48
- text={() => ""}
49
- sx={{
50
- opacity: showPauseAnimation || showErrorAnimation ? 0.6 : 1,
51
- transition: "opacity 0.5s ease-out",
52
- [`& .MuiGauge-valueArc`]: {
53
- fill: hasError
54
- ? theme.palette.error.light
55
- : theme.palette.success.main,
56
- transition: "fill 0.5s ease-out",
57
- },
58
- [`& .MuiGauge-referenceArc`]: {
59
- fill: "#171927",
60
- stroke: "transparent",
61
- strokeWidth: 0,
62
- transition:
63
- "fill 0.5s ease-out, stroke 0.5s ease-out, stroke-width 0.5s ease-out",
64
- },
65
- [`& .MuiGauge-valueText`]: {
66
- display: "none",
67
- },
68
- [`& .MuiGauge-text`]: {
69
- display: "none",
70
- },
71
- }}
72
- />
73
-
74
- {/* Center content overlay */}
75
- <Box
76
- sx={{
77
- position: "absolute",
78
- top: "50%",
79
- left: "50%",
80
- transform: "translate(-50%, -50%)",
81
- width: 225,
82
- height: 225,
83
- borderRadius: "50%",
84
- backgroundColor: "#292B3F",
85
- display: "flex",
86
- flexDirection: "column",
87
- alignItems: "center",
88
- justifyContent: "center",
89
- textAlign: "center",
90
- gap: 1,
91
- transition: "background-color 0.5s ease-out",
92
- }}
93
- >
94
- {/* Main display */}
95
- <Box
96
- sx={{
97
- position: "relative",
98
- height: "48px",
99
- display: "flex",
100
- alignItems: "center",
101
- justifyContent: "center",
102
- marginBottom: 0.5,
103
- }}
104
- >
105
- {/* Error text */}
106
- <Fade in={showMainText && hasError} timeout={200}>
107
- <Typography
108
- variant="h6"
109
- sx={{
110
- position: "absolute",
111
- fontSize: "16px",
112
- fontWeight: 500,
113
- color: theme.palette.error.light,
114
- }}
115
- >
116
- {t("timer.error")}
117
- </Typography>
118
- </Fade>
119
-
120
- {/* Timer display */}
121
- <Fade in={showMainText && !hasError} timeout={300}>
122
- <Typography
123
- variant="h1"
124
- sx={{
125
- position: "absolute",
126
- fontSize: "48px",
127
- fontWeight: 500,
128
- color: theme.palette.text.primary,
129
- lineHeight: 1,
130
- letterSpacing: "-0.5px",
131
- }}
132
- >
133
- {formatTime(elapsedTime)}
134
- </Typography>
135
- </Fade>
136
- </Box>
137
- </Box>
138
- </Box>
139
- )
140
- }
@@ -1,140 +0,0 @@
1
- import { Box, Typography } from "@mui/material"
2
- import { useTheme } from "@mui/material/styles"
3
- import { useTranslation } from "react-i18next"
4
- import type { TimerState, TimerAnimationState } from "./types"
5
- import { formatTime } from "./utils"
6
-
7
- interface TimerSmallVariantProps {
8
- timerState: TimerState
9
- animationState: TimerAnimationState
10
- hasError: boolean
11
- compact: boolean
12
- className?: string
13
- }
14
-
15
- export const TimerSmallVariant = ({
16
- timerState,
17
- animationState,
18
- hasError,
19
- compact,
20
- className,
21
- }: TimerSmallVariantProps) => {
22
- const { t } = useTranslation()
23
- const theme = useTheme()
24
- const { elapsedTime, currentProgress } = timerState
25
- const { showErrorAnimation, showPauseAnimation } = animationState
26
-
27
- // Simple text-only mode for compact variant
28
- if (compact) {
29
- return (
30
- <Box
31
- className={className}
32
- sx={{
33
- display: "flex",
34
- alignItems: "center",
35
- m: 0,
36
- }}
37
- >
38
- <Typography
39
- variant="body2"
40
- sx={{
41
- color: hasError
42
- ? theme.palette.error.light
43
- : theme.palette.text.primary,
44
- fontSize: "14px",
45
- transition: "color 0.5s ease-out",
46
- }}
47
- >
48
- {hasError ? t("timer.error") : formatTime(elapsedTime)}
49
- </Typography>
50
- </Box>
51
- )
52
- }
53
-
54
- return (
55
- <Box
56
- className={className}
57
- sx={{
58
- display: "flex",
59
- alignItems: "center",
60
- m: 0,
61
- gap: 1,
62
- }}
63
- >
64
- {/* Animated progress ring icon */}
65
- <Box
66
- sx={{
67
- width: 20,
68
- height: 20,
69
- display: "flex",
70
- alignItems: "center",
71
- justifyContent: "center",
72
- opacity: showPauseAnimation || showErrorAnimation ? 0.6 : 1,
73
- transition: "opacity 0.5s ease-out",
74
- }}
75
- >
76
- <svg
77
- width="20"
78
- height="20"
79
- viewBox="0 0 20 20"
80
- style={{ transform: "rotate(-90deg)" }}
81
- role="img"
82
- aria-label="Timer progress"
83
- >
84
- <circle
85
- cx="10"
86
- cy="10"
87
- r="8"
88
- fill="none"
89
- stroke={
90
- hasError
91
- ? theme.palette.error.light
92
- : theme.palette.success.main
93
- }
94
- strokeWidth="2"
95
- opacity={0.3}
96
- style={{
97
- transition: "stroke 0.8s ease-in-out, opacity 2s ease-in-out",
98
- }}
99
- />
100
- <circle
101
- cx="10"
102
- cy="10"
103
- r="8"
104
- fill="none"
105
- stroke={
106
- hasError
107
- ? theme.palette.error.light
108
- : theme.palette.success.main
109
- }
110
- strokeWidth="2"
111
- strokeLinecap="round"
112
- strokeDasharray={`${2 * Math.PI * 8}`}
113
- strokeDashoffset={`${2 * Math.PI * 8 * (1 - currentProgress / 100)}`}
114
- style={{
115
- transition:
116
- "stroke-dashoffset 0.1s ease-out, stroke 0.8s ease-in-out, opacity 2s ease-in-out",
117
- }}
118
- />
119
- </svg>
120
- </Box>
121
-
122
- {/* Timer text display */}
123
- <Typography
124
- variant="body2"
125
- sx={{
126
- color: hasError
127
- ? theme.palette.error.light
128
- : theme.palette.text.primary,
129
- fontSize: "14px",
130
- lineHeight: "normal",
131
- letterSpacing: "normal",
132
- transition:
133
- "color 0.8s ease-in-out, font-size 0.3s ease-out, opacity 2s ease-in-out",
134
- }}
135
- >
136
- {hasError ? t("timer.error") : formatTime(elapsedTime)}
137
- </Typography>
138
- </Box>
139
- )
140
- }