@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 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) return;
38
- if (connection.effectiveType === "3g" || connection.effectiveType === "2g" || connection.effectiveType === "slow-2g") {
39
- onDetect();
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
- async function detectLowBattery(onDetect) {
54
+ function detectLowBattery(onDetect) {
45
55
  if (!("getBattery" in navigator)) return;
46
- const battery = await navigator.getBattery();
47
- if (battery.level < 0.2) {
48
- onDetect();
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
- window.addEventListener("click", () => {
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
- detectSlowNetwork(() => adaptive.addContext("slow-network"));
68
- detectLowBattery(() => adaptive.addContext("low-battery"));
69
- detectImpatience(() => adaptive.addContext("impatient"));
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\"));\n detectLowBattery(() => adaptive.addContext(\"low-battery\"));\n detectImpatience(() => adaptive.addContext(\"impatient\"));\n }, []);\n\n return adaptive;\n}\n","export function detectSlowNetwork(onDetect: () => void) {\n const connection = (navigator as any).connection;\n if (!connection) return;\n\n if (\n connection.effectiveType === \"3g\" ||\n connection.effectiveType === \"2g\" ||\n connection.effectiveType === \"slow-2g\"\n ) {\n onDetect();\n }\n}\n","export async function detectLowBattery(onDetect: () => void) {\n if (!(\"getBattery\" in navigator)) return;\n\n const battery = await (navigator as any).getBattery();\n if (battery.level < 0.2) {\n onDetect();\n }\n}\n","export function detectImpatience(onDetect: () => void) {\n let clicks = 0;\n\n window.addEventListener(\"click\", () => {\n clicks++;\n if (clicks >= 6) {\n onDetect();\n }\n });\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":";AAWO,IAAM,aAAN,MAAiB;AAAA,EAAjB;AACL,SAAQ,UAAU,oBAAI,IAAa;AACnC,SAAQ,aAAyB,CAAC;AAAA;AAAA,EAElC,WAAW,KAAc;AACvB,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,IAAI,KAAc;AAChB,WAAO,KAAK,QAAQ,IAAI,GAAG;AAAA,EAC7B;AAAA,EAEA,SAAS,UAAoB;AAC3B,SAAK,WAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA,EAEA,MAAM;AACJ,eAAW,KAAK,KAAK,YAAY;AAC/B,UAAI,EAAE,WAAW,MAAM,OAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG;AAChD,UAAE,QAAQ;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU;AACR,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,KAAK,OAAO;AAAA,MAChC,YAAY,KAAK,WAAW;AAAA,IAC9B;AAAA,EACF;AACF;;;ACzCA,SAAS,WAAW,gBAAgB;;;ACA7B,SAAS,kBAAkB,UAAsB;AACtD,QAAM,aAAc,UAAkB;AACtC,MAAI,CAAC,WAAY;AAEjB,MACE,WAAW,kBAAkB,QAC7B,WAAW,kBAAkB,QAC7B,WAAW,kBAAkB,WAC7B;AACA,aAAS;AAAA,EACX;AACF;;;ACXA,eAAsB,iBAAiB,UAAsB;AAC3D,MAAI,EAAE,gBAAgB,WAAY;AAElC,QAAM,UAAU,MAAO,UAAkB,WAAW;AACpD,MAAI,QAAQ,QAAQ,KAAK;AACvB,aAAS;AAAA,EACX;AACF;;;ACPO,SAAS,iBAAiB,UAAsB;AACrD,MAAI,SAAS;AAEb,SAAO,iBAAiB,SAAS,MAAM;AACrC;AACA,QAAI,UAAU,GAAG;AACf,eAAS;AAAA,IACX;AAAA,EACF,CAAC;AACH;;;AHHO,SAAS,cAAc;AAC5B,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM,IAAI,WAAW,CAAC;AAElD,YAAU,MAAM;AACd,sBAAkB,MAAM,SAAS,WAAW,cAAc,CAAC;AAC3D,qBAAiB,MAAM,SAAS,WAAW,aAAa,CAAC;AACzD,qBAAiB,MAAM,SAAS,WAAW,WAAW,CAAC;AAAA,EACzD,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;AIhBO,SAAS,SAAS;AACvB,WAAS,KAAK,UAAU,IAAI,SAAS;AACvC;AAEO,SAAS,YAAY;AAC1B,WAAS,KAAK,UAAU,IAAI,UAAU;AACxC;","names":[]}
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":";AAWO,IAAM,aAAN,MAAiB;AAAA,EAAjB;AACL,SAAQ,UAAU,oBAAI,IAAa;AACnC,SAAQ,aAAyB,CAAC;AAAA;AAAA,EAElC,WAAW,KAAc;AACvB,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,IAAI,KAAc;AAChB,WAAO,KAAK,QAAQ,IAAI,GAAG;AAAA,EAC7B;AAAA,EAEA,SAAS,UAAoB;AAC3B,SAAK,WAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA,EAEA,MAAM;AACJ,eAAW,KAAK,KAAK,YAAY;AAC/B,UAAI,EAAE,WAAW,MAAM,OAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG;AAChD,UAAE,QAAQ;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU;AACR,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,KAAK,OAAO;AAAA,MAChC,YAAY,KAAK,WAAW;AAAA,IAC9B;AAAA,EACF;AACF;;;ACzCA,SAAS,WAAW,gBAAgB;;;ACA7B,SAAS,kBAAkB,UAAkC;AAClE,QAAM,aAAc,UAAkB;AAEtC,MAAI,CAAC,YAAY;AACf,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAEA,QAAM,QAAQ,MAAM;AAClB,QAAI,WAAW,kBAAkB,QAAQ,WAAW,UAAU;AAC5D,eAAS;AAAA,IACX;AAAA,EACF;AAEA,aAAW,iBAAiB,UAAU,KAAK;AAC3C,QAAM;AAEN,SAAO,MAAM;AACX,eAAW,oBAAoB,UAAU,KAAK;AAAA,EAChD;AACF;;;ACnBO,SAAS,iBAAiB,UAAsB;AACrD,MAAI,EAAE,gBAAgB,WAAY;AAElC,YAAU,aAAa,EAAE,KAAK,CAAC,YAA4B;AACzD,QAAI,QAAQ,QAAQ,KAAK;AACvB,eAAS;AAAA,IACX;AAEA,UAAM,WAAW,MAAM;AACrB,UAAI,QAAQ,QAAQ,KAAK;AACvB,iBAAS;AAAA,MACX;AAAA,IACF;AAEA,YAAQ,iBAAiB,eAAe,QAAQ;AAEhD,WAAO,MAAM;AACX,cAAQ,oBAAoB,eAAe,QAAQ;AAAA,IACrD;AAAA,EACF,CAAC;AACH;;;ACpBO,SAAS,iBAAiB,UAAkC;AACjE,MAAI,SAAS;AACb,MAAI,YAAY;AAChB,MAAI,QAAuB;AAE3B,WAAS,cAAc;AACrB,QAAI,UAAW;AAEf;AAEA,QAAI,CAAC,OAAO;AACV,cAAQ,OAAO,WAAW,MAAM;AAC9B,iBAAS;AACT,gBAAQ;AAAA,MACV,GAAG,GAAI;AAAA,IACT;AAEA,QAAI,UAAU,GAAG;AACf,kBAAY;AACZ,eAAS;AACT,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,WAAS,UAAU;AACjB,WAAO,oBAAoB,SAAS,WAAW;AAC/C,QAAI,MAAO,cAAa,KAAK;AAAA,EAC/B;AAEA,SAAO,iBAAiB,SAAS,WAAW;AAC5C,SAAO;AACT;;;AHzBO,SAAS,cAAc;AAC5B,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM,IAAI,WAAW,CAAC;AAElD,YAAU,MAAM;AACd,UAAM,WAAW;AAAA,MACf,kBAAkB,MAAM,SAAS,WAAW,cAAc,CAAC;AAAA,MAC3D,iBAAiB,MAAM,SAAS,WAAW,aAAa,CAAC;AAAA,MACzD,iBAAiB,MAAM,SAAS,WAAW,WAAW,CAAC;AAAA,IACzD;AAEA,WAAO,MAAM;AACX,eAAS,QAAQ,CAAC,YAAY,UAAU,CAAC;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;AItBO,SAAS,SAAS;AACvB,WAAS,KAAK,UAAU,IAAI,SAAS;AACvC;AAEO,SAAS,YAAY;AAC1B,WAAS,KAAK,UAAU,IAAI,UAAU;AACxC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-technology/adaptive-ui",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Human-aware UI adaptation layer for web apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",