Skip to content

Commit

Permalink
Merge pull request #583 from qeeqez/feature/v8-active-state
Browse files Browse the repository at this point in the history
v8 visible state
  • Loading branch information
heyqbnk authored Dec 17, 2024
2 parents fc6cfaa + 41ef1a6 commit 2f40464
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 77 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-ducks-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@telegram-apps/sdk": minor
---

Add functionality related to the mini apps active state.
5 changes: 5 additions & 0 deletions .changeset/strong-scissors-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@telegram-apps/bridge": minor
---

Add `visibility_changed` event.
23 changes: 22 additions & 1 deletion apps/docs/packages/telegram-apps-sdk/2-x/components/mini-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ if (miniApp.setBackgroundColor.isAvailable()) {
```

```ts [Functions]
import {
import {
setMiniAppBackgroundColor,
miniAppBackgroundColor,
} from '@telegram-apps/sdk';
Expand All @@ -172,6 +172,27 @@ if (setMiniAppBackgroundColor.isAvailable()) {

:::

## Active State

The mini application becomes inactive if it is wrapped into the bottom native Telegram client tray
or if the currently active tab of the mini apps browser is changed to another one.

To track if the mini application is currently active, use the `isActive` signal.

::: code-group

```ts [Variable]
miniApp.isActive();
```

```ts [Functions]
import { isMiniAppActive } from '@telegram-apps/sdk';

isMiniAppActive()
```

:::

## Methods

### `close`
Expand Down
13 changes: 13 additions & 0 deletions apps/docs/platform/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,19 @@ user started dragging the application or called the expansion method.
> application window. You should probably use a stable height instead of the current one, or handle
> this problem in another way.
### `visibility_changed`

Available since: **v8.0**

Active state assumes that the native Telegram client is currently working with the
current mini application. It is important to note that this is not related to the
mini application’s visibility, but rather its selection among other currently opened
mini applications.

| Field | Type | Description |
|------------|-----------|---------------------------------------------------|
| is_visible | `boolean` | Indicates if the application is currently active. |

### `write_access_requested`

Available since: **v6.9**
Expand Down
16 changes: 16 additions & 0 deletions packages/bridge/src/events/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,22 @@ export interface Events {
*/
is_state_stable: boolean;
};
/**
* Occurs whenever the mini app becomes active or inactive.
*
* Active state assumes that the native Telegram client is currently working with the
* current mini application. It is important to note that this is not related to the
* mini application’s visibility, but rather its selection among other currently opened
* mini applications.
* @since v8.0
* @see https://docs.telegram-mini-apps.com/platform/events#visibility_changed
*/
visibility_changed: {
/**
* Indicates if the application is currently active.
*/
is_visible: boolean;
};
/**
* Application received write access request status.
* @since v6.9
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/src/scopes/components/mini-app/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ export {
} from './methods.js';
export {
backgroundColor as miniAppBackgroundColor,
backgroundColorRGB as miniAppBackgroundColorRGB,
bottomBarColor as miniAppBottomBarColor,
bottomBarColorRGB as miniAppBottomBarColorRGB,
headerColor as miniAppHeaderColor,
headerColorRGB as miniAppHeaderColorRGB,
isMounted as isMiniAppMounted,
isCssVarsBound as isMiniAppCssVarsBound,
isDark as isMiniAppDark,
isActive as isMiniAppActive,
state as miniAppState,
} from './signals.js';
export type {
Expand Down
17 changes: 16 additions & 1 deletion packages/sdk/src/scopes/components/mini-app/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import {
deleteCssVar,
setCssVar,
supports,
on,
off,
type EventListener,
type RGB,
type BottomBarColor,
type BackgroundColor, MethodName,
type BackgroundColor,
type MethodName,
} from '@telegram-apps/bridge';
import { isRGB } from '@telegram-apps/transformers';
import { isPageReload } from '@telegram-apps/navigation';
Expand All @@ -31,6 +35,7 @@ import {
headerColorRGB,
bottomBarColorRGB,
backgroundColorRGB,
isActive,
} from './signals.js';
import type { GetCssVarNameFn, HeaderColor, State } from './types.js';

Expand All @@ -39,6 +44,7 @@ type StorageValue = State;
const SET_BG_COLOR_METHOD = 'web_app_set_background_color';
const SET_BOTTOM_BAR_COLOR_METHOD = 'web_app_set_bottom_bar_color';
const SET_HEADER_COLOR_METHOD = 'web_app_set_header_color';
const VISIBILITY_CHANGED_EVENT = 'visibility_changed';
const COMPONENT_NAME = 'miniApp';

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

const onVisibilityChanged: EventListener<'visibility_changed'> = (data) => {
isActive.set(data.is_visible);
saveState();
};

/**
* Mounts the component.
*
Expand Down Expand Up @@ -165,6 +176,9 @@ export const mount = wrapSupported(
setBackgroundColor.ifAvailable(s ? s.backgroundColor : 'bg_color');
setBottomBarColor.ifAvailable(s ? s.bottomBarColor : 'bottom_bar_bg_color');
setHeaderColor.ifAvailable(s ? s.headerColor : 'bg_color');
isActive.set(s ? s.isActive : true);

on(VISIBILITY_CHANGED_EVENT, onVisibilityChanged);

isMounted.set(true);
}
Expand Down Expand Up @@ -280,5 +294,6 @@ export const setHeaderColor = wrapComplete(
* Unmounts the component, removing the listener, saving the component state in the local storage.
*/
export function unmount(): void {
off(VISIBILITY_CHANGED_EVENT, onVisibilityChanged);
isMounted.set(false);
}
6 changes: 6 additions & 0 deletions packages/sdk/src/scopes/components/mini-app/signals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,17 @@ export const isDark = computed(() => {
return color ? isColorDark(color) : false;
});

/**
* Signal indicating if the mini app is currently active.
*/
export const isActive = signal(true);

/**
* Complete component state.
*/
export const state = computed<State>(() => ({
backgroundColor: backgroundColor(),
bottomBarColor: bottomBarColor(),
headerColor: headerColor(),
isActive: isActive(),
}));
1 change: 1 addition & 0 deletions packages/sdk/src/scopes/components/mini-app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface State {
backgroundColor: BackgroundColor;
bottomBarColor: BottomBarColor;
headerColor: HeaderColor;
isActive: boolean;
}

export interface GetCssVarNameFn {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
CSA_CHANGED_EVENT,
FS_CHANGED_EVENT,
SA_CHANGED_EVENT,
VIEWPORT_CHANGED_EVENT
VIEWPORT_CHANGED_EVENT,
} from '../../const.js';
import { isMounted, mountPromise, mountError } from '../../signals/mounting.js';
import { getStateFromStorage, setState } from '../../signals/state.js';
Expand All @@ -20,7 +20,12 @@ import { requestSafeAreaInsets } from '../static/requestSafeAreaInsets.js';
import { requestViewport } from '../static/requestViewport.js';
import type { State } from '../../types.js';

import { onContentSafeAreaChanged, onFullscreenChanged, onSafeAreaChanged, onViewportChanged } from './shared.js';
import {
onContentSafeAreaChanged,
onFullscreenChanged,
onSafeAreaChanged,
onViewportChanged,
} from './shared.js';

/**
* Mounts the Viewport component.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { off } from '@telegram-apps/bridge';

import { CSA_CHANGED_EVENT, FS_CHANGED_EVENT, SA_CHANGED_EVENT, VIEWPORT_CHANGED_EVENT } from '../../const.js';
import {
CSA_CHANGED_EVENT,
FS_CHANGED_EVENT,
SA_CHANGED_EVENT,
VIEWPORT_CHANGED_EVENT,
} from '../../const.js';
import { isMounted, mountPromise } from '../../signals/mounting.js';

import { onContentSafeAreaChanged, onFullscreenChanged, onSafeAreaChanged, onViewportChanged } from './shared.js';
import {
onContentSafeAreaChanged,
onFullscreenChanged,
onSafeAreaChanged,
onViewportChanged,
} from './shared.js';

/**
* Unmounts the Viewport.
Expand Down
23 changes: 0 additions & 23 deletions playgrounds/react/src/components/App.tsx

This file was deleted.

16 changes: 16 additions & 0 deletions playgrounds/react/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useLaunchParams, miniApp } from '@telegram-apps/sdk-react';
import { AppRoot } from '@telegram-apps/telegram-ui';
import { Outlet } from 'react-router-dom';

export function Layout() {
const lp = useLaunchParams();

return (
<AppRoot
appearance={miniApp.isDark() ? 'dark' : 'light'}
platform={['macos', 'ios'].includes(lp.platform) ? 'ios' : 'base'}
>
<Outlet/>
</AppRoot>
);
}
4 changes: 2 additions & 2 deletions playgrounds/react/src/components/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TonConnectUIProvider } from '@tonconnect/ui-react';

import { App } from '@/components/App.tsx';
import { ErrorBoundary } from '@/components/ErrorBoundary.tsx';
import Router from "@/navigation/Router.tsx";

function ErrorBoundaryError({ error }: { error: unknown }) {
return (
Expand All @@ -26,7 +26,7 @@ export function Root() {
<TonConnectUIProvider
manifestUrl={new URL('/tonconnect-manifest.json', window.location.href).toString()}
>
<App/>
<Router/>
</TonConnectUIProvider>
</ErrorBoundary>
);
Expand Down
25 changes: 25 additions & 0 deletions playgrounds/react/src/navigation/Router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {createBrowserRouter, RouterProvider} from "react-router-dom";
import {Layout} from "@/components/Layout.tsx";
import {IndexPage} from "@/pages/IndexPage/IndexPage.tsx";
import {InitDataPage} from "@/pages/InitDataPage.tsx";
import {LaunchParamsPage} from "@/pages/LaunchParamsPage.tsx";
import {ThemeParamsPage} from "@/pages/ThemeParamsPage.tsx";
import {ViewportParamsPage} from "@/pages/ViewportParamsPage.tsx";
import {TONConnectPage} from "@/pages/TONConnectPage/TONConnectPage.tsx";

export default function Router() {
const router = createBrowserRouter([{
path: "/",
element: <Layout/>,
children: [
{index: true, element: <IndexPage/>},
{path: "/init-data", element: <InitDataPage/>},
{path: "/launch-params", element: <LaunchParamsPage/>},
{path: "/theme-params", element: <ThemeParamsPage/>},
{path: "/viewport-params", element: <ViewportParamsPage/>},
{path: '/ton-connect', element: <TONConnectPage/>}
],
}]);

return <RouterProvider router={router}/>;
}
46 changes: 0 additions & 46 deletions playgrounds/react/src/navigation/routes.tsx

This file was deleted.

0 comments on commit 2f40464

Please sign in to comment.