Skip to content

Commit c9b0c28

Browse files
committed
feat: implement Fullscreen
1 parent 55e7746 commit c9b0c28

7 files changed

Lines changed: 115 additions & 4 deletions

File tree

‎packages/mini-app-react/src/context.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
BackButton,
3+
Fullscreen,
34
Haptic,
45
MainButton,
56
SecondaryButton,
@@ -12,6 +13,7 @@ import { createContext } from 'react'
1213

1314
export interface MiniApp {
1415
viewport: Viewport.Viewport
16+
fullscreen: Fullscreen.Fullscreen
1517
backButton: BackButton.BackButton
1618
settingsButton: SettingsButton.SettingsButton
1719
mainButton: MainButton.MainButton
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useStore } from '@tanstack/react-store'
2+
import { useMiniApp } from './useMiniApp'
3+
4+
export interface UseFullscreenReturn {
5+
isFullscreen: boolean
6+
state: 'fullscreen' | 'not-fullscreen' | 'entering' | 'exiting'
7+
setFullscreen: (value: boolean) => Promise<{
8+
isFullscreen: boolean
9+
error?: 'UNSUPPORTED' | 'ALREADY_FULLSCREEN'
10+
}>
11+
}
12+
13+
export function useFullscreen(): UseFullscreenReturn {
14+
const { fullscreen } = useMiniApp()
15+
const state = useStore(fullscreen.stateStore, ({ state }) => state)
16+
return {
17+
isFullscreen: state === 'fullscreen',
18+
state,
19+
setFullscreen: fullscreen.setFullscreen,
20+
}
21+
}

‎packages/mini-app-react/src/index.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export { useMiniApp } from './hooks/useMiniApp.ts'
99
export type { UseViewportOptions, UseViewportReturn } from './hooks/useViewport.ts'
1010
export { useViewport } from './hooks/useViewport.ts'
1111

12+
// fullscreen
13+
export type { UseFullscreenReturn } from './hooks/useFullscreen.ts'
14+
export { useFullscreen } from './hooks/useFullscreen.ts'
15+
1216
// theme
1317
export type { UseThemeReturn } from './hooks/useTheme.ts'
1418
export { useTheme } from './hooks/useTheme.ts'
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { Bridge } from './Bridge.ts'
2+
import type { LaunchParams } from './LaunchParams.ts'
3+
import type { StoredState } from './SessionStorage.ts'
4+
import { Store } from '@tanstack/store'
5+
6+
/**
7+
* Module for controlling the fullscreen mode of the mini app.
8+
*/
9+
export interface Fullscreen {
10+
stateStore: Store<State>
11+
setFullscreen: (value: boolean) => Promise<{
12+
isFullscreen: boolean
13+
error?: 'UNSUPPORTED' | 'ALREADY_FULLSCREEN'
14+
}>
15+
}
16+
17+
export interface State {
18+
state: 'fullscreen' | 'not-fullscreen' | 'entering' | 'exiting'
19+
}
20+
21+
const toState = (value: boolean): State['state'] => (value ? 'fullscreen' : 'not-fullscreen')
22+
23+
export const init = (options: {
24+
launchParams: LaunchParams
25+
bridge: Bridge
26+
storedState: StoredState<State>
27+
}): Fullscreen => {
28+
const { launchParams, bridge, storedState } = options
29+
const stored = storedState.load()
30+
const stateStore = new Store<State>({ state: stored?.state ?? toState(launchParams.fullscreen) })
31+
stateStore.subscribe(({ currentVal }) => {
32+
storedState.save(currentVal)
33+
})
34+
let request: null | {
35+
promise: ReturnType<Fullscreen['setFullscreen']>
36+
resolve: (result: Awaited<ReturnType<Fullscreen['setFullscreen']>>) => void
37+
} = null
38+
bridge.on('fullscreen_changed', ({ is_fullscreen }) => {
39+
stateStore.setState({ state: toState(is_fullscreen) })
40+
if (request) {
41+
request.resolve({ isFullscreen: is_fullscreen })
42+
request = null
43+
}
44+
})
45+
bridge.on('fullscreen_failed', ({ error }) => {
46+
stateStore.setState({ state: toState(error === 'ALREADY_FULLSCREEN') })
47+
if (request) {
48+
request.resolve({
49+
isFullscreen: stateStore.state.state === 'fullscreen',
50+
error,
51+
})
52+
request = null
53+
}
54+
})
55+
return {
56+
stateStore,
57+
setFullscreen: (value) => {
58+
if (request) {
59+
return request.promise
60+
}
61+
if (value) {
62+
stateStore.setState({ state: 'entering' })
63+
bridge.emit('web_app_request_fullscreen')
64+
}
65+
else {
66+
stateStore.setState({ state: 'exiting' })
67+
bridge.emit('web_app_exit_fullscreen')
68+
}
69+
request = Promise.withResolvers()
70+
return request.promise
71+
},
72+
}
73+
}

‎packages/mini-app/src/SessionStorage.ts‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@ export const make = (options: {
1515
const { storage, transformKey } = options
1616
return {
1717
storedState: (key: string) => ({
18-
save: state => storage.setItem(transformKey(key), JSON.stringify(state)),
19-
load: () => JSON.parse(storage.getItem(transformKey(key)) || 'null'),
20-
clear: () => storage.removeItem(transformKey(key)),
18+
save: (state) => {
19+
storage.setItem(transformKey(key), JSON.stringify(state))
20+
},
21+
load: () => {
22+
const stored = storage.getItem(transformKey(key))
23+
if (stored) {
24+
return JSON.parse(stored)
25+
}
26+
return null
27+
},
28+
clear: () => {
29+
storage.removeItem(transformKey(key))
30+
},
2131
}),
2232
}
2333
}

‎packages/mini-app/src/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * as BackButton from './BackButton.ts'
22
export * as Bridge from './Bridge.ts'
33
export * as Events from './Events.ts'
4+
export * as Fullscreen from './Fullscreen.ts'
45
export * as Haptic from './Haptic.ts'
56
export * as InitParams from './InitParams.ts'
67
export * as LaunchParams from './LaunchParams.ts'

‎tsconfig.lib.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"extends": "./tsconfig.base.json",
33
"compilerOptions": {
44
"target": "es2020",
5-
"lib": ["DOM", "DOM.Iterable", "ES2022"],
5+
"lib": ["ES2024", "DOM", "DOM.Iterable"],
66
"baseUrl": ".",
77
"rootDir": ".",
88
"module": "esnext",

0 commit comments

Comments
 (0)