@mr-m/telegram-webapp-kit 1.0.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/README.md +376 -0
- package/dist/index.d.mts +701 -0
- package/dist/index.d.ts +701 -0
- package/dist/index.js +1232 -0
- package/dist/index.mjs +1174 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# telegram-webapp-kit
|
|
2
|
+
|
|
3
|
+
Full-featured Telegram Mini App SDK for React / Next.js.
|
|
4
|
+
Types · Hooks · Providers · Utilities — zero dependencies beyond React.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install telegram-webapp-kit
|
|
12
|
+
# or
|
|
13
|
+
pnpm add telegram-webapp-kit
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Add the Telegram script to your `layout.tsx` or `_document.tsx`:
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// Next.js App Router — layout.tsx
|
|
20
|
+
import Script from 'next/script';
|
|
21
|
+
|
|
22
|
+
export default function RootLayout({ children }) {
|
|
23
|
+
return (
|
|
24
|
+
<html>
|
|
25
|
+
<head>
|
|
26
|
+
<Script
|
|
27
|
+
src="https://telegram.org/js/telegram-web-app.js"
|
|
28
|
+
strategy="beforeInteractive"
|
|
29
|
+
/>
|
|
30
|
+
</head>
|
|
31
|
+
<body>{children}</body>
|
|
32
|
+
</html>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Setup Providers
|
|
40
|
+
|
|
41
|
+
Wrap your app with the providers you need:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// app/providers.tsx
|
|
45
|
+
'use client';
|
|
46
|
+
import {
|
|
47
|
+
TelegramProvider,
|
|
48
|
+
FullscreenProvider,
|
|
49
|
+
type TelegramProviderOptions,
|
|
50
|
+
} from '@mr-m/telegram-webapp-kit';
|
|
51
|
+
|
|
52
|
+
const telegramOptions: TelegramProviderOptions = {
|
|
53
|
+
langStorageKey: 'my-app-lang', // localStorage key for saved language
|
|
54
|
+
onUserReady: (user) => {
|
|
55
|
+
// sync user to your backend
|
|
56
|
+
fetch('/api/user', { method: 'POST', body: JSON.stringify(user) });
|
|
57
|
+
},
|
|
58
|
+
onLanguageChange: (lang) => {
|
|
59
|
+
// e.g. i18n.changeLanguage(lang)
|
|
60
|
+
},
|
|
61
|
+
loadingComponent: <div>Loading…</div>,
|
|
62
|
+
notInTelegramComponent: <div>Open in Telegram</div>,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
66
|
+
return (
|
|
67
|
+
<FullscreenProvider options={{ persistPreference: true }}>
|
|
68
|
+
<TelegramProvider options={telegramOptions}>
|
|
69
|
+
{children}
|
|
70
|
+
</TelegramProvider>
|
|
71
|
+
</FullscreenProvider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Hooks Reference
|
|
79
|
+
|
|
80
|
+
### `useTelegram()`
|
|
81
|
+
Main context hook — gives you everything from the provider.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
const {
|
|
85
|
+
ready, // boolean — is the SDK initialized?
|
|
86
|
+
inTelegram, // boolean — running inside Telegram?
|
|
87
|
+
bypass, // boolean — dev bypass mode?
|
|
88
|
+
webApp, // TgWebApp | null — raw WebApp instance
|
|
89
|
+
user, // TgUser | null
|
|
90
|
+
language, // 'en-US' (TMDB-style locale)
|
|
91
|
+
uiLang, // 'en' (short code)
|
|
92
|
+
colorScheme, // 'light' | 'dark'
|
|
93
|
+
startParam, // string | null
|
|
94
|
+
isRtl, // boolean
|
|
95
|
+
changeLanguage,// (lang: string) => void
|
|
96
|
+
} = useTelegram();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### `useTelegramBackButton()`
|
|
102
|
+
Auto-manages the Back Button based on the current route.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import { useTelegramBackButton } from '@mr-m/telegram-webapp-kit';
|
|
106
|
+
|
|
107
|
+
// Basic — uses browser history.back()
|
|
108
|
+
useTelegramBackButton({ pathname });
|
|
109
|
+
|
|
110
|
+
// Custom back handler
|
|
111
|
+
useTelegramBackButton({
|
|
112
|
+
pathname,
|
|
113
|
+
onBack: () => router.push('/'),
|
|
114
|
+
hideOnRoot: true, // default: true
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### `useTelegramMainButton()`
|
|
121
|
+
Declarative Main Button control.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
useTelegramMainButton({
|
|
125
|
+
text: 'Continue',
|
|
126
|
+
onClick: handleSubmit,
|
|
127
|
+
isVisible: formIsValid,
|
|
128
|
+
isActive: !isLoading,
|
|
129
|
+
showProgress: isLoading,
|
|
130
|
+
color: '#2481cc',
|
|
131
|
+
hasShineEffect: true,
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### `useTelegramSecondaryButton()`
|
|
138
|
+
```tsx
|
|
139
|
+
useTelegramSecondaryButton({
|
|
140
|
+
text: 'Cancel',
|
|
141
|
+
onClick: handleCancel,
|
|
142
|
+
position: 'left',
|
|
143
|
+
isVisible: true,
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### `useTelegramSettingsButton()`
|
|
150
|
+
```tsx
|
|
151
|
+
useTelegramSettingsButton(() => router.push('/settings'));
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### `useHapticFeedback()`
|
|
157
|
+
```tsx
|
|
158
|
+
const haptic = useHapticFeedback();
|
|
159
|
+
|
|
160
|
+
haptic.impact('medium'); // 'light' | 'medium' | 'heavy' | 'rigid' | 'soft'
|
|
161
|
+
haptic.notification('success');// 'error' | 'success' | 'warning'
|
|
162
|
+
haptic.selectionChanged();
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Or use the static shortcut:
|
|
166
|
+
```tsx
|
|
167
|
+
import { haptic } from '@mr-m/telegram-webapp-kit';
|
|
168
|
+
haptic.success();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### `useTelegramTheme()`
|
|
174
|
+
```tsx
|
|
175
|
+
const { colorScheme, themeParams, isDark } = useTelegramTheme();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### `useTelegramViewport()`
|
|
181
|
+
```tsx
|
|
182
|
+
const { height, stableHeight, isExpanded, expand } = useTelegramViewport();
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### `useTelegramFullscreen()`
|
|
188
|
+
```tsx
|
|
189
|
+
const { isFullscreen, isSupported, enter, exit, toggle, error } = useTelegramFullscreen();
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Or use `useFullscreen()` from the `FullscreenProvider` for the full context including safe areas.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### `useSafeArea()`
|
|
197
|
+
```tsx
|
|
198
|
+
const { safeArea, contentSafeArea } = useSafeArea();
|
|
199
|
+
// safeArea.top, .bottom, .left, .right — in pixels
|
|
200
|
+
|
|
201
|
+
// CSS variables are also set automatically:
|
|
202
|
+
// --tg-safe-area-inset-top, --tg-content-safe-area-inset-bottom, etc.
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### `useCloudStorage()`
|
|
208
|
+
Promise-based wrappers over Telegram CloudStorage.
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
const storage = useCloudStorage();
|
|
212
|
+
|
|
213
|
+
await storage.setItem('key', 'value');
|
|
214
|
+
const val = await storage.getItem('key');
|
|
215
|
+
const all = await storage.getItems(['a', 'b']);
|
|
216
|
+
await storage.removeItem('key');
|
|
217
|
+
const keys = await storage.getKeys();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### `useAccelerometer()` / `useGyroscope()` / `useDeviceOrientation()`
|
|
223
|
+
```tsx
|
|
224
|
+
const { x, y, z, isStarted, start, stop } = useAccelerometer({
|
|
225
|
+
refreshRate: 50,
|
|
226
|
+
autoStart: true,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const { x, y, z } = useGyroscope({ autoStart: true });
|
|
230
|
+
|
|
231
|
+
const { alpha, beta, gamma, absolute } = useDeviceOrientation({
|
|
232
|
+
needAbsolute: true,
|
|
233
|
+
autoStart: true,
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
### `useBiometric()`
|
|
240
|
+
```tsx
|
|
241
|
+
const { isAvailable, biometricType, init, requestAccess, authenticate } = useBiometric();
|
|
242
|
+
|
|
243
|
+
await init();
|
|
244
|
+
const granted = await requestAccess('Authenticate to continue');
|
|
245
|
+
const { authenticated, token } = await authenticate('Confirm your identity');
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
### `useLocation()`
|
|
251
|
+
```tsx
|
|
252
|
+
const { isAvailable, isGranted, init, getLocation, openSettings } = useLocation();
|
|
253
|
+
|
|
254
|
+
await init();
|
|
255
|
+
const loc = await getLocation();
|
|
256
|
+
// loc.latitude, loc.longitude, loc.altitude, etc.
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### `useHomeScreen()`
|
|
262
|
+
```tsx
|
|
263
|
+
const { addToHomeScreen, checkStatus } = useHomeScreen();
|
|
264
|
+
const status = await checkStatus(); // 'added' | 'missed' | 'unknown' | 'unsupported'
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### `useIsActive()`
|
|
270
|
+
Tracks whether the Mini App is currently active (foreground).
|
|
271
|
+
```tsx
|
|
272
|
+
const isActive = useIsActive();
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### `useTelegramEvent()`
|
|
278
|
+
Subscribe to any raw Telegram event.
|
|
279
|
+
```tsx
|
|
280
|
+
useTelegramEvent('themeChanged', () => {
|
|
281
|
+
console.log('Theme changed!');
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Utility Functions
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import {
|
|
291
|
+
getWebApp,
|
|
292
|
+
isInTelegram,
|
|
293
|
+
isVersionAtLeast,
|
|
294
|
+
getUserDisplayName,
|
|
295
|
+
getUserAvatarUrl,
|
|
296
|
+
getUserIdentifier,
|
|
297
|
+
getUserInfoWithAvatar,
|
|
298
|
+
getRawUserData,
|
|
299
|
+
openExternalLink,
|
|
300
|
+
openTelegramLink,
|
|
301
|
+
tgLangToTmdb,
|
|
302
|
+
tgLangToUi,
|
|
303
|
+
isRtlLang,
|
|
304
|
+
SUPPORTED_LANGS,
|
|
305
|
+
haptic,
|
|
306
|
+
cloudStorage, // Promise-based static helpers
|
|
307
|
+
dialog, // Promise-based alert/confirm/popup
|
|
308
|
+
readClipboard,
|
|
309
|
+
openInvoice,
|
|
310
|
+
scanQr,
|
|
311
|
+
biometric, // Static promise helpers
|
|
312
|
+
location, // Static promise helpers
|
|
313
|
+
} from '@mr-m/telegram-webapp-kit';
|
|
314
|
+
|
|
315
|
+
// Examples
|
|
316
|
+
const wa = getWebApp();
|
|
317
|
+
const user = getRawUserData();
|
|
318
|
+
const { displayName, avatarUrl } = getUserInfoWithAvatar();
|
|
319
|
+
|
|
320
|
+
await dialog.alert('Hello!');
|
|
321
|
+
const confirmed = await dialog.confirm('Are you sure?');
|
|
322
|
+
const buttonId = await dialog.popup({ message: 'Choose', buttons: [{ id: 'a', text: 'Option A' }] });
|
|
323
|
+
|
|
324
|
+
const status = await openInvoice('https://...');
|
|
325
|
+
const qrText = await scanQr('Scan the code');
|
|
326
|
+
const clipboard = await readClipboard();
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Start Param Routing
|
|
332
|
+
|
|
333
|
+
If you want to handle deep links via `start_param`, use `useTelegramStartParam`:
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
import { useTelegramStartParam } from '@mr-m/telegram-webapp-kit';
|
|
337
|
+
|
|
338
|
+
function App() {
|
|
339
|
+
const startParam = useTelegramStartParam();
|
|
340
|
+
|
|
341
|
+
useEffect(() => {
|
|
342
|
+
if (startParam === 'premium') router.push('/upgrade');
|
|
343
|
+
}, [startParam]);
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## TypeScript
|
|
350
|
+
|
|
351
|
+
All interfaces are exported. The most useful ones:
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
import type {
|
|
355
|
+
TgUser,
|
|
356
|
+
TgWebApp,
|
|
357
|
+
TgThemeParams,
|
|
358
|
+
SafeAreaInset,
|
|
359
|
+
LocationData,
|
|
360
|
+
WebAppEventType,
|
|
361
|
+
PopupParams,
|
|
362
|
+
TelegramContextValue,
|
|
363
|
+
TelegramProviderOptions,
|
|
364
|
+
} from '@mr-m/telegram-webapp-kit';
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Dev Bypass
|
|
370
|
+
|
|
371
|
+
Outside Telegram, the provider shows `notInTelegramComponent`.
|
|
372
|
+
In `development` or when `?bypass` is in the URL, it renders normally so you can develop locally.
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
http://localhost:3000?bypass
|
|
376
|
+
```
|