@checkstack/ui 1.3.2 → 1.3.3
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/components/PerformanceProvider.tsx +47 -84
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @checkstack/ui
|
|
2
2
|
|
|
3
|
+
## 1.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 594eecc: Implemented a manual "Low Power Mode" toggle in the user menu, allowing users to explicitly disable expensive visual effects. This replaces the previous automatic performance diagnostics with a more predictable, user-controlled system that persists to localStorage while still respecting OS-level "Reduced Motion" settings.
|
|
8
|
+
|
|
3
9
|
## 1.3.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
+
const STORAGE_KEY = "checkstack-low-power";
|
|
4
|
+
|
|
3
5
|
interface PerformanceContextValue {
|
|
4
6
|
/**
|
|
5
|
-
* Whether the
|
|
6
|
-
*
|
|
7
|
+
* Whether the application should run in low-power mode.
|
|
8
|
+
* Derived from (manualLowPower || prefersReducedMotion).
|
|
7
9
|
*/
|
|
8
10
|
isLowPower: boolean;
|
|
9
|
-
/** Whether the performance
|
|
11
|
+
/** Whether the performance state has been initialized from storage */
|
|
10
12
|
isLoaded: boolean;
|
|
13
|
+
/** The current state of the manual toggle */
|
|
14
|
+
manualLowPower: boolean;
|
|
15
|
+
/** Toggle the manual low power setting */
|
|
16
|
+
toggleManualLowPower: () => void;
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
const PerformanceContext = createContext<PerformanceContextValue>({
|
|
14
20
|
isLowPower: false,
|
|
15
21
|
isLoaded: false,
|
|
22
|
+
manualLowPower: false,
|
|
23
|
+
toggleManualLowPower: () => {},
|
|
16
24
|
});
|
|
17
25
|
|
|
18
26
|
/**
|
|
@@ -26,99 +34,54 @@ interface PerformanceProviderProps {
|
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
|
-
* PerformanceProvider - Centralizes
|
|
30
|
-
*
|
|
31
|
-
*
|
|
37
|
+
* PerformanceProvider - Centralizes management of the application's performance tier.
|
|
38
|
+
* Supports manual override (persisted to localStorage) and respects OS-level
|
|
39
|
+
* Reduced Motion preferences.
|
|
32
40
|
*/
|
|
33
41
|
export const PerformanceProvider: React.FC<PerformanceProviderProps> = ({ children }) => {
|
|
34
|
-
const [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
42
|
+
const [manualLowPower, setManualLowPower] = useState<boolean>(false);
|
|
43
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = useState<boolean>(false);
|
|
44
|
+
const [isLoaded, setIsLoaded] = useState<boolean>(false);
|
|
38
45
|
|
|
39
46
|
useEffect(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
// 1. Initialize Manual Toggle from localStorage
|
|
48
|
+
const stored = globalThis.localStorage?.getItem(STORAGE_KEY);
|
|
49
|
+
if (stored === "true") {
|
|
50
|
+
setManualLowPower(true);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. Initialize Reduced Motion Detection
|
|
54
|
+
const mediaQuery = globalThis.matchMedia("(prefers-reduced-motion: reduce)");
|
|
55
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(nav.deviceMemory !== undefined && nav.deviceMemory < 4) ||
|
|
50
|
-
nav.hardwareConcurrency <= 2;
|
|
57
|
+
// 3. Listen for changes in OS-level settings
|
|
58
|
+
const listener = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches);
|
|
59
|
+
mediaQuery.addEventListener("change", listener);
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
let isSoftwareRenderer = false;
|
|
54
|
-
try {
|
|
55
|
-
const canvas = document.createElement("canvas");
|
|
56
|
-
const gl =
|
|
57
|
-
canvas.getContext("webgl") ||
|
|
58
|
-
canvas.getContext("experimental-webgl");
|
|
59
|
-
|
|
60
|
-
if (gl instanceof WebGLRenderingContext) {
|
|
61
|
-
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
62
|
-
const renderer = (
|
|
63
|
-
debugInfo
|
|
64
|
-
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
|
|
65
|
-
: gl.getParameter(gl.RENDERER)
|
|
66
|
-
).toLowerCase();
|
|
61
|
+
setIsLoaded(true);
|
|
67
62
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"swiftshader",
|
|
71
|
-
"llvmpipe",
|
|
72
|
-
"softpipe",
|
|
73
|
-
"swrast",
|
|
74
|
-
"osmesa",
|
|
75
|
-
"mesa off-screen",
|
|
76
|
-
"basic render",
|
|
77
|
-
"warp",
|
|
78
|
-
].some((id) => renderer.includes(id));
|
|
79
|
-
} else {
|
|
80
|
-
// No WebGL support at all usually implies old/stripped browser
|
|
81
|
-
isSoftwareRenderer = true;
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
isSoftwareRenderer = true;
|
|
85
|
-
}
|
|
63
|
+
return () => mediaQuery.removeEventListener("change", listener);
|
|
64
|
+
}, []);
|
|
86
65
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (ctx) {
|
|
95
|
-
const t0 = globalThis.performance.now();
|
|
96
|
-
ctx.filter = "blur(20px)";
|
|
97
|
-
for (let i = 0; i < 50; i++) {
|
|
98
|
-
ctx.fillRect(i, i, 5, 5);
|
|
99
|
-
}
|
|
100
|
-
// Force pipeline sync to measure actual drawing time
|
|
101
|
-
ctx.getImageData(0, 0, 1, 1);
|
|
102
|
-
const t1 = globalThis.performance.now();
|
|
103
|
-
isSlow = t1 - t0 > 4; // Threshold for CPU-based rasterization
|
|
104
|
-
}
|
|
105
|
-
} catch {
|
|
106
|
-
isSlow = true;
|
|
107
|
-
}
|
|
66
|
+
const toggleManualLowPower = () => {
|
|
67
|
+
setManualLowPower((prev) => {
|
|
68
|
+
const next = !prev;
|
|
69
|
+
globalThis.localStorage?.setItem(STORAGE_KEY, String(next));
|
|
70
|
+
return next;
|
|
71
|
+
});
|
|
72
|
+
};
|
|
108
73
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
setState({
|
|
112
|
-
isLowPower: isLowPowerVerdict,
|
|
113
|
-
isLoaded: true,
|
|
114
|
-
});
|
|
115
|
-
};
|
|
74
|
+
const isLowPower = manualLowPower || prefersReducedMotion;
|
|
116
75
|
|
|
117
|
-
|
|
118
|
-
|
|
76
|
+
const value = {
|
|
77
|
+
isLowPower,
|
|
78
|
+
isLoaded,
|
|
79
|
+
manualLowPower,
|
|
80
|
+
toggleManualLowPower,
|
|
81
|
+
};
|
|
119
82
|
|
|
120
83
|
return (
|
|
121
|
-
<PerformanceContext.Provider value={
|
|
84
|
+
<PerformanceContext.Provider value={value}>
|
|
122
85
|
{children}
|
|
123
86
|
</PerformanceContext.Provider>
|
|
124
87
|
);
|