@develemit/web-hooks 0.2.0 → 0.3.1

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 (57) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +157 -0
  3. package/dist/chunk-4PVVTQ5V.js +74 -0
  4. package/dist/{chunk-OZ4PU4E3.js → chunk-5XRVPZHD.js} +14 -4
  5. package/dist/{chunk-3UGRXQIA.js → chunk-DQBKU7HI.js} +10 -3
  6. package/dist/chunk-EXEJI4FK.js +43 -0
  7. package/dist/{chunk-3CACI4OQ.js → chunk-FE3BQD2I.js} +1 -25
  8. package/dist/chunk-HTVNN2NM.js +29 -0
  9. package/dist/chunk-R2PFNE3U.js +154 -0
  10. package/dist/chunk-TNEJ34T5.js +86 -0
  11. package/dist/chunk-UVJBJETY.js +121 -0
  12. package/dist/{chunk-UZADAINO.js → chunk-WVM2LTWQ.js} +2 -21
  13. package/dist/chunk-WXL22EWK.js +21 -0
  14. package/dist/chunk-YFMMSLMB.js +41 -0
  15. package/dist/chunk-Z3X27PCA.js +108 -0
  16. package/dist/clipboard.cjs +13 -0
  17. package/dist/clipboard.d.cts +10 -1
  18. package/dist/clipboard.d.ts +10 -1
  19. package/dist/clipboard.js +6 -2
  20. package/dist/drawer-swipe.cjs +16 -4
  21. package/dist/drawer-swipe.d.cts +7 -3
  22. package/dist/drawer-swipe.d.ts +7 -3
  23. package/dist/drawer-swipe.js +5 -1
  24. package/dist/index.cjs +637 -19
  25. package/dist/index.d.cts +8 -2
  26. package/dist/index.d.ts +8 -2
  27. package/dist/index.js +77 -7
  28. package/dist/keyboard-inset.cjs +113 -0
  29. package/dist/keyboard-inset.d.cts +25 -0
  30. package/dist/keyboard-inset.d.ts +25 -0
  31. package/dist/keyboard-inset.js +11 -0
  32. package/dist/media-query.js +5 -3
  33. package/dist/online-status.cjs +46 -0
  34. package/dist/online-status.d.cts +3 -0
  35. package/dist/online-status.d.ts +3 -0
  36. package/dist/online-status.js +7 -0
  37. package/dist/outside-press.cjs +10 -3
  38. package/dist/outside-press.d.cts +4 -2
  39. package/dist/outside-press.d.ts +4 -2
  40. package/dist/outside-press.js +1 -1
  41. package/dist/push.cjs +209 -0
  42. package/dist/push.d.cts +38 -0
  43. package/dist/push.d.ts +38 -0
  44. package/dist/push.js +14 -0
  45. package/dist/pwa.cjs +198 -0
  46. package/dist/pwa.d.cts +35 -0
  47. package/dist/pwa.d.ts +35 -0
  48. package/dist/pwa.js +22 -0
  49. package/dist/service-worker.cjs +148 -0
  50. package/dist/service-worker.d.cts +24 -0
  51. package/dist/service-worker.d.ts +24 -0
  52. package/dist/service-worker.js +11 -0
  53. package/dist/share.cjs +139 -0
  54. package/dist/share.d.cts +23 -0
  55. package/dist/share.d.ts +23 -0
  56. package/dist/share.js +16 -0
  57. package/package.json +31 -1
