Skip to content

Commit 2f40464

Browse files
authored
Merge pull request #583 from qeeqez/feature/v8-active-state
v8 visible state
2 parents fc6cfaa + 41ef1a6 commit 2f40464

File tree

16 files changed

+148
-77
lines changed

16 files changed

+148
-77
lines changed

.changeset/eleven-ducks-carry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@telegram-apps/sdk": minor
3+
---
4+
5+
Add functionality related to the mini apps active state.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@telegram-apps/bridge": minor
3+
---
4+
5+
Add `visibility_changed` event.

apps/docs/packages/telegram-apps-sdk/2-x/components/mini-app.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ if (miniApp.setBackgroundColor.isAvailable()) {
159159
```
160160

161161
```ts [Functions]
162-
import {
162+
import {
163163
setMiniAppBackgroundColor,
164164
miniAppBackgroundColor,
165165
} from '@telegram-apps/sdk';
@@ -172,6 +172,27 @@ if (setMiniAppBackgroundColor.isAvailable()) {
172172

173173
:::
174174

175+
## Active State
176+
177+
The mini application becomes inactive if it is wrapped into the bottom native Telegram client tray
178+
or if the currently active tab of the mini apps browser is changed to another one.
179+
180+
To track if the mini application is currently active, use the `isActive` signal.
181+
182+
::: code-group
183+
184+
```ts [Variable]
185+
miniApp.isActive();
186+
```
187+
188+
```ts [Functions]
189+
import { isMiniAppActive } from '@telegram-apps/sdk';
190+
191+
isMiniAppActive()
192+
```
193+
194+
:::
195+
175196
## Methods
176197

177198
### `close`

apps/docs/platform/events.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,19 @@ user started dragging the application or called the expansion method.
349349
> application window. You should probably use a stable height instead of the current one, or handle
350350
> this problem in another way.
351351
352+
### `visibility_changed`
353+
354+
Available since: **v8.0**
355+
356+
Active state assumes that the native Telegram client is currently working with the
357+
current mini application. It is important to note that this is not related to the
358+
mini application’s visibility, but rather its selection among other currently opened
359+
mini applications.
360+
361+
| Field | Type | Description |
362+
|------------|-----------|---------------------------------------------------|
363+
| is_visible | `boolean` | Indicates if the application is currently active. |
364+
352365
### `write_access_requested`
353366

354367
Available since: **v6.9**

packages/bridge/src/events/types/events.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,22 @@ export interface Events {
365365
*/
366366
is_state_stable: boolean;
367367
};
368+
/**
369+
* Occurs whenever the mini app becomes active or inactive.
370+
*
371+
* Active state assumes that the native Telegram client is currently working with the
372+
* current mini application. It is important to note that this is not related to the
373+
* mini application’s visibility, but rather its selection among other currently opened
374+
* mini applications.
375+
* @since v8.0
376+
* @see https://docs.telegram-mini-apps.com/platform/events#visibility_changed
377+
*/
378+
visibility_changed: {
379+
/**
380+
* Indicates if the application is currently active.
381+
*/
382+
is_visible: boolean;
383+
};
368384
/**
369385
* Application received write access request status.
370386
* @since v6.9

packages/sdk/src/scopes/components/mini-app/exports.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ export {
1111
} from './methods.js';
1212
export {
1313
backgroundColor as miniAppBackgroundColor,
14+
backgroundColorRGB as miniAppBackgroundColorRGB,
1415
bottomBarColor as miniAppBottomBarColor,
1516
bottomBarColorRGB as miniAppBottomBarColorRGB,
1617
headerColor as miniAppHeaderColor,
1718
headerColorRGB as miniAppHeaderColorRGB,
1819
isMounted as isMiniAppMounted,
1920
isCssVarsBound as isMiniAppCssVarsBound,
2021
isDark as isMiniAppDark,
22+
isActive as isMiniAppActive,
2123
state as miniAppState,
2224
} from './signals.js';
2325
export type {

packages/sdk/src/scopes/components/mini-app/methods.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ import {
66
deleteCssVar,
77
setCssVar,
88
supports,
9+
on,
10+
off,
11+
type EventListener,
912
type RGB,
1013
type BottomBarColor,
11-
type BackgroundColor, MethodName,
14+
type BackgroundColor,
15+
type MethodName,
1216
} from '@telegram-apps/bridge';
1317
import { isRGB } from '@telegram-apps/transformers';
1418
import { isPageReload } from '@telegram-apps/navigation';
@@ -31,6 +35,7 @@ import {
3135
headerColorRGB,
3236
bottomBarColorRGB,
3337
backgroundColorRGB,
38+
isActive,
3439
} from './signals.js';
3540
import type { GetCssVarNameFn, HeaderColor, State } from './types.js';
3641

@@ -39,6 +44,7 @@ type StorageValue = State;
3944
const SET_BG_COLOR_METHOD = 'web_app_set_background_color';
4045
const SET_BOTTOM_BAR_COLOR_METHOD = 'web_app_set_bottom_bar_color';
4146
const SET_HEADER_COLOR_METHOD = 'web_app_set_header_color';
47+
const VISIBILITY_CHANGED_EVENT = 'visibility_changed';
4248
const COMPONENT_NAME = 'miniApp';
4349

4450
const isSupportedSchema = {
@@ -138,6 +144,11 @@ export const close = wrapBasic('close', (returnBack?: boolean): void => {
138144
postEvent('web_app_close', { return_back: returnBack });
139145
});
140146

147+
const onVisibilityChanged: EventListener<'visibility_changed'> = (data) => {
148+
isActive.set(data.is_visible);
149+
saveState();
150+
};
151+
141152
/**
142153
* Mounts the component.
143154
*
@@ -165,6 +176,9 @@ export const mount = wrapSupported(
165176
setBackgroundColor.ifAvailable(s ? s.backgroundColor : 'bg_color');
166177
setBottomBarColor.ifAvailable(s ? s.bottomBarColor : 'bottom_bar_bg_color');
167178
setHeaderColor.ifAvailable(s ? s.headerColor : 'bg_color');
179+
isActive.set(s ? s.isActive : true);
180+
181+
on(VISIBILITY_CHANGED_EVENT, onVisibilityChanged);
168182

169183
isMounted.set(true);
170184
}
@@ -280,5 +294,6 @@ export const setHeaderColor = wrapComplete(
280294
* Unmounts the component, removing the listener, saving the component state in the local storage.
281295
*/
282296
export function unmount(): void {
297+
off(VISIBILITY_CHANGED_EVENT, onVisibilityChanged);
283298
isMounted.set(false);
284299
}

packages/sdk/src/scopes/components/mini-app/signals.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,17 @@ export const isDark = computed(() => {
9191
return color ? isColorDark(color) : false;
9292
});
9393

94+
/**
95+
* Signal indicating if the mini app is currently active.
96+
*/
97+
export const isActive = signal(true);
98+
9499
/**
95100
* Complete component state.
96101
*/
97102
export const state = computed<State>(() => ({
98103
backgroundColor: backgroundColor(),
99104
bottomBarColor: bottomBarColor(),
100105
headerColor: headerColor(),
106+
isActive: isActive(),
101107
}));

packages/sdk/src/scopes/components/mini-app/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface State {
99
backgroundColor: BackgroundColor;
1010
bottomBarColor: BottomBarColor;
1111
headerColor: HeaderColor;
12+
isActive: boolean;
1213
}
1314

1415
export interface GetCssVarNameFn {

packages/sdk/src/scopes/components/viewport/methods/mounting/mount.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
CSA_CHANGED_EVENT,
1010
FS_CHANGED_EVENT,
1111
SA_CHANGED_EVENT,
12-
VIEWPORT_CHANGED_EVENT
12+
VIEWPORT_CHANGED_EVENT,
1313
} from '../../const.js';
1414
import { isMounted, mountPromise, mountError } from '../../signals/mounting.js';
1515
import { getStateFromStorage, setState } from '../../signals/state.js';
@@ -20,7 +20,12 @@ import { requestSafeAreaInsets } from '../static/requestSafeAreaInsets.js';
2020
import { requestViewport } from '../static/requestViewport.js';
2121
import type { State } from '../../types.js';
2222

23-
import { onContentSafeAreaChanged, onFullscreenChanged, onSafeAreaChanged, onViewportChanged } from './shared.js';
23+
import {
24+
onContentSafeAreaChanged,
25+
onFullscreenChanged,
26+
onSafeAreaChanged,
27+
onViewportChanged,
28+
} from './shared.js';
2429

2530
/**
2631
* Mounts the Viewport component.

0 commit comments

Comments
 (0)