@livx.cc/native-kit 0.19.0 → 0.21.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/package.json +1 -1
- package/src/core/NativeKit.ts +2 -0
- package/src/core/web-adapter.ts +25 -0
- package/src/index.ts +1 -0
- package/src/modules/contacts.ts +11 -0
- package/src/modules/keyboard.ts +44 -0
package/package.json
CHANGED
package/src/core/NativeKit.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { DeviceModule } from '../modules/device';
|
|
|
12
12
|
import { GeoModule } from '../modules/geo';
|
|
13
13
|
import { HapticsModule } from '../modules/haptics';
|
|
14
14
|
import { HealthModule } from '../modules/health';
|
|
15
|
+
import { KeyboardModule } from '../modules/keyboard';
|
|
15
16
|
import { LifecycleModule } from '../modules/lifecycle';
|
|
16
17
|
import { MediaModule } from '../modules/media';
|
|
17
18
|
import { MotionModule } from '../modules/motion';
|
|
@@ -70,6 +71,7 @@ export class NativeKit {
|
|
|
70
71
|
public readonly haptics = new HapticsModule(this);
|
|
71
72
|
public readonly share = new ShareModule(this);
|
|
72
73
|
public readonly screen = new ScreenModule(this);
|
|
74
|
+
public readonly keyboard = new KeyboardModule(this);
|
|
73
75
|
public readonly storage = new StorageModule(this);
|
|
74
76
|
public readonly toast = new ToastModule(this);
|
|
75
77
|
public readonly ui = new UiModule(this);
|
package/src/core/web-adapter.ts
CHANGED
|
@@ -54,6 +54,7 @@ export class WebAdapter implements NativeKitAdapter {
|
|
|
54
54
|
photos: 'web',
|
|
55
55
|
network: 'web',
|
|
56
56
|
screen: 'wakeLock' in n ? 'web' : 'none',
|
|
57
|
+
keyboard: (window as any).visualViewport ? 'web' : 'none', // VisualViewport resize ≈ keyboard show/hide
|
|
57
58
|
dialogs: 'web',
|
|
58
59
|
reviews: 'none',
|
|
59
60
|
themeColor: 'web', // the browser honors <meta name="theme-color"> itself
|
|
@@ -180,6 +181,11 @@ export class WebAdapter implements NativeKitAdapter {
|
|
|
180
181
|
case 'screen.orientation.current':
|
|
181
182
|
return (((screen as any)?.orientation?.type ?? '').startsWith('landscape') ? 'landscape' : 'portrait') as T;
|
|
182
183
|
|
|
184
|
+
case 'keyboard.hide':
|
|
185
|
+
// No programmatic IME on web — blurring the focused field dismisses it.
|
|
186
|
+
(document.activeElement as HTMLElement | null)?.blur?.();
|
|
187
|
+
return undefined as T;
|
|
188
|
+
|
|
183
189
|
case 'reviews.requestReview':
|
|
184
190
|
throw new KitError('UNSUPPORTED', 'No in-app review prompt on web');
|
|
185
191
|
|
|
@@ -297,6 +303,9 @@ export class WebAdapter implements NativeKitAdapter {
|
|
|
297
303
|
return { picked: true, name: c.name?.[0], phones: c.tel, emails: c.email } as T;
|
|
298
304
|
}
|
|
299
305
|
|
|
306
|
+
case 'contacts.getAll':
|
|
307
|
+
throw new KitError('UNSUPPORTED', 'No bulk contacts read on web — use contacts.pick');
|
|
308
|
+
|
|
300
309
|
case 'calendar.createEvent':
|
|
301
310
|
throw new KitError('UNSUPPORTED', 'No calendar access on web');
|
|
302
311
|
|
|
@@ -368,6 +377,22 @@ export class WebAdapter implements NativeKitAdapter {
|
|
|
368
377
|
so.addEventListener('change', fire);
|
|
369
378
|
return () => so.removeEventListener('change', fire);
|
|
370
379
|
}
|
|
380
|
+
if (event === 'keyboard.show' || event === 'keyboard.hide') {
|
|
381
|
+
const vv = (window as any).visualViewport;
|
|
382
|
+
if (!vv) return () => {};
|
|
383
|
+
let shown = false;
|
|
384
|
+
const onResize = () => {
|
|
385
|
+
// The keyboard shrinks the visual viewport; the hidden band ≈ its height.
|
|
386
|
+
const height = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
|
|
387
|
+
const nowShown = height > 120; // threshold filters URL-bar/toolbar resizes
|
|
388
|
+
if (nowShown === shown) return;
|
|
389
|
+
shown = nowShown;
|
|
390
|
+
if (event === 'keyboard.show' && nowShown) cb({ height: Math.round(height) });
|
|
391
|
+
if (event === 'keyboard.hide' && !nowShown) cb(undefined);
|
|
392
|
+
};
|
|
393
|
+
vv.addEventListener('resize', onResize);
|
|
394
|
+
return () => vv.removeEventListener('resize', onResize);
|
|
395
|
+
}
|
|
371
396
|
if (event === 'app.pause' || event === 'app.resume') {
|
|
372
397
|
const handler = () => {
|
|
373
398
|
const paused = document.visibilityState === 'hidden';
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type {
|
|
|
22
22
|
export type { ImpactStyle, NotifyType } from './modules/haptics';
|
|
23
23
|
export type { SharePayload, ShareFile } from './modules/share';
|
|
24
24
|
export type { Orientation, OrientationLock } from './modules/screen';
|
|
25
|
+
export type { KeyboardInfo } from './modules/keyboard';
|
|
25
26
|
export type { DeviceInfo } from './modules/device';
|
|
26
27
|
export type { ScheduleOptions } from './modules/notifications';
|
|
27
28
|
export type { PushMessage, PushPlatform, PushToken } from './modules/push';
|
package/src/modules/contacts.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface PickedContact {
|
|
|
7
7
|
emails?: string[];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface Contact {
|
|
11
|
+
name?: string;
|
|
12
|
+
phones?: string[];
|
|
13
|
+
emails?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
/** Contact picker — native: CNContactPicker (no permission needed); web: Contact Picker API where present. */
|
|
11
17
|
export class ContactsModule {
|
|
12
18
|
constructor(private kit: NativeKit) {}
|
|
@@ -19,4 +25,9 @@ export class ContactsModule {
|
|
|
19
25
|
pick(): Promise<PickedContact> {
|
|
20
26
|
return this.kit.invoke('contacts.pick', undefined, { timeoutMs: 120_000 });
|
|
21
27
|
}
|
|
28
|
+
|
|
29
|
+
/** Read the full address book; native-only (requires permission), unsupported on web. */
|
|
30
|
+
getAll(): Promise<{ contacts: Contact[] }> {
|
|
31
|
+
return this.kit.invoke('contacts.getAll', undefined, { timeoutMs: 120_000 });
|
|
32
|
+
}
|
|
22
33
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { NativeKit } from '../core/NativeKit';
|
|
2
|
+
import type { Unsubscribe } from '../core/types';
|
|
3
|
+
|
|
4
|
+
/** Payload of {@link KeyboardModule.onShow}: the on-screen keyboard's height in CSS pixels,
|
|
5
|
+
* so the page can pad/scroll content above it. */
|
|
6
|
+
export interface KeyboardInfo {
|
|
7
|
+
/** Keyboard height in CSS px (0 when unknown). */
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Software-keyboard control + observation — ONE API across platforms.
|
|
13
|
+
*
|
|
14
|
+
* The classic webview pain: the keyboard slides up and covers the focused input.
|
|
15
|
+
* Native emits `show` with the keyboard height (CSS px) and `hide`, so the page can
|
|
16
|
+
* lift content above it; `hide()` dismisses the keyboard programmatically.
|
|
17
|
+
*
|
|
18
|
+
* Native (iOS `UIKeyboardWillShow/Hide`, Android global-layout/IME insets) reports
|
|
19
|
+
* `capability === 'native'`. Web maps to the VisualViewport API where present
|
|
20
|
+
* (`'web'`), else `'none'`. Branch on {@link capability}, not try/catch.
|
|
21
|
+
*/
|
|
22
|
+
export class KeyboardModule {
|
|
23
|
+
constructor(private kit: NativeKit) {}
|
|
24
|
+
|
|
25
|
+
/** 'native' on a shell · 'web' where VisualViewport exists · else 'none'. */
|
|
26
|
+
get capability() {
|
|
27
|
+
return this.kit.capability('keyboard');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Dismiss the software keyboard (resign first responder / hide the IME). */
|
|
31
|
+
hide(): Promise<void> {
|
|
32
|
+
return this.kit.invoke('keyboard.hide');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Keyboard shown — payload carries its height in CSS pixels. */
|
|
36
|
+
onShow(cb: (info: KeyboardInfo) => void): Unsubscribe {
|
|
37
|
+
return this.kit.on('keyboard.show', (p) => cb(p as KeyboardInfo));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Keyboard dismissed. */
|
|
41
|
+
onHide(cb: () => void): Unsubscribe {
|
|
42
|
+
return this.kit.on('keyboard.hide', () => cb());
|
|
43
|
+
}
|
|
44
|
+
}
|