@@ -0,0 +1,148 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/service-worker/index.ts
22
+ var service_worker_exports = {};
23
+ __export(service_worker_exports, {
24
+ deriveUpdateState: () => deriveUpdateState,
25
+ unregisterAll: () => unregisterAll,
26
+ useServiceWorker: () => useServiceWorker
27
+ });
28
+ module.exports = __toCommonJS(service_worker_exports);
29
+
30
+ // src/service-worker/use-service-worker.ts
31
+ var import_react = require("react");
32
+
33
+ // src/service-worker/update-state.ts
34
+ function deriveUpdateState({ hasController: hasController2, waiting, installingState }) {
35
+ if (!hasController2) return false;
36
+ return waiting || installingState === "installed";
37
+ }
38
+
39
+ // src/service-worker/register.ts
40
+ var reloaded = false;
41
+ function isServiceWorkerSupported() {
42
+ return typeof navigator !== "undefined" && "serviceWorker" in navigator;
43
+ }
44
+ var hasController = () => Boolean(navigator.serviceWorker.controller);
45
+ async function unregisterAll() {
46
+ if (!isServiceWorkerSupported()) return;
47
+ try {
48
+ const registrations = await navigator.serviceWorker.getRegistrations();
49
+ await Promise.all(registrations.map((r) => r.unregister()));
50
+ } catch {
51
+ }
52
+ }
53
+ function registerServiceWorker({ url, scope, onUpdateAvailable, onError }, { reload = () => window.location.reload() } = {}) {
54
+ let registration;
55
+ let disposed = false;
56
+ let applying = false;
57
+ const cleanups = [];
58
+ const controlledAtStart = hasController();
59
+ let activatedUnasked = false;
60
+ const reloadOnce = () => {
61
+ if (reloaded) return;
62
+ reloaded = true;
63
+ reload();
64
+ };
65
+ const onControllerChange = () => {
66
+ if (applying) return reloadOnce();
67
+ if (!controlledAtStart || activatedUnasked) return;
68
+ activatedUnasked = true;
69
+ onUpdateAvailable();
70
+ };
71
+ navigator.serviceWorker.addEventListener("controllerchange", onControllerChange);
72
+ cleanups.push(() => navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange));
73
+ const watchInstalling = (reg) => {
74
+ const worker = reg.installing;
75
+ if (!worker) return;
76
+ const onState = () => {
77
+ if (deriveUpdateState({ hasController: hasController(), waiting: false, installingState: worker.state })) {
78
+ onUpdateAvailable();
79
+ }
80
+ };
81
+ worker.addEventListener("statechange", onState);
82
+ cleanups.push(() => worker.removeEventListener("statechange", onState));
83
+ };
84
+ navigator.serviceWorker.register(url, scope === void 0 ? void 0 : { scope }).then((reg) => {
85
+ if (disposed) return;
86
+ registration = reg;
87
+ if (deriveUpdateState({ hasController: hasController(), waiting: Boolean(reg.waiting) })) {
88
+ onUpdateAvailable();
89
+ }
90
+ const onUpdateFound = () => watchInstalling(reg);
91
+ reg.addEventListener("updatefound", onUpdateFound);
92
+ cleanups.push(() => reg.removeEventListener("updatefound", onUpdateFound));
93
+ }).catch((error) => {
94
+ if (disposed) return;
95
+ try {
96
+ onError?.(error);
97
+ } catch {
98
+ }
99
+ });
100
+ return {
101
+ applyUpdate() {
102
+ if (activatedUnasked) return reloadOnce();
103
+ const waiting = registration?.waiting;
104
+ if (!waiting) return;
105
+ applying = true;
106
+ waiting.postMessage({ type: "SKIP_WAITING" });
107
+ },
108
+ dispose() {
109
+ disposed = true;
110
+ cleanups.splice(0).forEach((fn) => fn());
111
+ }
112
+ };
113
+ }
114
+
115
+ // src/service-worker/use-service-worker.ts
116
+ function useServiceWorker({ url, scope, enabled = true, onError }) {
117
+ const [supported, setSupported] = (0, import_react.useState)(true);
118
+ const [updateAvailable, setUpdateAvailable] = (0, import_react.useState)(false);
119
+ const onErrorRef = (0, import_react.useRef)(onError);
120
+ onErrorRef.current = onError;
121
+ const handle = (0, import_react.useRef)(void 0);
122
+ (0, import_react.useEffect)(() => {
123
+ if (!enabled) return;
124
+ if (!isServiceWorkerSupported()) {
125
+ setSupported(false);
126
+ return;
127
+ }
128
+ const registered = registerServiceWorker({
129
+ url,
130
+ scope,
131
+ onUpdateAvailable: () => setUpdateAvailable(true),
132
+ onError: (error) => onErrorRef.current?.(error)
133
+ });
134
+ handle.current = registered;
135
+ return () => {
136
+ registered.dispose();
137
+ handle.current = void 0;
138
+ };
139
+ }, [url, scope, enabled]);
140
+ const applyUpdate = (0, import_react.useCallback)(() => handle.current?.applyUpdate(), []);
141
+ return { supported, updateAvailable, applyUpdate };
142
+ }
143
+ // Annotate the CommonJS export names for ESM import in node:
144
+ 0 && (module.exports = {
145
+ deriveUpdateState,
146
+ unregisterAll,
147
+ useServiceWorker
148
+ });
@@ -0,0 +1,24 @@
1
+ interface UseServiceWorkerOptions {
2
+ url: string;
3
+ scope?: string;
4
+ enabled?: boolean;
5
+ onError?: (error: unknown) => void;
6
+ }
7
+ interface ServiceWorkerState$1 {
8
+ supported: boolean;
9
+ updateAvailable: boolean;
10
+ applyUpdate: () => void;
11
+ }
12
+ declare function useServiceWorker({ url, scope, enabled, onError }: UseServiceWorkerOptions): ServiceWorkerState$1;
13
+
14
+ declare function unregisterAll(): Promise<void>;
15
+
16
+ interface UpdateStateInput {
17
+ hasController: boolean;
18
+ waiting: boolean;
19
+ installingState?: ServiceWorkerState | null;
20
+ }
21
+ /** A first install (no controller yet) is never an "update". */
22
+ declare function deriveUpdateState({ hasController, waiting, installingState }: UpdateStateInput): boolean;
23
+
24
+ export { type ServiceWorkerState$1 as ServiceWorkerState, type UpdateStateInput, type UseServiceWorkerOptions, deriveUpdateState, unregisterAll, useServiceWorker };
@@ -0,0 +1,24 @@
1
+ interface UseServiceWorkerOptions {
2
+ url: string;
3
+ scope?: string;
4
+ enabled?: boolean;
5
+ onError?: (error: unknown) => void;
6
+ }
7
+ interface ServiceWorkerState$1 {
8
+ supported: boolean;
9
+ updateAvailable: boolean;
10
+ applyUpdate: () => void;
11
+ }
12
+ declare function useServiceWorker({ url, scope, enabled, onError }: UseServiceWorkerOptions): ServiceWorkerState$1;
13
+
14
+ declare function unregisterAll(): Promise<void>;
15
+
16
+ interface UpdateStateInput {
17
+ hasController: boolean;
18
+ waiting: boolean;
19
+ installingState?: ServiceWorkerState | null;
20
+ }
21
+ /** A first install (no controller yet) is never an "update". */
22
+ declare function deriveUpdateState({ hasController, waiting, installingState }: UpdateStateInput): boolean;
23
+
24
+ export { type ServiceWorkerState$1 as ServiceWorkerState, type UpdateStateInput, type UseServiceWorkerOptions, deriveUpdateState, unregisterAll, useServiceWorker };
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import {
3
+ deriveUpdateState,
4
+ unregisterAll,
5
+ useServiceWorker
6
+ } from "./chunk-UVJBJETY.js";
7
+ export {
8
+ deriveUpdateState,
9
+ unregisterAll,
10
+ useServiceWorker
11
+ };
package/dist/share.cjs ADDED
@@ -0,0 +1,139 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/share/index.ts
22
+ var share_exports = {};
23
+ __export(share_exports, {
24
+ canShareFiles: () => canShareFiles,
25
+ isShareCancel: () => isShareCancel,
26
+ shareOrCopy: () => shareOrCopy,
27
+ shareTextFor: () => shareTextFor,
28
+ useShareFeedback: () => useShareFeedback
29
+ });
30
+ module.exports = __toCommonJS(share_exports);
31
+
32
+ // src/share/share-text.ts
33
+ function shareTextFor({ text, url }) {
34
+ return [text, url].filter((part) => !!part).join("\n");
35
+ }
36
+ function isShareCancel(error) {
37
+ return typeof error === "object" && error !== null && error.name === "AbortError";
38
+ }
39
+
40
+ // src/clipboard/copy-text.ts
41
+ async function copyText(text) {
42
+ const hasClipboardApi = typeof navigator !== "undefined" && !!navigator.clipboard?.writeText && typeof window !== "undefined" && window.isSecureContext;
43
+ if (hasClipboardApi) {
44
+ try {
45
+ await navigator.clipboard.writeText(text);
46
+ return { ok: true };
47
+ } catch {
48
+ }
49
+ }
50
+ if (execCommandCopy(text)) return { ok: true };
51
+ return { ok: false, reason: hasClipboardApi ? "denied" : "unavailable" };
52
+ }
53
+ function execCommandCopy(text) {
54
+ if (typeof document === "undefined") return false;
55
+ const textarea = document.createElement("textarea");
56
+ textarea.value = text;
57
+ textarea.readOnly = true;
58
+ textarea.style.position = "fixed";
59
+ textarea.style.top = "-1000px";
60
+ textarea.style.left = "-1000px";
61
+ textarea.style.fontSize = "16px";
62
+ const previouslyFocused = document.activeElement;
63
+ document.body.appendChild(textarea);
64
+ try {
65
+ textarea.focus({ preventScroll: true });
66
+ textarea.select();
67
+ textarea.setSelectionRange(0, text.length);
68
+ return document.execCommand("copy");
69
+ } catch {
70
+ return false;
71
+ } finally {
72
+ document.body.removeChild(textarea);
73
+ if (previouslyFocused instanceof HTMLElement && previouslyFocused !== document.body) {
74
+ previouslyFocused.focus({ preventScroll: true });
75
+ }
76
+ }
77
+ }
78
+
79
+ // src/share/share-or-copy.ts
80
+ async function shareOrCopy(data) {
81
+ if (canShareNatively(data)) {
82
+ try {
83
+ await navigator.share(data);
84
+ return { status: "shared" };
85
+ } catch (error) {
86
+ if (isShareCancel(error)) return { status: "cancelled" };
87
+ }
88
+ }
89
+ const result = await copyText(shareTextFor(data));
90
+ return { status: result.ok ? "copied" : "failed" };
91
+ }
92
+ function canShareFiles(files) {
93
+ if (typeof navigator === "undefined" || typeof navigator.canShare !== "function") return false;
94
+ try {
95
+ return navigator.canShare({ files });
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+ function canShareNatively(data) {
101
+ if (typeof navigator === "undefined" || typeof navigator.share !== "function") return false;
102
+ if (typeof navigator.canShare !== "function") return true;
103
+ try {
104
+ return navigator.canShare(data);
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+
110
+ // src/share/use-share-feedback.ts
111
+ var import_react = require("react");
112
+ function useShareFeedback({ resetMs = 1500 } = {}) {
113
+ const [status, setStatus] = (0, import_react.useState)("idle");
114
+ const timerRef = (0, import_react.useRef)(void 0);
115
+ const clearTimer = (0, import_react.useCallback)(() => {
116
+ if (timerRef.current !== void 0) clearTimeout(timerRef.current);
117
+ timerRef.current = void 0;
118
+ }, []);
119
+ (0, import_react.useEffect)(() => clearTimer, [clearTimer]);
120
+ const share = (0, import_react.useCallback)(
121
+ async (data) => {
122
+ const result = await shareOrCopy(data);
123
+ clearTimer();
124
+ setStatus(result.status);
125
+ timerRef.current = setTimeout(() => setStatus("idle"), resetMs);
126
+ return result;
127
+ },
128
+ [clearTimer, resetMs]
129
+ );
130
+ return { share, status };
131
+ }
132
+ // Annotate the CommonJS export names for ESM import in node:
133
+ 0 && (module.exports = {
134
+ canShareFiles,
135
+ isShareCancel,
136
+ shareOrCopy,
137
+ shareTextFor,
138
+ useShareFeedback
139
+ });
@@ -0,0 +1,23 @@
1
+ interface ShareInput {
2
+ title?: string;
3
+ text?: string;
4
+ url?: string;
5
+ }
6
+ declare function shareTextFor({ text, url }: ShareInput): string;
7
+ declare function isShareCancel(error: unknown): boolean;
8
+
9
+ type ShareResult = {
10
+ status: 'shared' | 'copied' | 'cancelled' | 'failed';
11
+ };
12
+ declare function shareOrCopy(data: ShareInput): Promise<ShareResult>;
13
+ declare function canShareFiles(files: File[]): boolean;
14
+
15
+ type ShareStatus = 'idle' | ShareResult['status'];
16
+ declare function useShareFeedback({ resetMs }?: {
17
+ resetMs?: number;
18
+ }): {
19
+ share: (data: ShareInput) => Promise<ShareResult>;
20
+ status: ShareStatus;
21
+ };
22
+
23
+ export { type ShareInput, type ShareResult, type ShareStatus, canShareFiles, isShareCancel, shareOrCopy, shareTextFor, useShareFeedback };
@@ -0,0 +1,23 @@
1
+ interface ShareInput {
2
+ title?: string;
3
+ text?: string;
4
+ url?: string;
5
+ }
6
+ declare function shareTextFor({ text, url }: ShareInput): string;
7
+ declare function isShareCancel(error: unknown): boolean;
8
+
9
+ type ShareResult = {
10
+ status: 'shared' | 'copied' | 'cancelled' | 'failed';
11
+ };
12
+ declare function shareOrCopy(data: ShareInput): Promise<ShareResult>;
13
+ declare function canShareFiles(files: File[]): boolean;
14
+
15
+ type ShareStatus = 'idle' | ShareResult['status'];
16
+ declare function useShareFeedback({ resetMs }?: {
17
+ resetMs?: number;
18
+ }): {
19
+ share: (data: ShareInput) => Promise<ShareResult>;
20
+ status: ShareStatus;
21
+ };
22
+
23
+ export { type ShareInput, type ShareResult, type ShareStatus, canShareFiles, isShareCancel, shareOrCopy, shareTextFor, useShareFeedback };
package/dist/share.js ADDED
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import {
3
+ canShareFiles,
4
+ isShareCancel,
5
+ shareOrCopy,
6
+ shareTextFor,
7
+ useShareFeedback
8
+ } from "./chunk-4PVVTQ5V.js";
9
+ import "./chunk-FE3BQD2I.js";
10
+ export {
11
+ canShareFiles,
12
+ isShareCancel,
13
+ shareOrCopy,
14
+ shareTextFor,
15
+ useShareFeedback
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@develemit/web-hooks",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Shared React behavior hooks for develemit web apps: drawer swipe, focus trap, escape key and clipboard.",
5
5
  "license": "MIT",
6
6
  "author": "Emit Dutcher",
@@ -79,6 +79,36 @@
79
79
  "types": "./dist/auto-grow.d.ts",
80
80
  "import": "./dist/auto-grow.js",
81
81
  "require": "./dist/auto-grow.cjs"
82
+ },
83
+ "./pwa": {
84
+ "types": "./dist/pwa.d.ts",
85
+ "import": "./dist/pwa.js",
86
+ "require": "./dist/pwa.cjs"
87
+ },
88
+ "./online-status": {
89
+ "types": "./dist/online-status.d.ts",
90
+ "import": "./dist/online-status.js",
91
+ "require": "./dist/online-status.cjs"
92
+ },
93
+ "./service-worker": {
94
+ "types": "./dist/service-worker.d.ts",
95
+ "import": "./dist/service-worker.js",
96
+ "require": "./dist/service-worker.cjs"
97
+ },
98
+ "./share": {
99
+ "types": "./dist/share.d.ts",
100
+ "import": "./dist/share.js",
101
+ "require": "./dist/share.cjs"
102
+ },
103
+ "./keyboard-inset": {
104
+ "types": "./dist/keyboard-inset.d.ts",
105
+ "import": "./dist/keyboard-inset.js",
106
+ "require": "./dist/keyboard-inset.cjs"
107
+ },
108
+ "./push": {
109
+ "types": "./dist/push.d.ts",
110
+ "import": "./dist/push.js",
111
+ "require": "./dist/push.cjs"
82
112
  }
83
113
  },
84
114
  "main": "./dist/index.cjs",