@glassly/miniapp 0.3.0-dev.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.
- package/README.md +275 -0
- package/dist/background/index.d.ts +64 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +26 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/register.d.ts +39 -0
- package/dist/background/register.d.ts.map +1 -0
- package/dist/background/register.js +72 -0
- package/dist/background/register.js.map +1 -0
- package/dist/dev-reload.d.ts +21 -0
- package/dist/dev-reload.d.ts.map +1 -0
- package/dist/dev-reload.js +60 -0
- package/dist/dev-reload.js.map +1 -0
- package/dist/envelope.d.ts +23 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +47 -0
- package/dist/envelope.js.map +1 -0
- package/dist/globals.d.ts +54 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +12 -0
- package/dist/globals.js.map +1 -0
- package/dist/hardware.d.ts +38 -0
- package/dist/hardware.d.ts.map +1 -0
- package/dist/hardware.js +31 -0
- package/dist/hardware.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/actions.d.ts +81 -0
- package/dist/modules/actions.d.ts.map +1 -0
- package/dist/modules/actions.js +137 -0
- package/dist/modules/actions.js.map +1 -0
- package/dist/modules/ai.d.ts +211 -0
- package/dist/modules/ai.d.ts.map +1 -0
- package/dist/modules/ai.js +117 -0
- package/dist/modules/ai.js.map +1 -0
- package/dist/modules/auth.d.ts +25 -0
- package/dist/modules/auth.d.ts.map +1 -0
- package/dist/modules/auth.js +52 -0
- package/dist/modules/auth.js.map +1 -0
- package/dist/modules/base64.d.ts +16 -0
- package/dist/modules/base64.d.ts.map +1 -0
- package/dist/modules/base64.js +92 -0
- package/dist/modules/base64.js.map +1 -0
- package/dist/modules/blob.d.ts +161 -0
- package/dist/modules/blob.d.ts.map +1 -0
- package/dist/modules/blob.js +277 -0
- package/dist/modules/blob.js.map +1 -0
- package/dist/modules/camera.d.ts +183 -0
- package/dist/modules/camera.d.ts.map +1 -0
- package/dist/modules/camera.js +119 -0
- package/dist/modules/camera.js.map +1 -0
- package/dist/modules/cloud.d.ts +34 -0
- package/dist/modules/cloud.d.ts.map +1 -0
- package/dist/modules/cloud.js +70 -0
- package/dist/modules/cloud.js.map +1 -0
- package/dist/modules/dashboard.d.ts +24 -0
- package/dist/modules/dashboard.d.ts.map +1 -0
- package/dist/modules/dashboard.js +39 -0
- package/dist/modules/dashboard.js.map +1 -0
- package/dist/modules/display.d.ts +167 -0
- package/dist/modules/display.d.ts.map +1 -0
- package/dist/modules/display.js +83 -0
- package/dist/modules/display.js.map +1 -0
- package/dist/modules/events.d.ts +178 -0
- package/dist/modules/events.d.ts.map +1 -0
- package/dist/modules/events.js +168 -0
- package/dist/modules/events.js.map +1 -0
- package/dist/modules/glasses.d.ts +36 -0
- package/dist/modules/glasses.d.ts.map +1 -0
- package/dist/modules/glasses.js +52 -0
- package/dist/modules/glasses.js.map +1 -0
- package/dist/modules/heading.d.ts +16 -0
- package/dist/modules/heading.d.ts.map +1 -0
- package/dist/modules/heading.js +20 -0
- package/dist/modules/heading.js.map +1 -0
- package/dist/modules/imu.d.ts +31 -0
- package/dist/modules/imu.d.ts.map +1 -0
- package/dist/modules/imu.js +40 -0
- package/dist/modules/imu.js.map +1 -0
- package/dist/modules/input.d.ts +34 -0
- package/dist/modules/input.d.ts.map +1 -0
- package/dist/modules/input.js +50 -0
- package/dist/modules/input.js.map +1 -0
- package/dist/modules/keys.d.ts +30 -0
- package/dist/modules/keys.d.ts.map +1 -0
- package/dist/modules/keys.js +37 -0
- package/dist/modules/keys.js.map +1 -0
- package/dist/modules/languages.d.ts +42 -0
- package/dist/modules/languages.d.ts.map +1 -0
- package/dist/modules/languages.js +57 -0
- package/dist/modules/languages.js.map +1 -0
- package/dist/modules/led.d.ts +35 -0
- package/dist/modules/led.d.ts.map +1 -0
- package/dist/modules/led.js +39 -0
- package/dist/modules/led.js.map +1 -0
- package/dist/modules/location.d.ts +27 -0
- package/dist/modules/location.d.ts.map +1 -0
- package/dist/modules/location.js +35 -0
- package/dist/modules/location.js.map +1 -0
- package/dist/modules/memory.d.ts +126 -0
- package/dist/modules/memory.d.ts.map +1 -0
- package/dist/modules/memory.js +141 -0
- package/dist/modules/memory.js.map +1 -0
- package/dist/modules/mic.d.ts +61 -0
- package/dist/modules/mic.d.ts.map +1 -0
- package/dist/modules/mic.js +94 -0
- package/dist/modules/mic.js.map +1 -0
- package/dist/modules/miniapps.d.ts +82 -0
- package/dist/modules/miniapps.d.ts.map +1 -0
- package/dist/modules/miniapps.js +58 -0
- package/dist/modules/miniapps.js.map +1 -0
- package/dist/modules/navigation.d.ts +332 -0
- package/dist/modules/navigation.d.ts.map +1 -0
- package/dist/modules/navigation.js +387 -0
- package/dist/modules/navigation.js.map +1 -0
- package/dist/modules/permissions.d.ts +58 -0
- package/dist/modules/permissions.d.ts.map +1 -0
- package/dist/modules/permissions.js +66 -0
- package/dist/modules/permissions.js.map +1 -0
- package/dist/modules/phone.d.ts +95 -0
- package/dist/modules/phone.d.ts.map +1 -0
- package/dist/modules/phone.js +110 -0
- package/dist/modules/phone.js.map +1 -0
- package/dist/modules/pivots/engine.d.ts +169 -0
- package/dist/modules/pivots/engine.d.ts.map +1 -0
- package/dist/modules/pivots/engine.js +778 -0
- package/dist/modules/pivots/engine.js.map +1 -0
- package/dist/modules/pivots/geometry.d.ts +84 -0
- package/dist/modules/pivots/geometry.d.ts.map +1 -0
- package/dist/modules/pivots/geometry.js +371 -0
- package/dist/modules/pivots/geometry.js.map +1 -0
- package/dist/modules/pivots/instructions.d.ts +139 -0
- package/dist/modules/pivots/instructions.d.ts.map +1 -0
- package/dist/modules/pivots/instructions.js +281 -0
- package/dist/modules/pivots/instructions.js.map +1 -0
- package/dist/modules/speaker.d.ts +175 -0
- package/dist/modules/speaker.d.ts.map +1 -0
- package/dist/modules/speaker.js +249 -0
- package/dist/modules/speaker.js.map +1 -0
- package/dist/modules/speakers.d.ts +29 -0
- package/dist/modules/speakers.d.ts.map +1 -0
- package/dist/modules/speakers.js +38 -0
- package/dist/modules/speakers.js.map +1 -0
- package/dist/modules/storage.d.ts +50 -0
- package/dist/modules/storage.d.ts.map +1 -0
- package/dist/modules/storage.js +99 -0
- package/dist/modules/storage.js.map +1 -0
- package/dist/modules/stream.d.ts +133 -0
- package/dist/modules/stream.d.ts.map +1 -0
- package/dist/modules/stream.js +53 -0
- package/dist/modules/stream.js.map +1 -0
- package/dist/modules/system.d.ts +71 -0
- package/dist/modules/system.d.ts.map +1 -0
- package/dist/modules/system.js +65 -0
- package/dist/modules/system.js.map +1 -0
- package/dist/modules/transcription.d.ts +99 -0
- package/dist/modules/transcription.d.ts.map +1 -0
- package/dist/modules/transcription.js +126 -0
- package/dist/modules/transcription.js.map +1 -0
- package/dist/modules/translation.d.ts +65 -0
- package/dist/modules/translation.d.ts.map +1 -0
- package/dist/modules/translation.js +121 -0
- package/dist/modules/translation.js.map +1 -0
- package/dist/modules/ui.d.ts +186 -0
- package/dist/modules/ui.d.ts.map +1 -0
- package/dist/modules/ui.js +289 -0
- package/dist/modules/ui.js.map +1 -0
- package/dist/protocol.d.ts +384 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +413 -0
- package/dist/protocol.js.map +1 -0
- package/dist/react/MiniappHeader.d.ts +44 -0
- package/dist/react/MiniappHeader.d.ts.map +1 -0
- package/dist/react/MiniappHeader.js +32 -0
- package/dist/react/MiniappHeader.js.map +1 -0
- package/dist/react/MiniappProvider.d.ts +33 -0
- package/dist/react/MiniappProvider.d.ts.map +1 -0
- package/dist/react/MiniappProvider.js +15 -0
- package/dist/react/MiniappProvider.js.map +1 -0
- package/dist/react/capsuleHeaderLayout.d.ts +3 -0
- package/dist/react/capsuleHeaderLayout.d.ts.map +1 -0
- package/dist/react/capsuleHeaderLayout.js +5 -0
- package/dist/react/capsuleHeaderLayout.js.map +1 -0
- package/dist/react/index.d.ts +13 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +9 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useCapabilities.d.ts +26 -0
- package/dist/react/useCapabilities.d.ts.map +1 -0
- package/dist/react/useCapabilities.js +27 -0
- package/dist/react/useCapabilities.js.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts +27 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.js +39 -0
- package/dist/react/useCapsuleHeaderStyle.js.map +1 -0
- package/dist/react/useColorScheme.d.ts +18 -0
- package/dist/react/useColorScheme.d.ts.map +1 -0
- package/dist/react/useColorScheme.js +24 -0
- package/dist/react/useColorScheme.js.map +1 -0
- package/dist/react/useConnected.d.ts +17 -0
- package/dist/react/useConnected.d.ts.map +1 -0
- package/dist/react/useConnected.js +39 -0
- package/dist/react/useConnected.js.map +1 -0
- package/dist/react/useRpc.d.ts +29 -0
- package/dist/react/useRpc.d.ts.map +1 -0
- package/dist/react/useRpc.js +82 -0
- package/dist/react/useRpc.js.map +1 -0
- package/dist/react/useSafeArea.d.ts +21 -0
- package/dist/react/useSafeArea.d.ts.map +1 -0
- package/dist/react/useSafeArea.js +22 -0
- package/dist/react/useSafeArea.js.map +1 -0
- package/dist/session.d.ts +355 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +688 -0
- package/dist/session.js.map +1 -0
- package/dist/sub-path-types.test-d.d.ts +40 -0
- package/dist/sub-path-types.test-d.d.ts.map +1 -0
- package/dist/sub-path-types.test-d.js +37 -0
- package/dist/sub-path-types.test-d.js.map +1 -0
- package/dist/transport/auto.d.ts +35 -0
- package/dist/transport/auto.d.ts.map +1 -0
- package/dist/transport/auto.js +124 -0
- package/dist/transport/auto.js.map +1 -0
- package/dist/transport/dispatch.d.ts +43 -0
- package/dist/transport/dispatch.d.ts.map +1 -0
- package/dist/transport/dispatch.js +91 -0
- package/dist/transport/dispatch.js.map +1 -0
- package/dist/transport/local-socket.d.ts +28 -0
- package/dist/transport/local-socket.d.ts.map +1 -0
- package/dist/transport/local-socket.js +80 -0
- package/dist/transport/local-socket.js.map +1 -0
- package/dist/transport/mock.d.ts +54 -0
- package/dist/transport/mock.d.ts.map +1 -0
- package/dist/transport/mock.js +210 -0
- package/dist/transport/mock.js.map +1 -0
- package/dist/transport/postmessage.d.ts +36 -0
- package/dist/transport/postmessage.d.ts.map +1 -0
- package/dist/transport/postmessage.js +78 -0
- package/dist/transport/postmessage.js.map +1 -0
- package/dist/transport/types.d.ts +25 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +11 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/ui/index.d.ts +107 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +32 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +84 -0
- package/src/background/index.ts +177 -0
- package/src/background/register.ts +89 -0
- package/src/dev-reload.ts +59 -0
- package/src/envelope.ts +54 -0
- package/src/globals.ts +62 -0
- package/src/hardware.ts +40 -0
- package/src/index.ts +216 -0
- package/src/modules/actions.ts +189 -0
- package/src/modules/ai.ts +281 -0
- package/src/modules/auth.ts +68 -0
- package/src/modules/base64.ts +87 -0
- package/src/modules/blob.ts +341 -0
- package/src/modules/camera.ts +258 -0
- package/src/modules/cloud.ts +94 -0
- package/src/modules/dashboard.ts +51 -0
- package/src/modules/display.ts +207 -0
- package/src/modules/events.ts +318 -0
- package/src/modules/glasses.ts +58 -0
- package/src/modules/heading.ts +23 -0
- package/src/modules/imu.ts +44 -0
- package/src/modules/input.ts +66 -0
- package/src/modules/keys.ts +46 -0
- package/src/modules/languages.ts +72 -0
- package/src/modules/led.ts +61 -0
- package/src/modules/location.ts +39 -0
- package/src/modules/memory.ts +224 -0
- package/src/modules/mic.ts +103 -0
- package/src/modules/miniapps.ts +103 -0
- package/src/modules/navigation.ts +674 -0
- package/src/modules/permissions.ts +83 -0
- package/src/modules/phone.ts +155 -0
- package/src/modules/pivots/engine.ts +863 -0
- package/src/modules/pivots/geometry.ts +409 -0
- package/src/modules/pivots/instructions.ts +341 -0
- package/src/modules/speaker.ts +347 -0
- package/src/modules/speakers.ts +40 -0
- package/src/modules/storage.ts +109 -0
- package/src/modules/stream.ts +168 -0
- package/src/modules/system.ts +113 -0
- package/src/modules/transcription.ts +180 -0
- package/src/modules/translation.ts +156 -0
- package/src/modules/ui.ts +481 -0
- package/src/protocol.ts +475 -0
- package/src/react/MiniappHeader.tsx +114 -0
- package/src/react/MiniappProvider.tsx +50 -0
- package/src/react/capsuleHeaderLayout.ts +11 -0
- package/src/react/index.ts +12 -0
- package/src/react/useCapabilities.ts +29 -0
- package/src/react/useCapsuleHeaderStyle.ts +55 -0
- package/src/react/useColorScheme.ts +26 -0
- package/src/react/useConnected.ts +47 -0
- package/src/react/useRpc.ts +103 -0
- package/src/react/useSafeArea.ts +36 -0
- package/src/session.ts +969 -0
- package/src/sub-path-types.test-d.ts +60 -0
- package/src/transport/auto.ts +143 -0
- package/src/transport/dispatch.ts +106 -0
- package/src/transport/local-socket.ts +91 -0
- package/src/transport/mock.ts +255 -0
- package/src/transport/postmessage.ts +95 -0
- package/src/transport/types.ts +26 -0
- package/src/ui/index.ts +129 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview useCapabilities — React hook for the connected glasses'
|
|
3
|
+
* capability profile.
|
|
4
|
+
*
|
|
5
|
+
* The glasses `GlassesCapabilities` profile is *background-only* state: it
|
|
6
|
+
* arrives on the background `MiniappSession` (CONNECT_ACK / CAPABILITIES_UPDATE)
|
|
7
|
+
* and is never injected into the UI WebView, so there is no WebView-side source
|
|
8
|
+
* for it — this hook always returns `null`.
|
|
9
|
+
*
|
|
10
|
+
* If a UI page needs glasses capabilities, relay them from the background half
|
|
11
|
+
* over an app channel: read `session.capabilities` in a `session.ui.onOpen`
|
|
12
|
+
* handler, `session.ui.send("caps", ...)`, then read it in the UI with
|
|
13
|
+
* `glassly.on("caps", ...)`. See the example miniapp's `captions:snapshot`
|
|
14
|
+
* channel for the pattern.
|
|
15
|
+
*
|
|
16
|
+
* IMPORTANT: this hook must NOT construct a `MiniappSession`. That is the
|
|
17
|
+
* *background* (JSContext) API; inside a UI WebView its `CONNECT` never gets an
|
|
18
|
+
* ACK from the host's UI router and `session.connect()` times out
|
|
19
|
+
* ("CONNECT_ACK timeout") — the original reason this hook was rewritten.
|
|
20
|
+
*
|
|
21
|
+
* (Note: `window.Glassly.capabilities` is a different thing — host *feature*
|
|
22
|
+
* flags like "share" / "open_url", not the glasses hardware profile.)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {type GlassesCapabilities} from "../session"
|
|
26
|
+
|
|
27
|
+
export function useCapabilities(): GlassesCapabilities | null {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview useCapsuleHeaderStyle — ready-to-spread React CSS props that
|
|
3
|
+
* vertically align a header row with the host's floating capsule menu.
|
|
4
|
+
*
|
|
5
|
+
* Use this when you want full control over header markup but want the
|
|
6
|
+
* alignment math done for you. If you just want a stock header, use
|
|
7
|
+
* <MiniappHeader> instead.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* const style = useCapsuleHeaderStyle()
|
|
11
|
+
* <header style={style}>
|
|
12
|
+
* <h1>Hello</h1>
|
|
13
|
+
* </header>
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type {CSSProperties} from "react"
|
|
17
|
+
|
|
18
|
+
import {getCapsuleHeaderPaddingRight} from "./capsuleHeaderLayout"
|
|
19
|
+
import {useSafeArea} from "./useSafeArea"
|
|
20
|
+
|
|
21
|
+
export interface UseCapsuleHeaderStyleOptions {
|
|
22
|
+
/** Extra left padding beyond the safe area. Default 20px. */
|
|
23
|
+
leftPadding?: number
|
|
24
|
+
/** Extra space between the header content and the capsule menu. Default 16px. */
|
|
25
|
+
rightGap?: number
|
|
26
|
+
/** Fallback header height when no capsule menu is present. Default 32px. */
|
|
27
|
+
fallbackHeight?: number
|
|
28
|
+
/** Fallback top margin when no capsule menu is present. Default 16px. */
|
|
29
|
+
fallbackMarginTop?: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function useCapsuleHeaderStyle(options: UseCapsuleHeaderStyleOptions = {}): CSSProperties {
|
|
33
|
+
const {leftPadding = 20, rightGap = 16, fallbackHeight = 32, fallbackMarginTop = 16} = options
|
|
34
|
+
const {insets, capsuleMenu} = useSafeArea()
|
|
35
|
+
|
|
36
|
+
const height = capsuleMenu?.height ?? fallbackHeight
|
|
37
|
+
const center = capsuleMenu ? capsuleMenu.top + capsuleMenu.height / 2 - insets.top : fallbackMarginTop + height / 2
|
|
38
|
+
const marginTop = Math.max(0, center - height / 2)
|
|
39
|
+
const paddingRight = capsuleMenu
|
|
40
|
+
? typeof window === "undefined"
|
|
41
|
+
? capsuleMenu.width + rightGap
|
|
42
|
+
: getCapsuleHeaderPaddingRight(capsuleMenu, window.innerWidth, insets.right, rightGap)
|
|
43
|
+
: leftPadding
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
display: "flex",
|
|
47
|
+
flexShrink: 0,
|
|
48
|
+
alignItems: "center",
|
|
49
|
+
justifyContent: "space-between",
|
|
50
|
+
paddingLeft: leftPadding,
|
|
51
|
+
paddingRight,
|
|
52
|
+
marginTop,
|
|
53
|
+
height,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview useColorScheme — React hook that returns the host's current
|
|
3
|
+
* color scheme.
|
|
4
|
+
*
|
|
5
|
+
* WebView-side hook: reads `window.Glassly.colorScheme`, injected by the host
|
|
6
|
+
* before the miniapp's content loads. Like `useSafeArea`, this is read once at
|
|
7
|
+
* mount — the host doesn't push color-scheme changes to the WebView at runtime;
|
|
8
|
+
* flipping the phone's theme forces a reload.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: this hook must NOT construct a `MiniappSession`. `MiniappSession`
|
|
11
|
+
* is the *background* (JSContext) API; inside a UI WebView its transport falls
|
|
12
|
+
* back to PostMessage and its `CONNECT` never gets an ACK from the host's UI
|
|
13
|
+
* router, so `session.connect()` times out ("CONNECT_ACK timeout"). UI hooks
|
|
14
|
+
* read host-injected globals instead (see `useSafeArea`).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {useState} from "react"
|
|
18
|
+
|
|
19
|
+
import {getGlasslyGlobals, type MiniappColorScheme} from "../globals"
|
|
20
|
+
|
|
21
|
+
export function useColorScheme(): MiniappColorScheme {
|
|
22
|
+
const [scheme] = useState<MiniappColorScheme>(() => {
|
|
23
|
+
return getGlasslyGlobals().colorScheme === "dark" ? "dark" : "light"
|
|
24
|
+
})
|
|
25
|
+
return scheme
|
|
26
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview useConnected — React hook that returns true while the miniapp's
|
|
3
|
+
* UI WebView is bridged to its background JSContext.
|
|
4
|
+
*
|
|
5
|
+
* WebView-side hook. "Connected" here means the `window.glassly` bridge is open:
|
|
6
|
+
* the shim has fired `glassly.ready()` and the host has bound the WebView so
|
|
7
|
+
* `glassly.send/on/request` flow. Tracked via the shim's `onOpen` / `onClose`.
|
|
8
|
+
* `onOpen` fires its callback immediately if the bridge is already open (see
|
|
9
|
+
* the shim), so late mounts still observe the connected state.
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT: this hook must NOT construct a `MiniappSession`. That is the
|
|
12
|
+
* *background* (JSContext) API; inside a UI WebView its `CONNECT` never gets an
|
|
13
|
+
* ACK from the host's UI router and `session.connect()` times out
|
|
14
|
+
* ("CONNECT_ACK timeout").
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {useEffect, useState} from "react"
|
|
18
|
+
|
|
19
|
+
interface Bridge {
|
|
20
|
+
onOpen?: (cb: () => void) => () => void
|
|
21
|
+
onClose?: (cb: () => void) => () => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getBridge(): Bridge | null {
|
|
25
|
+
if (typeof window === "undefined") return null
|
|
26
|
+
return (window as unknown as {glassly?: Bridge}).glassly ?? null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function useConnected(): boolean {
|
|
30
|
+
const [connected, setConnected] = useState<boolean>(false)
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const bridge = getBridge()
|
|
34
|
+
if (!bridge) return
|
|
35
|
+
|
|
36
|
+
// onOpen fires immediately when the bridge is already open, so this also
|
|
37
|
+
// seeds the initial value without a separate synchronous read.
|
|
38
|
+
const offOpen = bridge.onOpen?.(() => setConnected(true))
|
|
39
|
+
const offClose = bridge.onClose?.(() => setConnected(false))
|
|
40
|
+
return () => {
|
|
41
|
+
offOpen?.()
|
|
42
|
+
offClose?.()
|
|
43
|
+
}
|
|
44
|
+
}, [])
|
|
45
|
+
|
|
46
|
+
return connected
|
|
47
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRpc — React hook around `glassly.request(channel, ...)`.
|
|
3
|
+
*
|
|
4
|
+
* Returns a stable callable plus an `.abort()` method. The internal
|
|
5
|
+
* AbortController is recreated per call and bound to component lifecycle:
|
|
6
|
+
*
|
|
7
|
+
* - Calling the returned function once: abort() the previous in-flight
|
|
8
|
+
* call (if any), then issue a fresh request. Useful for per-keystroke
|
|
9
|
+
* autocomplete — every keystroke aborts the stale request.
|
|
10
|
+
* - Unmount: all in-flight calls abort.
|
|
11
|
+
* - Caller-provided `options.signal` is merged with the internal one
|
|
12
|
+
* via `AbortSignal.any` when available; manual fan-out otherwise.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {useCallback, useEffect, useRef} from "react"
|
|
16
|
+
|
|
17
|
+
import type {RpcReq, RpcRes, RpcRequestOptions} from "../modules/ui"
|
|
18
|
+
|
|
19
|
+
type RequestFn = (channel: string, payload: unknown, options?: RpcRequestOptions) => Promise<unknown>
|
|
20
|
+
|
|
21
|
+
/** Walk to the global `glassly.request` (typed). */
|
|
22
|
+
function getGlasslyRequest(): RequestFn {
|
|
23
|
+
const m = (globalThis as unknown as {glassly?: {request?: RequestFn}}).glassly
|
|
24
|
+
if (!m || typeof m.request !== "function") {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"useRpc: window.glassly.request is not available — is this miniapp running in a UI WebView with the shim injected?",
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
return m.request
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** AbortSignal.any polyfill — combine multiple signals into one. */
|
|
33
|
+
function mergeSignals(signals: AbortSignal[]): AbortSignal {
|
|
34
|
+
type WithAny = {any?: (s: AbortSignal[]) => AbortSignal}
|
|
35
|
+
const ctor = AbortSignal as unknown as WithAny
|
|
36
|
+
if (typeof ctor.any === "function") return ctor.any(signals)
|
|
37
|
+
const ctrl = new AbortController()
|
|
38
|
+
const onAbort = (sig: AbortSignal) => {
|
|
39
|
+
if (!ctrl.signal.aborted) ctrl.abort(sig.reason)
|
|
40
|
+
}
|
|
41
|
+
for (const s of signals) {
|
|
42
|
+
if (s.aborted) {
|
|
43
|
+
onAbort(s)
|
|
44
|
+
break
|
|
45
|
+
}
|
|
46
|
+
s.addEventListener("abort", () => onAbort(s))
|
|
47
|
+
}
|
|
48
|
+
return ctrl.signal
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface RpcCallable<TChannels extends object, C extends keyof TChannels & string> {
|
|
52
|
+
(payload: RpcReq<TChannels[C]>, options?: RpcRequestOptions): Promise<RpcRes<TChannels[C]>>
|
|
53
|
+
/** Abort the current in-flight call (if any). No-op if nothing is pending. */
|
|
54
|
+
abort(): void
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns a stable callable for an RPC channel. The callable auto-aborts
|
|
59
|
+
* on unmount and exposes `.abort()` for cancel-previous patterns.
|
|
60
|
+
*
|
|
61
|
+
* const autocomplete = useRpc<Channels, "places:autocomplete">("places:autocomplete")
|
|
62
|
+
* const suggestions = await autocomplete({query: "..."})
|
|
63
|
+
* autocomplete.abort() // cancel the latest in-flight call
|
|
64
|
+
*/
|
|
65
|
+
export function useRpc<TChannels extends object, C extends keyof TChannels & string>(
|
|
66
|
+
channel: C,
|
|
67
|
+
): RpcCallable<TChannels, C> {
|
|
68
|
+
// Latest in-flight controller. Replaced on each call.
|
|
69
|
+
const currentRef = useRef<AbortController | null>(null)
|
|
70
|
+
// Mount controller — aborts every in-flight call on unmount.
|
|
71
|
+
const mountRef = useRef<AbortController | null>(null)
|
|
72
|
+
if (mountRef.current == null) mountRef.current = new AbortController()
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const mount = mountRef.current!
|
|
76
|
+
return () => {
|
|
77
|
+
mount.abort()
|
|
78
|
+
currentRef.current?.abort()
|
|
79
|
+
currentRef.current = null
|
|
80
|
+
}
|
|
81
|
+
}, [])
|
|
82
|
+
|
|
83
|
+
const callable = useCallback(
|
|
84
|
+
(payload: RpcReq<TChannels[C]>, options?: RpcRequestOptions) => {
|
|
85
|
+
// Abort any previous call for this hook.
|
|
86
|
+
currentRef.current?.abort()
|
|
87
|
+
const ctrl = new AbortController()
|
|
88
|
+
currentRef.current = ctrl
|
|
89
|
+
const signals: AbortSignal[] = [ctrl.signal, mountRef.current!.signal]
|
|
90
|
+
if (options?.signal) signals.push(options.signal)
|
|
91
|
+
const signal = mergeSignals(signals)
|
|
92
|
+
return getGlasslyRequest()(channel, payload, {signal, timeout: options?.timeout}) as Promise<RpcRes<TChannels[C]>>
|
|
93
|
+
},
|
|
94
|
+
[channel],
|
|
95
|
+
) as RpcCallable<TChannels, C>
|
|
96
|
+
|
|
97
|
+
callable.abort = () => {
|
|
98
|
+
currentRef.current?.abort()
|
|
99
|
+
currentRef.current = null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return callable
|
|
103
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview useSafeArea — React hook exposing the host's safe-area insets
|
|
3
|
+
* and the capsule menu rect to miniapp UIs.
|
|
4
|
+
*
|
|
5
|
+
* The host injects these via window.Glassly before content loads. This hook
|
|
6
|
+
* reads them once at mount — they don't currently change at runtime (the host
|
|
7
|
+
* would have to force a reload to update them, e.g. on orientation change).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {useState} from "react"
|
|
11
|
+
|
|
12
|
+
import {getGlasslyGlobals, type MiniappCapsuleMenuRect, type MiniappSafeAreaInsets} from "../globals"
|
|
13
|
+
|
|
14
|
+
const EMPTY_INSETS: MiniappSafeAreaInsets = {top: 0, bottom: 0, left: 0, right: 0}
|
|
15
|
+
|
|
16
|
+
export interface UseSafeAreaResult {
|
|
17
|
+
/** Pixel insets around the WebView content. Apply as padding on your root element. */
|
|
18
|
+
insets: MiniappSafeAreaInsets
|
|
19
|
+
/**
|
|
20
|
+
* Bounding rect of the host's floating capsule menu (top-right overlay).
|
|
21
|
+
* Null when the host doesn't render one (e.g. older builds). Use this to
|
|
22
|
+
* avoid placing clickable content underneath the menu.
|
|
23
|
+
*/
|
|
24
|
+
capsuleMenu: MiniappCapsuleMenuRect | null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function useSafeArea(): UseSafeAreaResult {
|
|
28
|
+
const [result] = useState<UseSafeAreaResult>(() => {
|
|
29
|
+
const globals = getGlasslyGlobals()
|
|
30
|
+
return {
|
|
31
|
+
insets: globals.safeAreaInsets ?? EMPTY_INSETS,
|
|
32
|
+
capsuleMenu: globals.capsuleMenu ?? null,
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
return result
|
|
36
|
+
}
|