@c-technology/adaptive-ui 0.1.6 → 0.1.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.js +55 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,39 +34,81 @@ import { useEffect, useState } from "react";
|
|
|
34
34
|
// src/signals/network.ts
|
|
35
35
|
function detectSlowNetwork(onDetect) {
|
|
36
36
|
const connection = navigator.connection;
|
|
37
|
-
if (!connection)
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (!connection) {
|
|
38
|
+
return () => {
|
|
39
|
+
};
|
|
40
40
|
}
|
|
41
|
+
const check = () => {
|
|
42
|
+
if (connection.effectiveType === "2g" || connection.saveData) {
|
|
43
|
+
onDetect();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
connection.addEventListener("change", check);
|
|
47
|
+
check();
|
|
48
|
+
return () => {
|
|
49
|
+
connection.removeEventListener("change", check);
|
|
50
|
+
};
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
// src/signals/battery.ts
|
|
44
|
-
|
|
54
|
+
function detectLowBattery(onDetect) {
|
|
45
55
|
if (!("getBattery" in navigator)) return;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
navigator.getBattery?.().then((battery) => {
|
|
57
|
+
if (battery.level < 0.2) {
|
|
58
|
+
onDetect();
|
|
59
|
+
}
|
|
60
|
+
const onChange = () => {
|
|
61
|
+
if (battery.level < 0.2) {
|
|
62
|
+
onDetect();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
battery.addEventListener("levelchange", onChange);
|
|
66
|
+
return () => {
|
|
67
|
+
battery.removeEventListener("levelchange", onChange);
|
|
68
|
+
};
|
|
69
|
+
});
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
// src/signals/behavior.ts
|
|
53
73
|
function detectImpatience(onDetect) {
|
|
54
74
|
let clicks = 0;
|
|
55
|
-
|
|
75
|
+
let triggered = false;
|
|
76
|
+
let timer = null;
|
|
77
|
+
function handleClick() {
|
|
78
|
+
if (triggered) return;
|
|
56
79
|
clicks++;
|
|
80
|
+
if (!timer) {
|
|
81
|
+
timer = window.setTimeout(() => {
|
|
82
|
+
clicks = 0;
|
|
83
|
+
timer = null;
|
|
84
|
+
}, 2e3);
|
|
85
|
+
}
|
|
57
86
|
if (clicks >= 6) {
|
|
87
|
+
triggered = true;
|
|
58
88
|
onDetect();
|
|
89
|
+
cleanup();
|
|
59
90
|
}
|
|
60
|
-
}
|
|
91
|
+
}
|
|
92
|
+
function cleanup() {
|
|
93
|
+
window.removeEventListener("click", handleClick);
|
|
94
|
+
if (timer) clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
window.addEventListener("click", handleClick);
|
|
97
|
+
return cleanup;
|
|
61
98
|
}
|
|
62
99
|
|
|
63
100
|
// src/react.ts
|
|
64
101
|
function useAdaptive() {
|
|
65
102
|
const [adaptive] = useState(() => new AdaptiveUI());
|
|
66
103
|
useEffect(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
104
|
+
const cleanups = [
|
|
105
|
+
detectSlowNetwork(() => adaptive.addContext("slow-network")),
|
|
106
|
+
detectLowBattery(() => adaptive.addContext("low-battery")),
|
|
107
|
+
detectImpatience(() => adaptive.addContext("impatient"))
|
|
108
|
+
];
|
|
109
|
+
return () => {
|
|
110
|
+
cleanups.forEach((cleanup) => cleanup?.());
|
|
111
|
+
};
|
|
70
112
|
}, []);
|
|
71
113
|
return adaptive;
|
|
72
114
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adaptive.ts","../src/react.ts","../src/signals/network.ts","../src/signals/battery.ts","../src/signals/behavior.ts","../src/strategies.ts"],"sourcesContent":["export type Context =\n | \"slow-network\"\n | \"low-battery\"\n | \"impatient\"\n | \"new-user\";\n\ntype Strategy = {\n conditions: Context[];\n actions: () => void;\n};\n\nexport class AdaptiveUI {\n private context = new Set<Context>();\n private strategies: Strategy[] = [];\n\n addContext(ctx: Context) {\n this.context.add(ctx);\n }\n\n has(ctx: Context) {\n return this.context.has(ctx);\n }\n\n strategy(strategy: Strategy) {\n this.strategies.push(strategy);\n }\n\n run() {\n for (const s of this.strategies) {\n if (s.conditions.every(c => this.context.has(c))) {\n s.actions();\n }\n }\n }\n\n explain() {\n return {\n context: Array.from(this.context),\n strategies: this.strategies.length,\n };\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { AdaptiveUI } from \"./adaptive\";\nimport { detectSlowNetwork } from \"./signals/network\";\nimport { detectLowBattery } from \"./signals/battery\";\nimport { detectImpatience } from \"./signals/behavior\";\n\nexport function useAdaptive() {\n const [adaptive] = useState(() => new AdaptiveUI());\n\n useEffect(() => {\n detectSlowNetwork(() => adaptive.addContext(\"slow-network\"))
|
|
1
|
+
{"version":3,"sources":["../src/adaptive.ts","../src/react.ts","../src/signals/network.ts","../src/signals/battery.ts","../src/signals/behavior.ts","../src/strategies.ts"],"sourcesContent":["export type Context =\n | \"slow-network\"\n | \"low-battery\"\n | \"impatient\"\n | \"new-user\";\n\ntype Strategy = {\n conditions: Context[];\n actions: () => void;\n};\n\nexport class AdaptiveUI {\n private context = new Set<Context>();\n private strategies: Strategy[] = [];\n\n addContext(ctx: Context) {\n this.context.add(ctx);\n }\n\n has(ctx: Context) {\n return this.context.has(ctx);\n }\n\n strategy(strategy: Strategy) {\n this.strategies.push(strategy);\n }\n\n run() {\n for (const s of this.strategies) {\n if (s.conditions.every(c => this.context.has(c))) {\n s.actions();\n }\n }\n }\n\n explain() {\n return {\n context: Array.from(this.context),\n strategies: this.strategies.length,\n };\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { AdaptiveUI } from \"./adaptive\";\nimport { detectSlowNetwork } from \"./signals/network\";\nimport { detectLowBattery } from \"./signals/battery\";\nimport { detectImpatience } from \"./signals/behavior\";\n\nexport function useAdaptive() {\n const [adaptive] = useState(() => new AdaptiveUI());\n\n useEffect(() => {\n const cleanups = [\n detectSlowNetwork(() => adaptive.addContext(\"slow-network\")),\n detectLowBattery(() => adaptive.addContext(\"low-battery\")),\n detectImpatience(() => adaptive.addContext(\"impatient\")),\n ];\n\n return () => {\n cleanups.forEach((cleanup) => cleanup?.());\n };\n }, []);\n\n return adaptive;\n}\n","export function detectSlowNetwork(onDetect: () => void): () => void {\n const connection = (navigator as any).connection;\n\n if (!connection) {\n return () => {};\n }\n\n const check = () => {\n if (connection.effectiveType === \"2g\" || connection.saveData) {\n onDetect();\n }\n };\n\n connection.addEventListener(\"change\", check);\n check();\n\n return () => {\n connection.removeEventListener(\"change\", check);\n };\n}\n","export function detectLowBattery(onDetect: () => void) {\n if (!(\"getBattery\" in navigator)) return;\n\n navigator.getBattery?.().then((battery: BatteryManager) => {\n if (battery.level < 0.2) {\n onDetect();\n }\n\n const onChange = () => {\n if (battery.level < 0.2) {\n onDetect();\n }\n };\n\n battery.addEventListener(\"levelchange\", onChange);\n\n return () => {\n battery.removeEventListener(\"levelchange\", onChange);\n };\n });\n}\n","export function detectImpatience(onDetect: () => void): () => void {\n let clicks = 0;\n let triggered = false;\n let timer: number | null = null;\n\n function handleClick() {\n if (triggered) return;\n\n clicks++;\n\n if (!timer) {\n timer = window.setTimeout(() => {\n clicks = 0;\n timer = null;\n }, 2000);\n }\n\n if (clicks >= 6) {\n triggered = true;\n onDetect();\n cleanup();\n }\n }\n\n function cleanup() {\n window.removeEventListener(\"click\", handleClick);\n if (timer) clearTimeout(timer);\n }\n\n window.addEventListener(\"click\", handleClick);\n return cleanup;\n}\n","export function liteUI() {\n document.body.classList.add(\"ui-lite\");\n}\n\nexport function focusMode() {\n document.body.classList.add(\"ui-focus\");\n}\n"],"mappings":"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","names":[]}
|