@ttt-productions/mobile-core 0.0.1 → 0.0.2
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/env.d.ts +5 -0
- package/dist/env.d.ts.map +1 -0
- package/{src/env.ts → dist/env.js} +1 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +1 -5
- package/dist/index.js.map +1 -0
- package/dist/ios/useIosSafariFixes.d.ts +8 -0
- package/dist/ios/useIosSafariFixes.d.ts.map +1 -0
- package/{src/ios/useIosSafariFixes.ts → dist/ios/useIosSafariFixes.js} +7 -7
- package/dist/ios/useIosSafariFixes.js.map +1 -0
- package/dist/ios/useNoRubberBand.d.ts +6 -0
- package/dist/ios/useNoRubberBand.d.ts.map +1 -0
- package/dist/ios/useNoRubberBand.js +19 -0
- package/dist/ios/useNoRubberBand.js.map +1 -0
- package/dist/keyboard/KeyboardAvoidingView.d.ts +18 -0
- package/dist/keyboard/KeyboardAvoidingView.d.ts.map +1 -0
- package/dist/keyboard/KeyboardAvoidingView.js +11 -0
- package/dist/keyboard/KeyboardAvoidingView.js.map +1 -0
- package/dist/keyboard/focusOrder.d.ts +2 -0
- package/dist/keyboard/focusOrder.d.ts.map +1 -0
- package/dist/keyboard/focusOrder.js +18 -0
- package/dist/keyboard/focusOrder.js.map +1 -0
- package/dist/keyboard/useInputNavigation.d.ts +17 -0
- package/dist/keyboard/useInputNavigation.d.ts.map +1 -0
- package/dist/keyboard/useInputNavigation.js +35 -0
- package/dist/keyboard/useInputNavigation.js.map +1 -0
- package/dist/keyboard/useKeepFocusedInputVisible.d.ts +9 -0
- package/dist/keyboard/useKeepFocusedInputVisible.d.ts.map +1 -0
- package/dist/keyboard/useKeepFocusedInputVisible.js +36 -0
- package/dist/keyboard/useKeepFocusedInputVisible.js.map +1 -0
- package/dist/keyboard/useKeyboard.d.ts +8 -0
- package/dist/keyboard/useKeyboard.d.ts.map +1 -0
- package/dist/keyboard/useKeyboard.js +66 -0
- package/dist/keyboard/useKeyboard.js.map +1 -0
- package/dist/safe-area/SafeArea.d.ts +10 -0
- package/dist/safe-area/SafeArea.d.ts.map +1 -0
- package/dist/safe-area/SafeArea.js +11 -0
- package/dist/safe-area/SafeArea.js.map +1 -0
- package/dist/safe-area/useSafeAreaInsets.d.ts +7 -0
- package/dist/safe-area/useSafeAreaInsets.d.ts.map +1 -0
- package/dist/safe-area/useSafeAreaInsets.js +38 -0
- package/dist/safe-area/useSafeAreaInsets.js.map +1 -0
- package/dist/scroll/useScrollLock.d.ts +7 -0
- package/dist/scroll/useScrollLock.d.ts.map +1 -0
- package/dist/scroll/useScrollLock.js +35 -0
- package/dist/scroll/useScrollLock.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/viewport/useViewportHeightVars.d.ts +10 -0
- package/dist/viewport/useViewportHeightVars.d.ts.map +1 -0
- package/dist/viewport/useViewportHeightVars.js +30 -0
- package/dist/viewport/useViewportHeightVars.js.map +1 -0
- package/dist/viewport/useVisualViewport.d.ts +11 -0
- package/dist/viewport/useVisualViewport.d.ts.map +1 -0
- package/dist/viewport/useVisualViewport.js +36 -0
- package/dist/viewport/useVisualViewport.js.map +1 -0
- package/package.json +41 -18
- package/src/ios/useNoRubberBand.ts +0 -20
- package/src/keyboard/KeyboardAvoidingView.tsx +0 -24
- package/src/keyboard/focusOrder.ts +0 -20
- package/src/keyboard/useInputNavigation.ts +0 -44
- package/src/keyboard/useKeepFocusedInputVisible.ts +0 -41
- package/src/keyboard/useKeyboard.ts +0 -74
- package/src/safe-area/SafeArea.tsx +0 -23
- package/src/safe-area/useSafeAreaInsets.ts +0 -44
- package/src/scroll/useScrollLock.ts +0 -37
- package/src/types.ts +0 -8
- package/src/viewport/useViewportHeightVars.ts +0 -32
- package/src/viewport/useVisualViewport.ts +0 -42
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,SAAmE,CAAC;AAC1F,eAAO,MAAM,KAAK,SAA0D,CAAC;AAC7E,eAAO,MAAM,QAAQ,SAA0E,CAAC;AAChG,eAAO,MAAM,iBAAiB,SAAuC,CAAC"}
|
|
@@ -2,3 +2,4 @@ export const isBrowser = typeof window !== "undefined" && typeof document !== "u
|
|
|
2
2
|
export const isIOS = isBrowser && /iP(ad|hone|od)/.test(navigator.userAgent);
|
|
3
3
|
export const isSafari = isBrowser && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
4
4
|
export const hasVisualViewport = isBrowser && !!window.visualViewport;
|
|
5
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,CAAC;AAC1F,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAC7E,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,IAAI,gCAAgC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAChG,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./env";
|
|
3
|
+
export * from "./viewport/useVisualViewport";
|
|
4
|
+
export * from "./viewport/useViewportHeightVars";
|
|
5
|
+
export * from "./keyboard/useKeyboard";
|
|
6
|
+
export * from "./keyboard/useKeepFocusedInputVisible";
|
|
7
|
+
export * from "./keyboard/useInputNavigation";
|
|
8
|
+
export * from "./keyboard/KeyboardAvoidingView";
|
|
9
|
+
export * from "./safe-area/useSafeAreaInsets";
|
|
10
|
+
export * from "./safe-area/SafeArea";
|
|
11
|
+
export * from "./scroll/useScrollLock";
|
|
12
|
+
export * from "./ios/useIosSafariFixes";
|
|
13
|
+
export * from "./ios/useNoRubberBand";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AAEtB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AAEjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AAErC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
export * from "./types";
|
|
2
2
|
export * from "./env";
|
|
3
|
-
|
|
4
3
|
export * from "./viewport/useVisualViewport";
|
|
5
4
|
export * from "./viewport/useViewportHeightVars";
|
|
6
|
-
|
|
7
5
|
export * from "./keyboard/useKeyboard";
|
|
8
6
|
export * from "./keyboard/useKeepFocusedInputVisible";
|
|
9
7
|
export * from "./keyboard/useInputNavigation";
|
|
10
8
|
export * from "./keyboard/KeyboardAvoidingView";
|
|
11
|
-
|
|
12
9
|
export * from "./safe-area/useSafeAreaInsets";
|
|
13
10
|
export * from "./safe-area/SafeArea";
|
|
14
|
-
|
|
15
11
|
export * from "./scroll/useScrollLock";
|
|
16
|
-
|
|
17
12
|
export * from "./ios/useIosSafariFixes";
|
|
18
13
|
export * from "./ios/useNoRubberBand";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AAEtB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AAEjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAEhD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AAErC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small, safe iOS Safari fixes:
|
|
3
|
+
* - disables double-tap-to-zoom delays for buttons (via touch-action)
|
|
4
|
+
* - ensures inputs don't auto-zoom by recommending 16px font (cannot enforce here)
|
|
5
|
+
* - adds -webkit-overflow-scrolling: touch helper class hook (optional)
|
|
6
|
+
*/
|
|
7
|
+
export declare function useIosSafariFixes(): void;
|
|
8
|
+
//# sourceMappingURL=useIosSafariFixes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIosSafariFixes.d.ts","sourceRoot":"","sources":["../../src/ios/useIosSafariFixes.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,iBAAiB,SAOhC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
2
|
import { isBrowser, isIOS, isSafari } from "../env";
|
|
3
|
-
|
|
4
3
|
/**
|
|
5
4
|
* Small, safe iOS Safari fixes:
|
|
6
5
|
* - disables double-tap-to-zoom delays for buttons (via touch-action)
|
|
@@ -8,10 +7,11 @@ import { isBrowser, isIOS, isSafari } from "../env";
|
|
|
8
7
|
* - adds -webkit-overflow-scrolling: touch helper class hook (optional)
|
|
9
8
|
*/
|
|
10
9
|
export function useIosSafariFixes() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!isBrowser || !isIOS || !isSafari)
|
|
12
|
+
return;
|
|
13
|
+
document.documentElement.classList.add("ttt-ios-safari");
|
|
14
|
+
return () => document.documentElement.classList.remove("ttt-ios-safari");
|
|
15
|
+
}, []);
|
|
17
16
|
}
|
|
17
|
+
//# sourceMappingURL=useIosSafariFixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIosSafariFixes.js","sourceRoot":"","sources":["../../src/ios/useIosSafariFixes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE9C,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACzD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC3E,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNoRubberBand.d.ts","sourceRoot":"","sources":["../../src/ios/useNoRubberBand.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,QAY/C"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { isBrowser, isIOS } from "../env";
|
|
3
|
+
/**
|
|
4
|
+
* Prevents iOS rubber-band scroll on the document by limiting overscroll chaining.
|
|
5
|
+
* Use sparingly (e.g., full-screen experiences).
|
|
6
|
+
*/
|
|
7
|
+
export function useNoRubberBand(enabled) {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!isBrowser || !isIOS || !enabled)
|
|
10
|
+
return;
|
|
11
|
+
const el = document.documentElement;
|
|
12
|
+
const prev = el.style.overscrollBehaviorY;
|
|
13
|
+
el.style.overscrollBehaviorY = "none";
|
|
14
|
+
return () => {
|
|
15
|
+
el.style.overscrollBehaviorY = prev;
|
|
16
|
+
};
|
|
17
|
+
}, [enabled]);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=useNoRubberBand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNoRubberBand.js","sourceRoot":"","sources":["../../src/ios/useNoRubberBand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE1C;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;YAAE,OAAO;QAE7C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QACpC,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,mBAA0B,CAAC;QAChD,EAAE,CAAC,KAAa,CAAC,mBAAmB,GAAG,MAAM,CAAC;QAE/C,OAAO,GAAG,EAAE;YACT,EAAE,CAAC,KAAa,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAC/C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
type Props = React.HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
/**
|
|
4
|
+
* If true, adds padding-bottom equal to keyboard height while open.
|
|
5
|
+
* Good default for forms.
|
|
6
|
+
*/
|
|
7
|
+
padding?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Adds extra px to bottom padding.
|
|
10
|
+
*/
|
|
11
|
+
offset?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Desktop-safe: does nothing when keyboard is not detected.
|
|
15
|
+
*/
|
|
16
|
+
export declare function KeyboardAvoidingView({ padding, offset, style, ...rest }: Props): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=KeyboardAvoidingView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyboardAvoidingView.d.ts","sourceRoot":"","sources":["../../src/keyboard/KeyboardAvoidingView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,KAAK,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAClD;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,OAAc,EAAE,MAAU,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK,2CAKzF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useKeyboard } from "./useKeyboard";
|
|
3
|
+
/**
|
|
4
|
+
* Desktop-safe: does nothing when keyboard is not detected.
|
|
5
|
+
*/
|
|
6
|
+
export function KeyboardAvoidingView({ padding = true, offset = 0, style, ...rest }) {
|
|
7
|
+
const k = useKeyboard();
|
|
8
|
+
const pb = padding && k.isOpen ? k.height + offset : 0;
|
|
9
|
+
return _jsx("div", { ...rest, style: { ...style, paddingBottom: style?.paddingBottom ?? pb } });
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=KeyboardAvoidingView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyboardAvoidingView.js","sourceRoot":"","sources":["../../src/keyboard/KeyboardAvoidingView.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAc5C;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,EAAS;IACxF,MAAM,CAAC,GAAG,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,GAAG,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvD,OAAO,iBAAS,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,aAAa,EAAG,KAAa,EAAE,aAAa,IAAI,EAAE,EAAE,GAAI,CAAC;AACpG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focusOrder.d.ts","sourceRoot":"","sources":["../../src/keyboard/focusOrder.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,WAAW,GAAG,QAAmB,iBAmBzE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function getFocusableInputs(root = document) {
|
|
2
|
+
const el = root instanceof Document ? root : root;
|
|
3
|
+
const list = Array.from(el.querySelectorAll('input, textarea, select, [contenteditable="true"], [data-ttt-input]')).filter((n) => !n.hasAttribute("disabled") && n.tabIndex !== -1);
|
|
4
|
+
// DOM order is usually correct; allow explicit override
|
|
5
|
+
list.sort((a, b) => {
|
|
6
|
+
const ao = Number(a.getAttribute("data-input-order") ?? "0");
|
|
7
|
+
const bo = Number(b.getAttribute("data-input-order") ?? "0");
|
|
8
|
+
if (ao && bo)
|
|
9
|
+
return ao - bo;
|
|
10
|
+
if (ao)
|
|
11
|
+
return -1;
|
|
12
|
+
if (bo)
|
|
13
|
+
return 1;
|
|
14
|
+
return 0;
|
|
15
|
+
});
|
|
16
|
+
return list;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=focusOrder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focusOrder.js","sourceRoot":"","sources":["../../src/keyboard/focusOrder.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,OAA+B,QAAQ;IACxE,MAAM,EAAE,GAAG,IAAI,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACrB,EAAE,CAAC,gBAAgB,CACjB,qEAAqE,CACtE,CACF,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;IAElE,wDAAwD;IACxD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,CAAC;QAC7D,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,CAAC;QAC7D,IAAI,EAAE,IAAI,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAC7B,IAAI,EAAE;YAAE,OAAO,CAAC,CAAC,CAAC;QAClB,IAAI,EAAE;YAAE,OAAO,CAAC,CAAC;QACjB,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type Options = {
|
|
2
|
+
root?: HTMLElement | null;
|
|
3
|
+
onDone?: () => void;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Attach to inputs:
|
|
7
|
+
* onKeyDown={nav.onKeyDown}
|
|
8
|
+
* onSubmitEditing={nav.onSubmitEditing} (optional)
|
|
9
|
+
*
|
|
10
|
+
* Also supports explicit ordering via data-input-order.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useInputNavigation(opts?: Options): {
|
|
13
|
+
focusNext: () => void;
|
|
14
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=useInputNavigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInputNavigation.d.ts","sourceRoot":"","sources":["../../src/keyboard/useInputNavigation.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG;IACb,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,OAAO;;mBAezC,KAAK,CAAC,aAAa;EAa1B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { getFocusableInputs } from "./focusOrder";
|
|
3
|
+
/**
|
|
4
|
+
* Attach to inputs:
|
|
5
|
+
* onKeyDown={nav.onKeyDown}
|
|
6
|
+
* onSubmitEditing={nav.onSubmitEditing} (optional)
|
|
7
|
+
*
|
|
8
|
+
* Also supports explicit ordering via data-input-order.
|
|
9
|
+
*/
|
|
10
|
+
export function useInputNavigation(opts) {
|
|
11
|
+
const root = opts?.root ?? null;
|
|
12
|
+
const focusNext = useCallback(() => {
|
|
13
|
+
const scope = root ?? document;
|
|
14
|
+
const inputs = getFocusableInputs(scope);
|
|
15
|
+
const active = document.activeElement;
|
|
16
|
+
const idx = active ? inputs.indexOf(active) : -1;
|
|
17
|
+
const next = inputs[idx + 1];
|
|
18
|
+
if (next)
|
|
19
|
+
next.focus();
|
|
20
|
+
else
|
|
21
|
+
opts?.onDone?.();
|
|
22
|
+
}, [root, opts]);
|
|
23
|
+
const onKeyDown = useCallback((e) => {
|
|
24
|
+
if (e.key === "Enter") {
|
|
25
|
+
// allow textarea newlines
|
|
26
|
+
const el = e.currentTarget;
|
|
27
|
+
if (el.tagName.toLowerCase() === "textarea")
|
|
28
|
+
return;
|
|
29
|
+
e.preventDefault();
|
|
30
|
+
focusNext();
|
|
31
|
+
}
|
|
32
|
+
}, [focusNext]);
|
|
33
|
+
return { focusNext, onKeyDown };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=useInputNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInputNavigation.js","sourceRoot":"","sources":["../../src/keyboard/useInputNavigation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOlD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;IAEhC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,MAAM,KAAK,GAAG,IAAI,IAAI,QAAQ,CAAC;QAC/B,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAY,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAmC,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAE7B,IAAI,IAAI;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;;YAClB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACxB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAEjB,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,CAAsB,EAAE,EAAE;QACzB,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACtB,0BAA0B;YAC1B,MAAM,EAAE,GAAG,CAAC,CAAC,aAA4B,CAAC;YAC1C,IAAI,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,UAAU;gBAAE,OAAO;YACpD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,SAAS,EAAE,CAAC;QACd,CAAC;IACH,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When keyboard opens, ensure focused element is visible within visual viewport.
|
|
3
|
+
* - iOS Safari often hides the caret behind the keyboard.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useKeepFocusedInputVisible(opts?: {
|
|
6
|
+
extraOffset?: number;
|
|
7
|
+
scrollBehavior?: ScrollBehavior;
|
|
8
|
+
}): void;
|
|
9
|
+
//# sourceMappingURL=useKeepFocusedInputVisible.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeepFocusedInputVisible.d.ts","sourceRoot":"","sources":["../../src/keyboard/useKeepFocusedInputVisible.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,QA6BA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { isBrowser } from "../env";
|
|
3
|
+
import { useKeyboard } from "./useKeyboard";
|
|
4
|
+
/**
|
|
5
|
+
* When keyboard opens, ensure focused element is visible within visual viewport.
|
|
6
|
+
* - iOS Safari often hides the caret behind the keyboard.
|
|
7
|
+
*/
|
|
8
|
+
export function useKeepFocusedInputVisible(opts) {
|
|
9
|
+
const { isOpen } = useKeyboard();
|
|
10
|
+
const extraOffset = opts?.extraOffset ?? 12;
|
|
11
|
+
const behavior = opts?.scrollBehavior ?? "smooth";
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!isBrowser)
|
|
14
|
+
return;
|
|
15
|
+
if (!isOpen)
|
|
16
|
+
return;
|
|
17
|
+
const el = document.activeElement;
|
|
18
|
+
if (!el)
|
|
19
|
+
return;
|
|
20
|
+
// only inputs-ish
|
|
21
|
+
const tag = el.tagName.toLowerCase();
|
|
22
|
+
const isInput = tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable || el.hasAttribute("data-ttt-input");
|
|
23
|
+
if (!isInput)
|
|
24
|
+
return;
|
|
25
|
+
const vv = window.visualViewport;
|
|
26
|
+
const vvH = vv?.height ?? window.innerHeight;
|
|
27
|
+
const rect = el.getBoundingClientRect();
|
|
28
|
+
const bottom = rect.bottom;
|
|
29
|
+
const limit = vvH - extraOffset;
|
|
30
|
+
if (bottom > limit) {
|
|
31
|
+
const delta = bottom - limit;
|
|
32
|
+
window.scrollBy({ top: delta, behavior });
|
|
33
|
+
}
|
|
34
|
+
}, [isOpen, extraOffset, behavior]);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=useKeepFocusedInputVisible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeepFocusedInputVisible.js","sourceRoot":"","sources":["../../src/keyboard/useKeepFocusedInputVisible.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAG1C;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,EAAE,cAAc,IAAI,QAAQ,CAAC;IAElD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAmC,CAAC;QACxD,IAAI,CAAC,EAAE;YAAE,OAAO;QAEhB,kBAAkB;QAClB,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,OAAO,GACX,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC,iBAAiB,IAAI,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;QACzH,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC;QACjC,MAAM,GAAG,GAAG,EAAE,EAAE,MAAM,IAAI,MAAM,CAAC,WAAW,CAAC;QAC7C,MAAM,IAAI,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,GAAG,WAAW,CAAC;QAEhC,IAAI,MAAM,GAAG,KAAK,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;YAC7B,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { KeyboardState } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Best effort keyboard detection:
|
|
4
|
+
* - iOS Safari: visualViewport.height shrinks when keyboard shows
|
|
5
|
+
* - fallback: focusin/focusout heuristics + innerHeight snapshots
|
|
6
|
+
*/
|
|
7
|
+
export declare function useKeyboard(): KeyboardState;
|
|
8
|
+
//# sourceMappingURL=useKeyboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyboard.d.ts","sourceRoot":"","sources":["../../src/keyboard/useKeyboard.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,aAAa,CAgE3C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { hasVisualViewport, isBrowser } from "../env";
|
|
3
|
+
/**
|
|
4
|
+
* Best effort keyboard detection:
|
|
5
|
+
* - iOS Safari: visualViewport.height shrinks when keyboard shows
|
|
6
|
+
* - fallback: focusin/focusout heuristics + innerHeight snapshots
|
|
7
|
+
*/
|
|
8
|
+
export function useKeyboard() {
|
|
9
|
+
const [baseline, setBaseline] = useState(() => (isBrowser ? window.innerHeight : 0));
|
|
10
|
+
const [height, setHeight] = useState(0);
|
|
11
|
+
const [open, setOpen] = useState(false);
|
|
12
|
+
const [source, setSource] = useState("fallback");
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!isBrowser)
|
|
15
|
+
return;
|
|
16
|
+
const setBaseIfNeeded = () => {
|
|
17
|
+
// update baseline when keyboard likely closed
|
|
18
|
+
const vvH = window.visualViewport?.height ?? window.innerHeight;
|
|
19
|
+
const inner = window.innerHeight;
|
|
20
|
+
const candidate = Math.max(vvH, inner);
|
|
21
|
+
setBaseline((b) => (Math.abs(candidate - b) > 40 ? candidate : b));
|
|
22
|
+
};
|
|
23
|
+
const onVV = () => {
|
|
24
|
+
const vvH = window.visualViewport?.height ?? window.innerHeight;
|
|
25
|
+
const delta = Math.max(0, Math.round(baseline - vvH));
|
|
26
|
+
const isOpen = delta > 80; // threshold
|
|
27
|
+
setSource("visualViewport");
|
|
28
|
+
setHeight(isOpen ? delta : 0);
|
|
29
|
+
setOpen(isOpen);
|
|
30
|
+
if (!isOpen)
|
|
31
|
+
setBaseIfNeeded();
|
|
32
|
+
};
|
|
33
|
+
const onFocusIn = () => {
|
|
34
|
+
// baseline snapshot on focus to reduce false positives
|
|
35
|
+
setBaseline((b) => Math.max(b, window.innerHeight));
|
|
36
|
+
};
|
|
37
|
+
const onFocusOut = () => {
|
|
38
|
+
// allow baseline update shortly after blur
|
|
39
|
+
setTimeout(setBaseIfNeeded, 50);
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
setOpen(false);
|
|
42
|
+
setHeight(0);
|
|
43
|
+
}, 250);
|
|
44
|
+
};
|
|
45
|
+
if (hasVisualViewport) {
|
|
46
|
+
window.visualViewport.addEventListener("resize", onVV, { passive: true });
|
|
47
|
+
window.visualViewport.addEventListener("scroll", onVV, { passive: true });
|
|
48
|
+
onVV();
|
|
49
|
+
}
|
|
50
|
+
window.addEventListener("focusin", onFocusIn, { passive: true });
|
|
51
|
+
window.addEventListener("focusout", onFocusOut, { passive: true });
|
|
52
|
+
window.addEventListener("orientationchange", setBaseIfNeeded, { passive: true });
|
|
53
|
+
setBaseIfNeeded();
|
|
54
|
+
return () => {
|
|
55
|
+
if (hasVisualViewport) {
|
|
56
|
+
window.visualViewport.removeEventListener("resize", onVV);
|
|
57
|
+
window.visualViewport.removeEventListener("scroll", onVV);
|
|
58
|
+
}
|
|
59
|
+
window.removeEventListener("focusin", onFocusIn);
|
|
60
|
+
window.removeEventListener("focusout", onFocusOut);
|
|
61
|
+
window.removeEventListener("orientationchange", setBaseIfNeeded);
|
|
62
|
+
};
|
|
63
|
+
}, [baseline]);
|
|
64
|
+
return useMemo(() => ({ isOpen: open, height, source }), [open, height, source]);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=useKeyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useKeyboard.js","sourceRoot":"","sources":["../../src/keyboard/useKeyboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
type Props = React.HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
top?: boolean;
|
|
4
|
+
bottom?: boolean;
|
|
5
|
+
left?: boolean;
|
|
6
|
+
right?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function SafeArea({ top, bottom, left, right, style, ...rest }: Props): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=SafeArea.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeArea.d.ts","sourceRoot":"","sources":["../../src/safe-area/SafeArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,KAAK,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAClD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,KAAK,2CAa3E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function SafeArea({ top, bottom, left, right, style, ...rest }) {
|
|
3
|
+
return (_jsx("div", { ...rest, style: {
|
|
4
|
+
...style,
|
|
5
|
+
paddingTop: top ? "env(safe-area-inset-top)" : style?.paddingTop,
|
|
6
|
+
paddingBottom: bottom ? "env(safe-area-inset-bottom)" : style?.paddingBottom,
|
|
7
|
+
paddingLeft: left ? "env(safe-area-inset-left)" : style?.paddingLeft,
|
|
8
|
+
paddingRight: right ? "env(safe-area-inset-right)" : style?.paddingRight,
|
|
9
|
+
} }));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=SafeArea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeArea.js","sourceRoot":"","sources":["../../src/safe-area/SafeArea.tsx"],"names":[],"mappings":";AASA,MAAM,UAAU,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAS;IAC1E,OAAO,CACL,iBACM,IAAI,EACR,KAAK,EAAE;YACL,GAAG,KAAK;YACR,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAE,KAAa,EAAE,UAAU;YACzE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAE,KAAa,EAAE,aAAa;YACrF,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAE,KAAa,EAAE,WAAW;YAC7E,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAE,KAAa,EAAE,YAAY;SAClF,GACD,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Insets } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Uses CSS env(safe-area-inset-*) by writing them to CSS vars and reading computed values.
|
|
4
|
+
* Works on iOS Safari; harmless elsewhere.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useSafeAreaInsets(): Insets;
|
|
7
|
+
//# sourceMappingURL=useSafeAreaInsets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSafeAreaInsets.d.ts","sourceRoot":"","sources":["../../src/safe-area/useSafeAreaInsets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAmC1C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { isBrowser } from "../env";
|
|
3
|
+
/**
|
|
4
|
+
* Uses CSS env(safe-area-inset-*) by writing them to CSS vars and reading computed values.
|
|
5
|
+
* Works on iOS Safari; harmless elsewhere.
|
|
6
|
+
*/
|
|
7
|
+
export function useSafeAreaInsets() {
|
|
8
|
+
const [insets, setInsets] = useState({ top: 0, right: 0, bottom: 0, left: 0 });
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!isBrowser)
|
|
11
|
+
return;
|
|
12
|
+
const el = document.documentElement;
|
|
13
|
+
// set vars once
|
|
14
|
+
el.style.setProperty("--ttt-sai-top", "env(safe-area-inset-top)");
|
|
15
|
+
el.style.setProperty("--ttt-sai-right", "env(safe-area-inset-right)");
|
|
16
|
+
el.style.setProperty("--ttt-sai-bottom", "env(safe-area-inset-bottom)");
|
|
17
|
+
el.style.setProperty("--ttt-sai-left", "env(safe-area-inset-left)");
|
|
18
|
+
const read = () => {
|
|
19
|
+
const cs = getComputedStyle(el);
|
|
20
|
+
const px = (v) => Math.max(0, Math.round(parseFloat(v || "0")));
|
|
21
|
+
setInsets({
|
|
22
|
+
top: px(cs.getPropertyValue("--ttt-sai-top")),
|
|
23
|
+
right: px(cs.getPropertyValue("--ttt-sai-right")),
|
|
24
|
+
bottom: px(cs.getPropertyValue("--ttt-sai-bottom")),
|
|
25
|
+
left: px(cs.getPropertyValue("--ttt-sai-left")),
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
read();
|
|
29
|
+
window.addEventListener("resize", read, { passive: true });
|
|
30
|
+
window.addEventListener("orientationchange", read, { passive: true });
|
|
31
|
+
return () => {
|
|
32
|
+
window.removeEventListener("resize", read);
|
|
33
|
+
window.removeEventListener("orientationchange", read);
|
|
34
|
+
};
|
|
35
|
+
}, []);
|
|
36
|
+
return insets;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=useSafeAreaInsets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSafeAreaInsets.js","sourceRoot":"","sources":["../../src/safe-area/useSafeAreaInsets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnC;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAS,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAEvF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAEpC,gBAAgB;QAChB,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC;QAClE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;QACtE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,kBAAkB,EAAE,6BAA6B,CAAC,CAAC;QACxE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,CAAC;QAEpE,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,MAAM,EAAE,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAChC,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;YACxE,SAAS,CAAC;gBACR,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;gBAC7C,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;gBACjD,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;gBACnD,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;aAChD,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,EAAE,CAAC;QACP,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC3C,MAAM,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollLock.d.ts","sourceRoot":"","sources":["../../src/scroll/useScrollLock.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,QA4B5C"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { isBrowser } from "../env";
|
|
3
|
+
/**
|
|
4
|
+
* Locks body scroll (mobile sheet/modal fix).
|
|
5
|
+
* - preserves current scroll position
|
|
6
|
+
* - iOS safe enough for common cases
|
|
7
|
+
*/
|
|
8
|
+
export function useScrollLock(locked) {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!isBrowser)
|
|
11
|
+
return;
|
|
12
|
+
if (!locked)
|
|
13
|
+
return;
|
|
14
|
+
const { body } = document;
|
|
15
|
+
const scrollY = window.scrollY;
|
|
16
|
+
const prev = {
|
|
17
|
+
position: body.style.position,
|
|
18
|
+
top: body.style.top,
|
|
19
|
+
width: body.style.width,
|
|
20
|
+
overflowY: body.style.overflowY,
|
|
21
|
+
};
|
|
22
|
+
body.style.position = "fixed";
|
|
23
|
+
body.style.top = `-${scrollY}px`;
|
|
24
|
+
body.style.width = "100%";
|
|
25
|
+
body.style.overflowY = "scroll";
|
|
26
|
+
return () => {
|
|
27
|
+
body.style.position = prev.position;
|
|
28
|
+
body.style.top = prev.top;
|
|
29
|
+
body.style.width = prev.width;
|
|
30
|
+
body.style.overflowY = prev.overflowY;
|
|
31
|
+
window.scrollTo(0, scrollY);
|
|
32
|
+
};
|
|
33
|
+
}, [locked]);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=useScrollLock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScrollLock.js","sourceRoot":"","sources":["../../src/scroll/useScrollLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE/B,MAAM,IAAI,GAAG;YACX,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC7B,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;YACvB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;SAChC,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,OAAO,IAAI,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,QAAQ,CAAC;QAEhC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YACpC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YAC1B,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACf,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAAC;CACvC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets:
|
|
3
|
+
* --ttt-vh: 1% of *layout* viewport height (window.innerHeight)
|
|
4
|
+
* --ttt-dvh: 1% of *visual* viewport height (visualViewport.height when available)
|
|
5
|
+
*
|
|
6
|
+
* Use in CSS:
|
|
7
|
+
* height: calc(var(--ttt-dvh, var(--ttt-vh, 1vh)) * 100);
|
|
8
|
+
*/
|
|
9
|
+
export declare function useViewportHeightVars(): void;
|
|
10
|
+
//# sourceMappingURL=useViewportHeightVars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewportHeightVars.d.ts","sourceRoot":"","sources":["../../src/viewport/useViewportHeightVars.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,SAoBpC"}
|