@develemit/web-hooks 0.1.0 → 0.3.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.
- package/CHANGELOG.md +28 -0
- package/README.md +311 -0
- package/dist/auto-grow.cjs +60 -0
- package/dist/auto-grow.d.cts +14 -0
- package/dist/auto-grow.d.ts +14 -0
- package/dist/auto-grow.js +9 -0
- package/dist/chunk-4PVVTQ5V.js +74 -0
- package/dist/chunk-5CA5RIMH.js +34 -0
- package/dist/chunk-5KIH2XLV.js +136 -0
- package/dist/chunk-5XRVPZHD.js +125 -0
- package/dist/chunk-6KCRVSLS.js +80 -0
- package/dist/chunk-DNU57XEJ.js +82 -0
- package/dist/chunk-DQBKU7HI.js +46 -0
- package/dist/chunk-EXEJI4FK.js +43 -0
- package/dist/chunk-FE3BQD2I.js +44 -0
- package/dist/chunk-HTVNN2NM.js +29 -0
- package/dist/chunk-IWQDAJEP.js +69 -0
- package/dist/chunk-JG3GPTMY.js +101 -0
- package/dist/chunk-LZKAGDER.js +22 -0
- package/dist/chunk-NKLEB5TR.js +98 -0
- package/dist/chunk-S4YKMGQE.js +23 -0
- package/dist/chunk-TNEJ34T5.js +86 -0
- package/dist/chunk-UJ366T3Y.js +146 -0
- package/dist/chunk-UPVNSGIK.js +72 -0
- package/dist/chunk-WVM2LTWQ.js +42 -0
- package/dist/chunk-WXL22EWK.js +21 -0
- package/dist/chunk-YFMMSLMB.js +41 -0
- package/dist/chunk-Z3X27PCA.js +108 -0
- package/dist/clipboard.cjs +18 -0
- package/dist/clipboard.d.cts +10 -1
- package/dist/clipboard.d.ts +10 -1
- package/dist/clipboard.js +8 -57
- package/dist/debounce.cjs +96 -0
- package/dist/debounce.d.cts +21 -0
- package/dist/debounce.d.ts +21 -0
- package/dist/debounce.js +11 -0
- package/dist/drawer-swipe.cjs +16 -4
- package/dist/drawer-swipe.d.cts +7 -3
- package/dist/drawer-swipe.d.ts +7 -3
- package/dist/drawer-swipe.js +16 -101
- package/dist/escape.cjs +1 -0
- package/dist/escape.js +3 -17
- package/dist/focus-trap.cjs +3 -1
- package/dist/focus-trap.js +6 -72
- package/dist/hotkey.cjs +127 -0
- package/dist/hotkey.d.cts +31 -0
- package/dist/hotkey.d.ts +31 -0
- package/dist/hotkey.js +15 -0
- package/dist/index.cjs +1207 -7
- package/dist/index.d.cts +20 -60
- package/dist/index.d.ts +20 -60
- package/dist/index.js +167 -247
- package/dist/keyboard-inset.cjs +113 -0
- package/dist/keyboard-inset.d.cts +25 -0
- package/dist/keyboard-inset.d.ts +25 -0
- package/dist/keyboard-inset.js +11 -0
- package/dist/media-query.cjs +90 -0
- package/dist/media-query.d.cts +12 -0
- package/dist/media-query.d.ts +12 -0
- package/dist/media-query.js +17 -0
- package/dist/online-status.cjs +46 -0
- package/dist/online-status.d.cts +3 -0
- package/dist/online-status.d.ts +3 -0
- package/dist/online-status.js +7 -0
- package/dist/outside-press.cjs +73 -0
- package/dist/outside-press.d.cts +17 -0
- package/dist/outside-press.d.ts +17 -0
- package/dist/outside-press.js +11 -0
- package/dist/push.cjs +201 -0
- package/dist/push.d.cts +37 -0
- package/dist/push.d.ts +37 -0
- package/dist/push.js +14 -0
- package/dist/pwa.cjs +198 -0
- package/dist/pwa.d.cts +35 -0
- package/dist/pwa.d.ts +35 -0
- package/dist/pwa.js +22 -0
- package/dist/scroll-lock.cjs +107 -0
- package/dist/scroll-lock.d.cts +8 -0
- package/dist/scroll-lock.d.ts +8 -0
- package/dist/scroll-lock.js +11 -0
- package/dist/service-worker.cjs +128 -0
- package/dist/service-worker.d.cts +23 -0
- package/dist/service-worker.d.ts +23 -0
- package/dist/service-worker.js +11 -0
- package/dist/share.cjs +139 -0
- package/dist/share.d.cts +23 -0
- package/dist/share.d.ts +23 -0
- package/dist/share.js +16 -0
- package/dist/storage-state.cjs +161 -0
- package/dist/storage-state.d.cts +14 -0
- package/dist/storage-state.d.ts +14 -0
- package/dist/storage-state.js +7 -0
- package/dist/unsaved-guard.cjs +48 -0
- package/dist/unsaved-guard.d.cts +5 -0
- package/dist/unsaved-guard.d.ts +5 -0
- package/dist/unsaved-guard.js +9 -0
- package/dist/visibility-polling.cjs +98 -0
- package/dist/visibility-polling.d.cts +14 -0
- package/dist/visibility-polling.d.ts +14 -0
- package/dist/visibility-polling.js +9 -0
- package/package.json +85 -2
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
STANDALONE_QUERY,
|
|
4
|
+
isIosSafari,
|
|
5
|
+
isStandalone
|
|
6
|
+
} from "./chunk-YFMMSLMB.js";
|
|
7
|
+
import {
|
|
8
|
+
subscribe
|
|
9
|
+
} from "./chunk-WVM2LTWQ.js";
|
|
10
|
+
|
|
11
|
+
// src/pwa/use-is-standalone.ts
|
|
12
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
13
|
+
function useIsStandalone() {
|
|
14
|
+
const subscribeToMode = useCallback((onChange) => subscribe(STANDALONE_QUERY, onChange), []);
|
|
15
|
+
return useSyncExternalStore(subscribeToMode, isStandalone, () => false);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/pwa/use-install-prompt.ts
|
|
19
|
+
import { useEffect, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
20
|
+
|
|
21
|
+
// src/pwa/install-store.ts
|
|
22
|
+
var state = { event: null, installed: false };
|
|
23
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
24
|
+
var permanent = false;
|
|
25
|
+
var holders = 0;
|
|
26
|
+
var attached = false;
|
|
27
|
+
function set(next) {
|
|
28
|
+
state = next;
|
|
29
|
+
subscribers.forEach((fn) => fn());
|
|
30
|
+
}
|
|
31
|
+
function onBeforeInstallPrompt(e) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
set({ ...state, event: e });
|
|
34
|
+
}
|
|
35
|
+
function onAppInstalled() {
|
|
36
|
+
set({ event: null, installed: true });
|
|
37
|
+
}
|
|
38
|
+
function sync() {
|
|
39
|
+
const wanted = permanent || holders > 0;
|
|
40
|
+
if (wanted === attached || typeof window === "undefined") return;
|
|
41
|
+
attached = wanted;
|
|
42
|
+
const toggle = wanted ? window.addEventListener : window.removeEventListener;
|
|
43
|
+
toggle.call(window, "beforeinstallprompt", onBeforeInstallPrompt);
|
|
44
|
+
toggle.call(window, "appinstalled", onAppInstalled);
|
|
45
|
+
}
|
|
46
|
+
function startInstallPromptCapture() {
|
|
47
|
+
permanent = true;
|
|
48
|
+
sync();
|
|
49
|
+
}
|
|
50
|
+
function acquireCapture() {
|
|
51
|
+
holders += 1;
|
|
52
|
+
sync();
|
|
53
|
+
let released = false;
|
|
54
|
+
return () => {
|
|
55
|
+
if (released) return;
|
|
56
|
+
released = true;
|
|
57
|
+
holders -= 1;
|
|
58
|
+
sync();
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function getInstallState() {
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
function subscribeInstallState(onChange) {
|
|
65
|
+
subscribers.add(onChange);
|
|
66
|
+
return () => {
|
|
67
|
+
subscribers.delete(onChange);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function promptInstall() {
|
|
71
|
+
const event = state.event;
|
|
72
|
+
if (!event) return "unavailable";
|
|
73
|
+
set({ ...state, event: null });
|
|
74
|
+
try {
|
|
75
|
+
await event.prompt();
|
|
76
|
+
const { outcome } = await event.userChoice;
|
|
77
|
+
return outcome;
|
|
78
|
+
} catch {
|
|
79
|
+
return "dismissed";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/pwa/use-install-prompt.ts
|
|
84
|
+
var serverState = { event: null, installed: false };
|
|
85
|
+
function useInstallPrompt() {
|
|
86
|
+
const state2 = useSyncExternalStore2(subscribeInstallState, getInstallState, () => serverState);
|
|
87
|
+
const standalone = useIsStandalone();
|
|
88
|
+
const iosSafari = useSyncExternalStore2(
|
|
89
|
+
() => () => {
|
|
90
|
+
},
|
|
91
|
+
isIosSafari,
|
|
92
|
+
() => false
|
|
93
|
+
);
|
|
94
|
+
useEffect(() => acquireCapture(), []);
|
|
95
|
+
const installed = state2.installed || standalone;
|
|
96
|
+
return {
|
|
97
|
+
canPrompt: state2.event !== null && !installed,
|
|
98
|
+
prompt: promptInstall,
|
|
99
|
+
installed,
|
|
100
|
+
needsIosInstructions: iosSafari && !installed
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export {
|
|
105
|
+
useIsStandalone,
|
|
106
|
+
startInstallPromptCapture,
|
|
107
|
+
useInstallPrompt
|
|
108
|
+
};
|
package/dist/clipboard.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var clipboard_exports = {};
|
|
23
23
|
__export(clipboard_exports, {
|
|
24
24
|
copyText: () => copyText,
|
|
25
|
+
readText: () => readText,
|
|
25
26
|
useCopyFeedback: () => useCopyFeedback
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(clipboard_exports);
|
|
@@ -48,8 +49,10 @@ function execCommandCopy(text) {
|
|
|
48
49
|
textarea.style.top = "-1000px";
|
|
49
50
|
textarea.style.left = "-1000px";
|
|
50
51
|
textarea.style.fontSize = "16px";
|
|
52
|
+
const previouslyFocused = document.activeElement;
|
|
51
53
|
document.body.appendChild(textarea);
|
|
52
54
|
try {
|
|
55
|
+
textarea.focus({ preventScroll: true });
|
|
53
56
|
textarea.select();
|
|
54
57
|
textarea.setSelectionRange(0, text.length);
|
|
55
58
|
return document.execCommand("copy");
|
|
@@ -57,6 +60,9 @@ function execCommandCopy(text) {
|
|
|
57
60
|
return false;
|
|
58
61
|
} finally {
|
|
59
62
|
document.body.removeChild(textarea);
|
|
63
|
+
if (previouslyFocused instanceof HTMLElement && previouslyFocused !== document.body) {
|
|
64
|
+
previouslyFocused.focus({ preventScroll: true });
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
|
|
@@ -82,8 +88,20 @@ function useCopyFeedback({ resetMs = 1500 } = {}) {
|
|
|
82
88
|
);
|
|
83
89
|
return { copy, status };
|
|
84
90
|
}
|
|
91
|
+
|
|
92
|
+
// src/clipboard/read-text.ts
|
|
93
|
+
async function readText() {
|
|
94
|
+
const hasClipboardApi = typeof navigator !== "undefined" && !!navigator.clipboard?.readText && typeof window !== "undefined" && window.isSecureContext;
|
|
95
|
+
if (!hasClipboardApi) return { ok: false, reason: "unavailable" };
|
|
96
|
+
try {
|
|
97
|
+
return { ok: true, text: await navigator.clipboard.readText() };
|
|
98
|
+
} catch {
|
|
99
|
+
return { ok: false, reason: "denied" };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
85
102
|
// Annotate the CommonJS export names for ESM import in node:
|
|
86
103
|
0 && (module.exports = {
|
|
87
104
|
copyText,
|
|
105
|
+
readText,
|
|
88
106
|
useCopyFeedback
|
|
89
107
|
});
|
package/dist/clipboard.d.cts
CHANGED
|
@@ -14,4 +14,13 @@ declare function useCopyFeedback({ resetMs }?: {
|
|
|
14
14
|
status: CopyStatus;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type ReadResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
text: string;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
reason: 'unavailable' | 'denied';
|
|
23
|
+
};
|
|
24
|
+
declare function readText(): Promise<ReadResult>;
|
|
25
|
+
|
|
26
|
+
export { type CopyResult, type CopyStatus, type ReadResult, copyText, readText, useCopyFeedback };
|
package/dist/clipboard.d.ts
CHANGED
|
@@ -14,4 +14,13 @@ declare function useCopyFeedback({ resetMs }?: {
|
|
|
14
14
|
status: CopyStatus;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type ReadResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
text: string;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
reason: 'unavailable' | 'denied';
|
|
23
|
+
};
|
|
24
|
+
declare function readText(): Promise<ReadResult>;
|
|
25
|
+
|
|
26
|
+
export { type CopyResult, type CopyStatus, type ReadResult, copyText, readText, useCopyFeedback };
|
package/dist/clipboard.js
CHANGED
|
@@ -1,62 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return { ok: true };
|
|
10
|
-
} catch {
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
if (execCommandCopy(text)) return { ok: true };
|
|
14
|
-
return { ok: false, reason: hasClipboardApi ? "denied" : "unavailable" };
|
|
15
|
-
}
|
|
16
|
-
function execCommandCopy(text) {
|
|
17
|
-
if (typeof document === "undefined") return false;
|
|
18
|
-
const textarea = document.createElement("textarea");
|
|
19
|
-
textarea.value = text;
|
|
20
|
-
textarea.readOnly = true;
|
|
21
|
-
textarea.style.position = "fixed";
|
|
22
|
-
textarea.style.top = "-1000px";
|
|
23
|
-
textarea.style.left = "-1000px";
|
|
24
|
-
textarea.style.fontSize = "16px";
|
|
25
|
-
document.body.appendChild(textarea);
|
|
26
|
-
try {
|
|
27
|
-
textarea.select();
|
|
28
|
-
textarea.setSelectionRange(0, text.length);
|
|
29
|
-
return document.execCommand("copy");
|
|
30
|
-
} catch {
|
|
31
|
-
return false;
|
|
32
|
-
} finally {
|
|
33
|
-
document.body.removeChild(textarea);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// src/clipboard/use-copy-feedback.ts
|
|
38
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
39
|
-
function useCopyFeedback({ resetMs = 1500 } = {}) {
|
|
40
|
-
const [status, setStatus] = useState("idle");
|
|
41
|
-
const timerRef = useRef(void 0);
|
|
42
|
-
const clearTimer = useCallback(() => {
|
|
43
|
-
if (timerRef.current !== void 0) clearTimeout(timerRef.current);
|
|
44
|
-
timerRef.current = void 0;
|
|
45
|
-
}, []);
|
|
46
|
-
useEffect(() => clearTimer, [clearTimer]);
|
|
47
|
-
const copy = useCallback(
|
|
48
|
-
async (text) => {
|
|
49
|
-
const result = await copyText(text);
|
|
50
|
-
clearTimer();
|
|
51
|
-
setStatus(result.ok ? "copied" : "failed");
|
|
52
|
-
timerRef.current = setTimeout(() => setStatus("idle"), resetMs);
|
|
53
|
-
return result;
|
|
54
|
-
},
|
|
55
|
-
[clearTimer, resetMs]
|
|
56
|
-
);
|
|
57
|
-
return { copy, status };
|
|
58
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
readText,
|
|
4
|
+
useCopyFeedback
|
|
5
|
+
} from "./chunk-EXEJI4FK.js";
|
|
6
|
+
import {
|
|
7
|
+
copyText
|
|
8
|
+
} from "./chunk-FE3BQD2I.js";
|
|
59
9
|
export {
|
|
60
10
|
copyText,
|
|
11
|
+
readText,
|
|
61
12
|
useCopyFeedback
|
|
62
13
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
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/debounce/index.ts
|
|
22
|
+
var debounce_exports = {};
|
|
23
|
+
__export(debounce_exports, {
|
|
24
|
+
createDebouncer: () => createDebouncer,
|
|
25
|
+
useDebouncedCallback: () => useDebouncedCallback,
|
|
26
|
+
useDebouncedValue: () => useDebouncedValue
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(debounce_exports);
|
|
29
|
+
|
|
30
|
+
// src/debounce/debouncer.ts
|
|
31
|
+
function createDebouncer(getFn, getMs) {
|
|
32
|
+
let timer;
|
|
33
|
+
let pending;
|
|
34
|
+
function clear() {
|
|
35
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
36
|
+
timer = void 0;
|
|
37
|
+
pending = void 0;
|
|
38
|
+
}
|
|
39
|
+
function run() {
|
|
40
|
+
const args = pending;
|
|
41
|
+
clear();
|
|
42
|
+
if (args) getFn()(...args);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
call(...args) {
|
|
46
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
47
|
+
pending = args;
|
|
48
|
+
timer = setTimeout(run, getMs());
|
|
49
|
+
},
|
|
50
|
+
cancel: clear,
|
|
51
|
+
flush() {
|
|
52
|
+
if (pending) run();
|
|
53
|
+
},
|
|
54
|
+
isPending: () => pending !== void 0
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/debounce/use-debounced-value.ts
|
|
59
|
+
var import_react = require("react");
|
|
60
|
+
function useDebouncedValue(value, ms) {
|
|
61
|
+
const [debounced, setDebounced] = (0, import_react.useState)(value);
|
|
62
|
+
(0, import_react.useEffect)(() => {
|
|
63
|
+
const timer = setTimeout(() => setDebounced(value), ms);
|
|
64
|
+
return () => clearTimeout(timer);
|
|
65
|
+
}, [value, ms]);
|
|
66
|
+
return debounced;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/debounce/use-debounced-callback.ts
|
|
70
|
+
var import_react2 = require("react");
|
|
71
|
+
function useDebouncedCallback(fn, ms) {
|
|
72
|
+
const fnRef = (0, import_react2.useRef)(fn);
|
|
73
|
+
const msRef = (0, import_react2.useRef)(ms);
|
|
74
|
+
(0, import_react2.useEffect)(() => {
|
|
75
|
+
fnRef.current = fn;
|
|
76
|
+
msRef.current = ms;
|
|
77
|
+
});
|
|
78
|
+
const [debounced] = (0, import_react2.useState)(() => {
|
|
79
|
+
const debouncer = createDebouncer(
|
|
80
|
+
() => fnRef.current,
|
|
81
|
+
() => msRef.current
|
|
82
|
+
);
|
|
83
|
+
return Object.assign((...args) => debouncer.call(...args), {
|
|
84
|
+
cancel: debouncer.cancel,
|
|
85
|
+
flush: debouncer.flush
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
(0, import_react2.useEffect)(() => () => debounced.cancel(), [debounced]);
|
|
89
|
+
return debounced;
|
|
90
|
+
}
|
|
91
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
92
|
+
0 && (module.exports = {
|
|
93
|
+
createDebouncer,
|
|
94
|
+
useDebouncedCallback,
|
|
95
|
+
useDebouncedValue
|
|
96
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface Debouncer<Args extends unknown[]> {
|
|
2
|
+
call(...args: Args): void;
|
|
3
|
+
cancel(): void;
|
|
4
|
+
/** Runs the pending call right now; does nothing when none is pending. */
|
|
5
|
+
flush(): void;
|
|
6
|
+
isPending(): boolean;
|
|
7
|
+
}
|
|
8
|
+
/** `getFn` and `getMs` are read at call time, so the latest values always win. */
|
|
9
|
+
declare function createDebouncer<Args extends unknown[]>(getFn: () => (...args: Args) => void, getMs: () => number): Debouncer<Args>;
|
|
10
|
+
|
|
11
|
+
declare function useDebouncedValue<T>(value: T, ms: number): T;
|
|
12
|
+
|
|
13
|
+
interface DebouncedCallback<Args extends unknown[]> {
|
|
14
|
+
(...args: Args): void;
|
|
15
|
+
cancel(): void;
|
|
16
|
+
flush(): void;
|
|
17
|
+
}
|
|
18
|
+
/** The returned function keeps one identity for the life of the component. */
|
|
19
|
+
declare function useDebouncedCallback<Args extends unknown[]>(fn: (...args: Args) => void, ms: number): DebouncedCallback<Args>;
|
|
20
|
+
|
|
21
|
+
export { type DebouncedCallback, type Debouncer, createDebouncer, useDebouncedCallback, useDebouncedValue };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface Debouncer<Args extends unknown[]> {
|
|
2
|
+
call(...args: Args): void;
|
|
3
|
+
cancel(): void;
|
|
4
|
+
/** Runs the pending call right now; does nothing when none is pending. */
|
|
5
|
+
flush(): void;
|
|
6
|
+
isPending(): boolean;
|
|
7
|
+
}
|
|
8
|
+
/** `getFn` and `getMs` are read at call time, so the latest values always win. */
|
|
9
|
+
declare function createDebouncer<Args extends unknown[]>(getFn: () => (...args: Args) => void, getMs: () => number): Debouncer<Args>;
|
|
10
|
+
|
|
11
|
+
declare function useDebouncedValue<T>(value: T, ms: number): T;
|
|
12
|
+
|
|
13
|
+
interface DebouncedCallback<Args extends unknown[]> {
|
|
14
|
+
(...args: Args): void;
|
|
15
|
+
cancel(): void;
|
|
16
|
+
flush(): void;
|
|
17
|
+
}
|
|
18
|
+
/** The returned function keeps one identity for the life of the component. */
|
|
19
|
+
declare function useDebouncedCallback<Args extends unknown[]>(fn: (...args: Args) => void, ms: number): DebouncedCallback<Args>;
|
|
20
|
+
|
|
21
|
+
export { type DebouncedCallback, type Debouncer, createDebouncer, useDebouncedCallback, useDebouncedValue };
|
package/dist/debounce.js
ADDED
package/dist/drawer-swipe.cjs
CHANGED
|
@@ -23,10 +23,12 @@ var drawer_swipe_exports = {};
|
|
|
23
23
|
__export(drawer_swipe_exports, {
|
|
24
24
|
BACK_ZONE_PX: () => BACK_ZONE_PX,
|
|
25
25
|
CLOSE_DISTANCE_PX: () => CLOSE_DISTANCE_PX,
|
|
26
|
+
DEFAULT_IGNORE_SELECTOR: () => DEFAULT_IGNORE_SELECTOR,
|
|
26
27
|
FORWARD_ZONE_PX: () => FORWARD_ZONE_PX,
|
|
27
28
|
MAX_SWIPE_DURATION_MS: () => MAX_SWIPE_DURATION_MS,
|
|
28
29
|
OPEN_DISTANCE_PX: () => OPEN_DISTANCE_PX,
|
|
29
30
|
VERTICAL_CANCEL_PX: () => VERTICAL_CANCEL_PX,
|
|
31
|
+
isInIgnoredRegion: () => isInIgnoredRegion,
|
|
30
32
|
isInOpenZone: () => isInOpenZone,
|
|
31
33
|
isInsideHorizontalScroller: () => isInsideHorizontalScroller,
|
|
32
34
|
resolveSwipeIntent: () => resolveSwipeIntent,
|
|
@@ -45,7 +47,8 @@ var HORIZONTAL_DOMINANCE = 1.5;
|
|
|
45
47
|
function isInOpenZone(x, viewportWidth) {
|
|
46
48
|
return x > BACK_ZONE_PX && x < viewportWidth - FORWARD_ZONE_PX;
|
|
47
49
|
}
|
|
48
|
-
function resolveSwipeIntent(start, end, drawerOpen, viewportWidth) {
|
|
50
|
+
function resolveSwipeIntent(start, end, drawerOpen, viewportWidth, startedInIgnoredRegion = false) {
|
|
51
|
+
if (startedInIgnoredRegion) return null;
|
|
49
52
|
const dx = end.x - start.x;
|
|
50
53
|
const dy = end.y - start.y;
|
|
51
54
|
if (end.time - start.time > MAX_SWIPE_DURATION_MS) return null;
|
|
@@ -67,6 +70,11 @@ function isInsideHorizontalScroller(target) {
|
|
|
67
70
|
}
|
|
68
71
|
return false;
|
|
69
72
|
}
|
|
73
|
+
var DEFAULT_IGNORE_SELECTOR = "[data-no-swipe]";
|
|
74
|
+
function isInIgnoredRegion(target, selector) {
|
|
75
|
+
if (!selector || !(target instanceof Element)) return false;
|
|
76
|
+
return target.closest(selector) !== null;
|
|
77
|
+
}
|
|
70
78
|
|
|
71
79
|
// src/drawer-swipe/use-drawer-swipe.ts
|
|
72
80
|
var import_react = require("react");
|
|
@@ -78,17 +86,19 @@ function useDrawerSwipe({
|
|
|
78
86
|
onOpen,
|
|
79
87
|
onClose,
|
|
80
88
|
enabled = true,
|
|
81
|
-
maxViewportWidth = 768
|
|
89
|
+
maxViewportWidth = 768,
|
|
90
|
+
ignoreSelector = DEFAULT_IGNORE_SELECTOR
|
|
82
91
|
}) {
|
|
83
92
|
const start = (0, import_react.useRef)(null);
|
|
84
|
-
const handlers = (0, import_react.useRef)({ drawerOpen, onOpen, onClose, maxViewportWidth });
|
|
85
|
-
handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth };
|
|
93
|
+
const handlers = (0, import_react.useRef)({ drawerOpen, onOpen, onClose, maxViewportWidth, ignoreSelector });
|
|
94
|
+
handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth, ignoreSelector };
|
|
86
95
|
(0, import_react.useEffect)(() => {
|
|
87
96
|
if (!enabled) return;
|
|
88
97
|
function handleStart(event) {
|
|
89
98
|
start.current = null;
|
|
90
99
|
if (event.touches.length !== 1) return;
|
|
91
100
|
if (isWideViewport(handlers.current.maxViewportWidth)) return;
|
|
101
|
+
if (isInIgnoredRegion(event.target, handlers.current.ignoreSelector)) return;
|
|
92
102
|
if (!handlers.current.drawerOpen && isInsideHorizontalScroller(event.target)) {
|
|
93
103
|
return;
|
|
94
104
|
}
|
|
@@ -138,10 +148,12 @@ function useDrawerSwipe({
|
|
|
138
148
|
0 && (module.exports = {
|
|
139
149
|
BACK_ZONE_PX,
|
|
140
150
|
CLOSE_DISTANCE_PX,
|
|
151
|
+
DEFAULT_IGNORE_SELECTOR,
|
|
141
152
|
FORWARD_ZONE_PX,
|
|
142
153
|
MAX_SWIPE_DURATION_MS,
|
|
143
154
|
OPEN_DISTANCE_PX,
|
|
144
155
|
VERTICAL_CANCEL_PX,
|
|
156
|
+
isInIgnoredRegion,
|
|
145
157
|
isInOpenZone,
|
|
146
158
|
isInsideHorizontalScroller,
|
|
147
159
|
resolveSwipeIntent,
|
package/dist/drawer-swipe.d.cts
CHANGED
|
@@ -11,8 +11,10 @@ declare const VERTICAL_CANCEL_PX = 40;
|
|
|
11
11
|
declare const MAX_SWIPE_DURATION_MS = 450;
|
|
12
12
|
type SwipeIntent = 'open' | 'close' | null;
|
|
13
13
|
declare function isInOpenZone(x: number, viewportWidth: number): boolean;
|
|
14
|
-
declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number): SwipeIntent;
|
|
14
|
+
declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number, startedInIgnoredRegion?: boolean): SwipeIntent;
|
|
15
15
|
declare function isInsideHorizontalScroller(target: EventTarget | null): boolean;
|
|
16
|
+
declare const DEFAULT_IGNORE_SELECTOR = "[data-no-swipe]";
|
|
17
|
+
declare function isInIgnoredRegion(target: EventTarget | null, selector: string | null): boolean;
|
|
16
18
|
|
|
17
19
|
type UseDrawerSwipeOptions = {
|
|
18
20
|
drawerOpen: boolean;
|
|
@@ -20,7 +22,9 @@ type UseDrawerSwipeOptions = {
|
|
|
20
22
|
onClose: () => void;
|
|
21
23
|
enabled?: boolean;
|
|
22
24
|
maxViewportWidth?: number;
|
|
25
|
+
/** Touches starting inside a match are ignored. Pass null to disable. */
|
|
26
|
+
ignoreSelector?: string | null;
|
|
23
27
|
};
|
|
24
|
-
declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, }: UseDrawerSwipeOptions): void;
|
|
28
|
+
declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, ignoreSelector, }: UseDrawerSwipeOptions): void;
|
|
25
29
|
|
|
26
|
-
export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe };
|
|
30
|
+
export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, DEFAULT_IGNORE_SELECTOR, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInIgnoredRegion, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe };
|
package/dist/drawer-swipe.d.ts
CHANGED
|
@@ -11,8 +11,10 @@ declare const VERTICAL_CANCEL_PX = 40;
|
|
|
11
11
|
declare const MAX_SWIPE_DURATION_MS = 450;
|
|
12
12
|
type SwipeIntent = 'open' | 'close' | null;
|
|
13
13
|
declare function isInOpenZone(x: number, viewportWidth: number): boolean;
|
|
14
|
-
declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number): SwipeIntent;
|
|
14
|
+
declare function resolveSwipeIntent(start: SwipePoint, end: SwipePoint, drawerOpen: boolean, viewportWidth: number, startedInIgnoredRegion?: boolean): SwipeIntent;
|
|
15
15
|
declare function isInsideHorizontalScroller(target: EventTarget | null): boolean;
|
|
16
|
+
declare const DEFAULT_IGNORE_SELECTOR = "[data-no-swipe]";
|
|
17
|
+
declare function isInIgnoredRegion(target: EventTarget | null, selector: string | null): boolean;
|
|
16
18
|
|
|
17
19
|
type UseDrawerSwipeOptions = {
|
|
18
20
|
drawerOpen: boolean;
|
|
@@ -20,7 +22,9 @@ type UseDrawerSwipeOptions = {
|
|
|
20
22
|
onClose: () => void;
|
|
21
23
|
enabled?: boolean;
|
|
22
24
|
maxViewportWidth?: number;
|
|
25
|
+
/** Touches starting inside a match are ignored. Pass null to disable. */
|
|
26
|
+
ignoreSelector?: string | null;
|
|
23
27
|
};
|
|
24
|
-
declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, }: UseDrawerSwipeOptions): void;
|
|
28
|
+
declare function useDrawerSwipe({ drawerOpen, onOpen, onClose, enabled, maxViewportWidth, ignoreSelector, }: UseDrawerSwipeOptions): void;
|
|
25
29
|
|
|
26
|
-
export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe };
|
|
30
|
+
export { BACK_ZONE_PX, CLOSE_DISTANCE_PX, DEFAULT_IGNORE_SELECTOR, FORWARD_ZONE_PX, MAX_SWIPE_DURATION_MS, OPEN_DISTANCE_PX, type SwipeIntent, type SwipePoint, type UseDrawerSwipeOptions, VERTICAL_CANCEL_PX, isInIgnoredRegion, isInOpenZone, isInsideHorizontalScroller, resolveSwipeIntent, useDrawerSwipe };
|
package/dist/drawer-swipe.js
CHANGED
|
@@ -1,112 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const dy = end.y - start.y;
|
|
17
|
-
if (end.time - start.time > MAX_SWIPE_DURATION_MS) return null;
|
|
18
|
-
if (Math.abs(dx) < Math.abs(dy) * HORIZONTAL_DOMINANCE) return null;
|
|
19
|
-
if (drawerOpen) {
|
|
20
|
-
return dx <= -CLOSE_DISTANCE_PX ? "close" : null;
|
|
21
|
-
}
|
|
22
|
-
if (dx < OPEN_DISTANCE_PX) return null;
|
|
23
|
-
return isInOpenZone(start.x, viewportWidth) ? "open" : null;
|
|
24
|
-
}
|
|
25
|
-
function isInsideHorizontalScroller(target) {
|
|
26
|
-
let node = target instanceof Element ? target : null;
|
|
27
|
-
while (node && node !== document.body) {
|
|
28
|
-
const { overflowX } = window.getComputedStyle(node);
|
|
29
|
-
if ((overflowX === "auto" || overflowX === "scroll") && node.scrollWidth > node.clientWidth) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
node = node.parentElement;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// src/drawer-swipe/use-drawer-swipe.ts
|
|
38
|
-
import { useEffect, useRef } from "react";
|
|
39
|
-
function isWideViewport(maxViewportWidth) {
|
|
40
|
-
return window.matchMedia(`(min-width: ${maxViewportWidth}px)`).matches;
|
|
41
|
-
}
|
|
42
|
-
function useDrawerSwipe({
|
|
43
|
-
drawerOpen,
|
|
44
|
-
onOpen,
|
|
45
|
-
onClose,
|
|
46
|
-
enabled = true,
|
|
47
|
-
maxViewportWidth = 768
|
|
48
|
-
}) {
|
|
49
|
-
const start = useRef(null);
|
|
50
|
-
const handlers = useRef({ drawerOpen, onOpen, onClose, maxViewportWidth });
|
|
51
|
-
handlers.current = { drawerOpen, onOpen, onClose, maxViewportWidth };
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (!enabled) return;
|
|
54
|
-
function handleStart(event) {
|
|
55
|
-
start.current = null;
|
|
56
|
-
if (event.touches.length !== 1) return;
|
|
57
|
-
if (isWideViewport(handlers.current.maxViewportWidth)) return;
|
|
58
|
-
if (!handlers.current.drawerOpen && isInsideHorizontalScroller(event.target)) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const touch = event.touches[0];
|
|
62
|
-
if (!touch) return;
|
|
63
|
-
start.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
64
|
-
}
|
|
65
|
-
function handleMove(event) {
|
|
66
|
-
const origin = start.current;
|
|
67
|
-
const touch = event.touches[0];
|
|
68
|
-
if (!origin || !touch) return;
|
|
69
|
-
if (Math.abs(touch.clientY - origin.y) > VERTICAL_CANCEL_PX) {
|
|
70
|
-
start.current = null;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function handleEnd(event) {
|
|
74
|
-
const origin = start.current;
|
|
75
|
-
start.current = null;
|
|
76
|
-
const touch = event.changedTouches[0];
|
|
77
|
-
if (!origin || !touch) return;
|
|
78
|
-
const { drawerOpen: drawerOpen2, onOpen: onOpen2, onClose: onClose2 } = handlers.current;
|
|
79
|
-
const intent = resolveSwipeIntent(
|
|
80
|
-
origin,
|
|
81
|
-
{ x: touch.clientX, y: touch.clientY, time: Date.now() },
|
|
82
|
-
drawerOpen2,
|
|
83
|
-
window.innerWidth
|
|
84
|
-
);
|
|
85
|
-
if (intent === "open") onOpen2();
|
|
86
|
-
if (intent === "close") onClose2();
|
|
87
|
-
}
|
|
88
|
-
function handleCancel() {
|
|
89
|
-
start.current = null;
|
|
90
|
-
}
|
|
91
|
-
document.addEventListener("touchstart", handleStart, { passive: true });
|
|
92
|
-
document.addEventListener("touchmove", handleMove, { passive: true });
|
|
93
|
-
document.addEventListener("touchend", handleEnd, { passive: true });
|
|
94
|
-
document.addEventListener("touchcancel", handleCancel, { passive: true });
|
|
95
|
-
return () => {
|
|
96
|
-
document.removeEventListener("touchstart", handleStart);
|
|
97
|
-
document.removeEventListener("touchmove", handleMove);
|
|
98
|
-
document.removeEventListener("touchend", handleEnd);
|
|
99
|
-
document.removeEventListener("touchcancel", handleCancel);
|
|
100
|
-
};
|
|
101
|
-
}, [enabled]);
|
|
102
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
BACK_ZONE_PX,
|
|
4
|
+
CLOSE_DISTANCE_PX,
|
|
5
|
+
DEFAULT_IGNORE_SELECTOR,
|
|
6
|
+
FORWARD_ZONE_PX,
|
|
7
|
+
MAX_SWIPE_DURATION_MS,
|
|
8
|
+
OPEN_DISTANCE_PX,
|
|
9
|
+
VERTICAL_CANCEL_PX,
|
|
10
|
+
isInIgnoredRegion,
|
|
11
|
+
isInOpenZone,
|
|
12
|
+
isInsideHorizontalScroller,
|
|
13
|
+
resolveSwipeIntent,
|
|
14
|
+
useDrawerSwipe
|
|
15
|
+
} from "./chunk-5XRVPZHD.js";
|
|
103
16
|
export {
|
|
104
17
|
BACK_ZONE_PX,
|
|
105
18
|
CLOSE_DISTANCE_PX,
|
|
19
|
+
DEFAULT_IGNORE_SELECTOR,
|
|
106
20
|
FORWARD_ZONE_PX,
|
|
107
21
|
MAX_SWIPE_DURATION_MS,
|
|
108
22
|
OPEN_DISTANCE_PX,
|
|
109
23
|
VERTICAL_CANCEL_PX,
|
|
24
|
+
isInIgnoredRegion,
|
|
110
25
|
isInOpenZone,
|
|
111
26
|
isInsideHorizontalScroller,
|
|
112
27
|
resolveSwipeIntent,
|
package/dist/escape.cjs
CHANGED
|
@@ -35,6 +35,7 @@ function useEscape(onEscape, active = true) {
|
|
|
35
35
|
(0, import_react.useEffect)(() => {
|
|
36
36
|
if (!active) return;
|
|
37
37
|
function onKeyDown(event) {
|
|
38
|
+
if (event.isComposing || event.keyCode === 229) return;
|
|
38
39
|
if (event.key === "Escape") handlerRef.current();
|
|
39
40
|
}
|
|
40
41
|
document.addEventListener("keydown", onKeyDown);
|