premium-react-loaders 2.0.0 → 2.2.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 (96) hide show
  1. package/README.md +262 -6
  2. package/dist/components/button/ButtonSpinner.d.ts +25 -0
  3. package/dist/components/button/ButtonSpinner.d.ts.map +1 -0
  4. package/dist/components/button/index.d.ts +2 -0
  5. package/dist/components/button/index.d.ts.map +1 -0
  6. package/dist/components/index.d.ts +2 -0
  7. package/dist/components/index.d.ts.map +1 -1
  8. package/dist/components/pulse/TypingIndicator.d.ts.map +1 -1
  9. package/dist/components/status/ErrorIndicator.d.ts +32 -0
  10. package/dist/components/status/ErrorIndicator.d.ts.map +1 -0
  11. package/dist/components/status/SuccessCheckmark.d.ts +31 -0
  12. package/dist/components/status/SuccessCheckmark.d.ts.map +1 -0
  13. package/dist/components/status/index.d.ts +3 -0
  14. package/dist/components/status/index.d.ts.map +1 -0
  15. package/dist/context/ThemeContext.d.ts +84 -0
  16. package/dist/context/ThemeContext.d.ts.map +1 -0
  17. package/dist/context/index.d.ts +3 -0
  18. package/dist/context/index.d.ts.map +1 -0
  19. package/dist/hooks/index.d.ts +3 -0
  20. package/dist/hooks/index.d.ts.map +1 -0
  21. package/dist/hooks/useLoader.d.ts +56 -0
  22. package/dist/hooks/useLoader.d.ts.map +1 -0
  23. package/dist/index.cjs +37 -26
  24. package/dist/index.d.ts +5 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +37 -26
  27. package/dist/index10.cjs +20 -31
  28. package/dist/index10.js +20 -31
  29. package/dist/index11.cjs +47 -25
  30. package/dist/index11.js +47 -25
  31. package/dist/index12.cjs +30 -126
  32. package/dist/index12.js +31 -127
  33. package/dist/index13.cjs +30 -53
  34. package/dist/index13.js +30 -53
  35. package/dist/index14.cjs +127 -43
  36. package/dist/index14.js +128 -44
  37. package/dist/index15.cjs +58 -37
  38. package/dist/index15.js +59 -38
  39. package/dist/index16.cjs +24 -36
  40. package/dist/index16.js +24 -36
  41. package/dist/index17.cjs +19 -21
  42. package/dist/index17.js +19 -21
  43. package/dist/index18.cjs +25 -20
  44. package/dist/index18.js +25 -20
  45. package/dist/index19.cjs +22 -32
  46. package/dist/index19.js +22 -32
  47. package/dist/index20.cjs +26 -35
  48. package/dist/index20.js +28 -37
  49. package/dist/index21.cjs +40 -76
  50. package/dist/index21.js +42 -78
  51. package/dist/index22.cjs +53 -102
  52. package/dist/index22.js +54 -103
  53. package/dist/index23.cjs +46 -80
  54. package/dist/index23.js +47 -81
  55. package/dist/index24.cjs +105 -103
  56. package/dist/index24.js +107 -105
  57. package/dist/index25.cjs +108 -27
  58. package/dist/index25.js +111 -30
  59. package/dist/index26.cjs +104 -36
  60. package/dist/index26.js +106 -38
  61. package/dist/index27.cjs +22 -30
  62. package/dist/index27.js +23 -31
  63. package/dist/index28.cjs +30 -29
  64. package/dist/index28.js +31 -30
  65. package/dist/index29.cjs +49 -52
  66. package/dist/index29.js +50 -53
  67. package/dist/index30.cjs +74 -121
  68. package/dist/index30.js +75 -122
  69. package/dist/index31.cjs +82 -0
  70. package/dist/index31.js +82 -0
  71. package/dist/index32.cjs +149 -0
  72. package/dist/index32.js +149 -0
  73. package/dist/index33.cjs +100 -0
  74. package/dist/index33.js +100 -0
  75. package/dist/index34.cjs +117 -0
  76. package/dist/index34.js +117 -0
  77. package/dist/index35.cjs +125 -0
  78. package/dist/index35.js +125 -0
  79. package/dist/index5.cjs +11 -72
  80. package/dist/index5.js +12 -73
  81. package/dist/index6.cjs +86 -65
  82. package/dist/index6.js +87 -66
  83. package/dist/index7.cjs +40 -20
  84. package/dist/index7.js +40 -20
  85. package/dist/index8.cjs +34 -21
  86. package/dist/index8.js +34 -21
  87. package/dist/index9.cjs +21 -55
  88. package/dist/index9.js +22 -56
  89. package/dist/premium-react-loaders.css +178 -6
  90. package/dist/types/button.d.ts +31 -0
  91. package/dist/types/button.d.ts.map +1 -0
  92. package/dist/types/index.d.ts +2 -0
  93. package/dist/types/index.d.ts.map +1 -1
  94. package/dist/types/status.d.ts +34 -0
  95. package/dist/types/status.d.ts.map +1 -0
  96. package/package.json +1 -1
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const hooks = require("./index35.cjs");
6
+ const classNames = require("./index3.cjs");
7
+ const colors = require("./index4.cjs");
8
+ const SuccessCheckmark = react.forwardRef(
9
+ ({
10
+ size = "md",
11
+ color = "#10b981",
12
+ strokeWidth = 3,
13
+ duration = 500,
14
+ showCircle = false,
15
+ circleColor,
16
+ fillCircle = false,
17
+ delay = 0,
18
+ minDuration = 0,
19
+ transition = true,
20
+ className,
21
+ style,
22
+ testId = "success-checkmark",
23
+ visible = true,
24
+ ariaLabel = "Success",
25
+ ...rest
26
+ }, ref) => {
27
+ const { shouldRender, opacity, transitionStyle } = hooks.useLoaderVisibility(
28
+ visible,
29
+ delay,
30
+ minDuration,
31
+ transition
32
+ );
33
+ if (!shouldRender) return null;
34
+ const effectiveCircleColor = circleColor || color;
35
+ const sizeValue = colors.normalizeSize(size);
36
+ return /* @__PURE__ */ jsxRuntime.jsx(
37
+ "div",
38
+ {
39
+ ref,
40
+ "data-testid": testId,
41
+ className: classNames.cn("inline-flex items-center justify-center", className),
42
+ style: {
43
+ ...style,
44
+ opacity,
45
+ transition: transitionStyle
46
+ },
47
+ role: "status",
48
+ "aria-label": ariaLabel,
49
+ ...rest,
50
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
51
+ "svg",
52
+ {
53
+ className: "animate-success-scale",
54
+ style: {
55
+ width: sizeValue,
56
+ height: sizeValue,
57
+ animationDuration: `${duration}ms`
58
+ },
59
+ viewBox: "0 0 52 52",
60
+ children: [
61
+ showCircle && /* @__PURE__ */ jsxRuntime.jsx(
62
+ "circle",
63
+ {
64
+ className: "animate-success-circle",
65
+ cx: "26",
66
+ cy: "26",
67
+ r: "23",
68
+ fill: fillCircle ? effectiveCircleColor : "none",
69
+ stroke: effectiveCircleColor,
70
+ strokeWidth,
71
+ style: {
72
+ animationDuration: `${duration}ms`
73
+ }
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsxRuntime.jsx(
77
+ "path",
78
+ {
79
+ className: "animate-success-check",
80
+ fill: "none",
81
+ stroke: color,
82
+ strokeWidth,
83
+ strokeLinecap: "round",
84
+ strokeLinejoin: "round",
85
+ d: "M14.1 27.2l7.1 7.2 16.7-16.8",
86
+ style: {
87
+ animationDuration: `${duration}ms`,
88
+ animationDelay: showCircle ? `${duration * 0.3}ms` : "0ms"
89
+ }
90
+ }
91
+ )
92
+ ]
93
+ }
94
+ )
95
+ }
96
+ );
97
+ }
98
+ );
99
+ SuccessCheckmark.displayName = "SuccessCheckmark";
100
+ exports.SuccessCheckmark = SuccessCheckmark;
@@ -0,0 +1,100 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { useLoaderVisibility } from "./index35.js";
4
+ import { cn } from "./index3.js";
5
+ import { normalizeSize } from "./index4.js";
6
+ const SuccessCheckmark = forwardRef(
7
+ ({
8
+ size = "md",
9
+ color = "#10b981",
10
+ strokeWidth = 3,
11
+ duration = 500,
12
+ showCircle = false,
13
+ circleColor,
14
+ fillCircle = false,
15
+ delay = 0,
16
+ minDuration = 0,
17
+ transition = true,
18
+ className,
19
+ style,
20
+ testId = "success-checkmark",
21
+ visible = true,
22
+ ariaLabel = "Success",
23
+ ...rest
24
+ }, ref) => {
25
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
26
+ visible,
27
+ delay,
28
+ minDuration,
29
+ transition
30
+ );
31
+ if (!shouldRender) return null;
32
+ const effectiveCircleColor = circleColor || color;
33
+ const sizeValue = normalizeSize(size);
34
+ return /* @__PURE__ */ jsx(
35
+ "div",
36
+ {
37
+ ref,
38
+ "data-testid": testId,
39
+ className: cn("inline-flex items-center justify-center", className),
40
+ style: {
41
+ ...style,
42
+ opacity,
43
+ transition: transitionStyle
44
+ },
45
+ role: "status",
46
+ "aria-label": ariaLabel,
47
+ ...rest,
48
+ children: /* @__PURE__ */ jsxs(
49
+ "svg",
50
+ {
51
+ className: "animate-success-scale",
52
+ style: {
53
+ width: sizeValue,
54
+ height: sizeValue,
55
+ animationDuration: `${duration}ms`
56
+ },
57
+ viewBox: "0 0 52 52",
58
+ children: [
59
+ showCircle && /* @__PURE__ */ jsx(
60
+ "circle",
61
+ {
62
+ className: "animate-success-circle",
63
+ cx: "26",
64
+ cy: "26",
65
+ r: "23",
66
+ fill: fillCircle ? effectiveCircleColor : "none",
67
+ stroke: effectiveCircleColor,
68
+ strokeWidth,
69
+ style: {
70
+ animationDuration: `${duration}ms`
71
+ }
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsx(
75
+ "path",
76
+ {
77
+ className: "animate-success-check",
78
+ fill: "none",
79
+ stroke: color,
80
+ strokeWidth,
81
+ strokeLinecap: "round",
82
+ strokeLinejoin: "round",
83
+ d: "M14.1 27.2l7.1 7.2 16.7-16.8",
84
+ style: {
85
+ animationDuration: `${duration}ms`,
86
+ animationDelay: showCircle ? `${duration * 0.3}ms` : "0ms"
87
+ }
88
+ }
89
+ )
90
+ ]
91
+ }
92
+ )
93
+ }
94
+ );
95
+ }
96
+ );
97
+ SuccessCheckmark.displayName = "SuccessCheckmark";
98
+ export {
99
+ SuccessCheckmark
100
+ };
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const hooks = require("./index35.cjs");
6
+ const classNames = require("./index3.cjs");
7
+ const colors = require("./index4.cjs");
8
+ const ErrorIndicator = react.forwardRef(
9
+ ({
10
+ size = "md",
11
+ color = "#ef4444",
12
+ strokeWidth = 3,
13
+ duration = 500,
14
+ showCircle = false,
15
+ circleColor,
16
+ fillCircle = false,
17
+ shake = true,
18
+ delay = 0,
19
+ minDuration = 0,
20
+ transition = true,
21
+ className,
22
+ style,
23
+ testId = "error-indicator",
24
+ visible = true,
25
+ ariaLabel = "Error",
26
+ ...rest
27
+ }, ref) => {
28
+ const { shouldRender, opacity, transitionStyle } = hooks.useLoaderVisibility(
29
+ visible,
30
+ delay,
31
+ minDuration,
32
+ transition
33
+ );
34
+ if (!shouldRender) return null;
35
+ const effectiveCircleColor = circleColor || color;
36
+ const sizeValue = colors.normalizeSize(size);
37
+ return /* @__PURE__ */ jsxRuntime.jsx(
38
+ "div",
39
+ {
40
+ ref,
41
+ "data-testid": testId,
42
+ className: classNames.cn("inline-flex items-center justify-center", className),
43
+ style: {
44
+ ...style,
45
+ opacity,
46
+ transition: transitionStyle
47
+ },
48
+ role: "status",
49
+ "aria-label": ariaLabel,
50
+ ...rest,
51
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
52
+ "svg",
53
+ {
54
+ className: shake ? "animate-error-shake" : "animate-error-scale",
55
+ style: {
56
+ width: sizeValue,
57
+ height: sizeValue,
58
+ animationDuration: `${duration}ms`
59
+ },
60
+ viewBox: "0 0 52 52",
61
+ children: [
62
+ showCircle && /* @__PURE__ */ jsxRuntime.jsx(
63
+ "circle",
64
+ {
65
+ className: "animate-error-circle",
66
+ cx: "26",
67
+ cy: "26",
68
+ r: "23",
69
+ fill: fillCircle ? effectiveCircleColor : "none",
70
+ stroke: effectiveCircleColor,
71
+ strokeWidth,
72
+ style: {
73
+ animationDuration: `${duration}ms`
74
+ }
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsxRuntime.jsxs(
78
+ "g",
79
+ {
80
+ className: "animate-error-x",
81
+ style: {
82
+ animationDuration: `${duration}ms`,
83
+ animationDelay: showCircle ? `${duration * 0.3}ms` : "0ms"
84
+ },
85
+ children: [
86
+ /* @__PURE__ */ jsxRuntime.jsx(
87
+ "path",
88
+ {
89
+ fill: "none",
90
+ stroke: color,
91
+ strokeWidth,
92
+ strokeLinecap: "round",
93
+ d: "M16 16 36 36"
94
+ }
95
+ ),
96
+ /* @__PURE__ */ jsxRuntime.jsx(
97
+ "path",
98
+ {
99
+ fill: "none",
100
+ stroke: color,
101
+ strokeWidth,
102
+ strokeLinecap: "round",
103
+ d: "M36 16 16 36"
104
+ }
105
+ )
106
+ ]
107
+ }
108
+ )
109
+ ]
110
+ }
111
+ )
112
+ }
113
+ );
114
+ }
115
+ );
116
+ ErrorIndicator.displayName = "ErrorIndicator";
117
+ exports.ErrorIndicator = ErrorIndicator;
@@ -0,0 +1,117 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { useLoaderVisibility } from "./index35.js";
4
+ import { cn } from "./index3.js";
5
+ import { normalizeSize } from "./index4.js";
6
+ const ErrorIndicator = forwardRef(
7
+ ({
8
+ size = "md",
9
+ color = "#ef4444",
10
+ strokeWidth = 3,
11
+ duration = 500,
12
+ showCircle = false,
13
+ circleColor,
14
+ fillCircle = false,
15
+ shake = true,
16
+ delay = 0,
17
+ minDuration = 0,
18
+ transition = true,
19
+ className,
20
+ style,
21
+ testId = "error-indicator",
22
+ visible = true,
23
+ ariaLabel = "Error",
24
+ ...rest
25
+ }, ref) => {
26
+ const { shouldRender, opacity, transitionStyle } = useLoaderVisibility(
27
+ visible,
28
+ delay,
29
+ minDuration,
30
+ transition
31
+ );
32
+ if (!shouldRender) return null;
33
+ const effectiveCircleColor = circleColor || color;
34
+ const sizeValue = normalizeSize(size);
35
+ return /* @__PURE__ */ jsx(
36
+ "div",
37
+ {
38
+ ref,
39
+ "data-testid": testId,
40
+ className: cn("inline-flex items-center justify-center", className),
41
+ style: {
42
+ ...style,
43
+ opacity,
44
+ transition: transitionStyle
45
+ },
46
+ role: "status",
47
+ "aria-label": ariaLabel,
48
+ ...rest,
49
+ children: /* @__PURE__ */ jsxs(
50
+ "svg",
51
+ {
52
+ className: shake ? "animate-error-shake" : "animate-error-scale",
53
+ style: {
54
+ width: sizeValue,
55
+ height: sizeValue,
56
+ animationDuration: `${duration}ms`
57
+ },
58
+ viewBox: "0 0 52 52",
59
+ children: [
60
+ showCircle && /* @__PURE__ */ jsx(
61
+ "circle",
62
+ {
63
+ className: "animate-error-circle",
64
+ cx: "26",
65
+ cy: "26",
66
+ r: "23",
67
+ fill: fillCircle ? effectiveCircleColor : "none",
68
+ stroke: effectiveCircleColor,
69
+ strokeWidth,
70
+ style: {
71
+ animationDuration: `${duration}ms`
72
+ }
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsxs(
76
+ "g",
77
+ {
78
+ className: "animate-error-x",
79
+ style: {
80
+ animationDuration: `${duration}ms`,
81
+ animationDelay: showCircle ? `${duration * 0.3}ms` : "0ms"
82
+ },
83
+ children: [
84
+ /* @__PURE__ */ jsx(
85
+ "path",
86
+ {
87
+ fill: "none",
88
+ stroke: color,
89
+ strokeWidth,
90
+ strokeLinecap: "round",
91
+ d: "M16 16 36 36"
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ "path",
96
+ {
97
+ fill: "none",
98
+ stroke: color,
99
+ strokeWidth,
100
+ strokeLinecap: "round",
101
+ d: "M36 16 16 36"
102
+ }
103
+ )
104
+ ]
105
+ }
106
+ )
107
+ ]
108
+ }
109
+ )
110
+ }
111
+ );
112
+ }
113
+ );
114
+ ErrorIndicator.displayName = "ErrorIndicator";
115
+ export {
116
+ ErrorIndicator
117
+ };
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const react = require("react");
4
+ function useReducedMotion() {
5
+ const [prefersReducedMotion, setPrefersReducedMotion] = react.useState(false);
6
+ react.useEffect(() => {
7
+ if (typeof window === "undefined" || !window.matchMedia) {
8
+ return;
9
+ }
10
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
11
+ setPrefersReducedMotion(mediaQuery.matches);
12
+ const handleChange = (event) => {
13
+ setPrefersReducedMotion(event.matches);
14
+ };
15
+ if (mediaQuery.addEventListener) {
16
+ mediaQuery.addEventListener("change", handleChange);
17
+ return () => mediaQuery.removeEventListener("change", handleChange);
18
+ } else {
19
+ mediaQuery.addListener(handleChange);
20
+ return () => mediaQuery.removeListener(handleChange);
21
+ }
22
+ }, []);
23
+ return prefersReducedMotion;
24
+ }
25
+ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion) {
26
+ if (respectMotionPreference && prefersReducedMotion) {
27
+ return "0.01ms";
28
+ }
29
+ if (typeof speed === "number") {
30
+ const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(1e4, speed)) : 1e3;
31
+ return `${validSpeed}ms`;
32
+ }
33
+ const speedMap = {
34
+ slow: "2s",
35
+ normal: "1s",
36
+ fast: "0.5s"
37
+ };
38
+ return speedMap[speed] || speedMap.normal;
39
+ }
40
+ function useLoaderVisibility(visible = true, delay = 0, minDuration = 0, transition) {
41
+ const transitionDuration = transition === true ? 150 : typeof transition === "number" ? transition : 0;
42
+ const hasTransition = transitionDuration > 0;
43
+ const [shouldRender, setShouldRender] = react.useState(visible && delay === 0);
44
+ const [isTransitioning, setIsTransitioning] = react.useState(visible && delay === 0 && hasTransition);
45
+ const showTimeRef = react.useRef(visible && delay === 0 ? Date.now() : null);
46
+ const delayTimerRef = react.useRef(null);
47
+ const minDurationTimerRef = react.useRef(null);
48
+ const transitionTimerRef = react.useRef(null);
49
+ react.useEffect(() => {
50
+ if (delayTimerRef.current) {
51
+ clearTimeout(delayTimerRef.current);
52
+ delayTimerRef.current = null;
53
+ }
54
+ if (minDurationTimerRef.current) {
55
+ clearTimeout(minDurationTimerRef.current);
56
+ minDurationTimerRef.current = null;
57
+ }
58
+ if (transitionTimerRef.current) {
59
+ clearTimeout(transitionTimerRef.current);
60
+ transitionTimerRef.current = null;
61
+ }
62
+ if (visible) {
63
+ if (delay > 0) {
64
+ delayTimerRef.current = setTimeout(() => {
65
+ setShouldRender(true);
66
+ showTimeRef.current = Date.now();
67
+ if (hasTransition) {
68
+ setIsTransitioning(true);
69
+ }
70
+ }, delay);
71
+ } else {
72
+ setShouldRender(true);
73
+ showTimeRef.current = Date.now();
74
+ if (hasTransition) {
75
+ setIsTransitioning(true);
76
+ }
77
+ }
78
+ } else {
79
+ const hideLoader = () => {
80
+ if (hasTransition) {
81
+ setIsTransitioning(false);
82
+ transitionTimerRef.current = setTimeout(() => {
83
+ setShouldRender(false);
84
+ showTimeRef.current = null;
85
+ }, transitionDuration);
86
+ } else {
87
+ setShouldRender(false);
88
+ showTimeRef.current = null;
89
+ }
90
+ };
91
+ if (showTimeRef.current !== null && minDuration > 0) {
92
+ const elapsedTime = Date.now() - showTimeRef.current;
93
+ const remainingTime = minDuration - elapsedTime;
94
+ if (remainingTime > 0) {
95
+ minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);
96
+ } else {
97
+ hideLoader();
98
+ }
99
+ } else {
100
+ hideLoader();
101
+ }
102
+ }
103
+ return () => {
104
+ if (delayTimerRef.current) {
105
+ clearTimeout(delayTimerRef.current);
106
+ }
107
+ if (minDurationTimerRef.current) {
108
+ clearTimeout(minDurationTimerRef.current);
109
+ }
110
+ if (transitionTimerRef.current) {
111
+ clearTimeout(transitionTimerRef.current);
112
+ }
113
+ };
114
+ }, [visible, delay, minDuration, hasTransition, transitionDuration]);
115
+ const opacity = hasTransition ? isTransitioning ? 1 : 0 : 1;
116
+ const transitionStyle = hasTransition ? `opacity ${transitionDuration}ms ease-in-out` : "none";
117
+ return {
118
+ shouldRender,
119
+ opacity,
120
+ transitionStyle
121
+ };
122
+ }
123
+ exports.getEffectiveDuration = getEffectiveDuration;
124
+ exports.useLoaderVisibility = useLoaderVisibility;
125
+ exports.useReducedMotion = useReducedMotion;
@@ -0,0 +1,125 @@
1
+ import { useState, useRef, useEffect } from "react";
2
+ function useReducedMotion() {
3
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
4
+ useEffect(() => {
5
+ if (typeof window === "undefined" || !window.matchMedia) {
6
+ return;
7
+ }
8
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
9
+ setPrefersReducedMotion(mediaQuery.matches);
10
+ const handleChange = (event) => {
11
+ setPrefersReducedMotion(event.matches);
12
+ };
13
+ if (mediaQuery.addEventListener) {
14
+ mediaQuery.addEventListener("change", handleChange);
15
+ return () => mediaQuery.removeEventListener("change", handleChange);
16
+ } else {
17
+ mediaQuery.addListener(handleChange);
18
+ return () => mediaQuery.removeListener(handleChange);
19
+ }
20
+ }, []);
21
+ return prefersReducedMotion;
22
+ }
23
+ function getEffectiveDuration(speed, respectMotionPreference, prefersReducedMotion) {
24
+ if (respectMotionPreference && prefersReducedMotion) {
25
+ return "0.01ms";
26
+ }
27
+ if (typeof speed === "number") {
28
+ const validSpeed = !isNaN(speed) && speed > 0 ? Math.max(50, Math.min(1e4, speed)) : 1e3;
29
+ return `${validSpeed}ms`;
30
+ }
31
+ const speedMap = {
32
+ slow: "2s",
33
+ normal: "1s",
34
+ fast: "0.5s"
35
+ };
36
+ return speedMap[speed] || speedMap.normal;
37
+ }
38
+ function useLoaderVisibility(visible = true, delay = 0, minDuration = 0, transition) {
39
+ const transitionDuration = transition === true ? 150 : typeof transition === "number" ? transition : 0;
40
+ const hasTransition = transitionDuration > 0;
41
+ const [shouldRender, setShouldRender] = useState(visible && delay === 0);
42
+ const [isTransitioning, setIsTransitioning] = useState(visible && delay === 0 && hasTransition);
43
+ const showTimeRef = useRef(visible && delay === 0 ? Date.now() : null);
44
+ const delayTimerRef = useRef(null);
45
+ const minDurationTimerRef = useRef(null);
46
+ const transitionTimerRef = useRef(null);
47
+ useEffect(() => {
48
+ if (delayTimerRef.current) {
49
+ clearTimeout(delayTimerRef.current);
50
+ delayTimerRef.current = null;
51
+ }
52
+ if (minDurationTimerRef.current) {
53
+ clearTimeout(minDurationTimerRef.current);
54
+ minDurationTimerRef.current = null;
55
+ }
56
+ if (transitionTimerRef.current) {
57
+ clearTimeout(transitionTimerRef.current);
58
+ transitionTimerRef.current = null;
59
+ }
60
+ if (visible) {
61
+ if (delay > 0) {
62
+ delayTimerRef.current = setTimeout(() => {
63
+ setShouldRender(true);
64
+ showTimeRef.current = Date.now();
65
+ if (hasTransition) {
66
+ setIsTransitioning(true);
67
+ }
68
+ }, delay);
69
+ } else {
70
+ setShouldRender(true);
71
+ showTimeRef.current = Date.now();
72
+ if (hasTransition) {
73
+ setIsTransitioning(true);
74
+ }
75
+ }
76
+ } else {
77
+ const hideLoader = () => {
78
+ if (hasTransition) {
79
+ setIsTransitioning(false);
80
+ transitionTimerRef.current = setTimeout(() => {
81
+ setShouldRender(false);
82
+ showTimeRef.current = null;
83
+ }, transitionDuration);
84
+ } else {
85
+ setShouldRender(false);
86
+ showTimeRef.current = null;
87
+ }
88
+ };
89
+ if (showTimeRef.current !== null && minDuration > 0) {
90
+ const elapsedTime = Date.now() - showTimeRef.current;
91
+ const remainingTime = minDuration - elapsedTime;
92
+ if (remainingTime > 0) {
93
+ minDurationTimerRef.current = setTimeout(hideLoader, remainingTime);
94
+ } else {
95
+ hideLoader();
96
+ }
97
+ } else {
98
+ hideLoader();
99
+ }
100
+ }
101
+ return () => {
102
+ if (delayTimerRef.current) {
103
+ clearTimeout(delayTimerRef.current);
104
+ }
105
+ if (minDurationTimerRef.current) {
106
+ clearTimeout(minDurationTimerRef.current);
107
+ }
108
+ if (transitionTimerRef.current) {
109
+ clearTimeout(transitionTimerRef.current);
110
+ }
111
+ };
112
+ }, [visible, delay, minDuration, hasTransition, transitionDuration]);
113
+ const opacity = hasTransition ? isTransitioning ? 1 : 0 : 1;
114
+ const transitionStyle = hasTransition ? `opacity ${transitionDuration}ms ease-in-out` : "none";
115
+ return {
116
+ shouldRender,
117
+ opacity,
118
+ transitionStyle
119
+ };
120
+ }
121
+ export {
122
+ getEffectiveDuration,
123
+ useLoaderVisibility,
124
+ useReducedMotion
125
+ };