@tma.js/sdk 0.11.3
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/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/lib/browser.js +2 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/index.cjs +2 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/types/components/BackButton/BackButton.d.ts +44 -0
- package/dist/types/components/BackButton/index.d.ts +2 -0
- package/dist/types/components/BackButton/types.d.ts +9 -0
- package/dist/types/components/ClosingBehaviour/ClosingBehaviour.d.ts +35 -0
- package/dist/types/components/ClosingBehaviour/index.d.ts +2 -0
- package/dist/types/components/ClosingBehaviour/types.d.ts +7 -0
- package/dist/types/components/CloudStorage/CloudStorage.d.ts +47 -0
- package/dist/types/components/CloudStorage/index.d.ts +1 -0
- package/dist/types/components/HapticFeedback/HapticFeedback.d.ts +37 -0
- package/dist/types/components/HapticFeedback/index.d.ts +1 -0
- package/dist/types/components/InitData/InitData.d.ts +52 -0
- package/dist/types/components/InitData/index.d.ts +1 -0
- package/dist/types/components/MainButton/MainButton.d.ts +114 -0
- package/dist/types/components/MainButton/index.d.ts +2 -0
- package/dist/types/components/MainButton/types.d.ts +15 -0
- package/dist/types/components/Popup/Popup.d.ts +44 -0
- package/dist/types/components/Popup/index.d.ts +2 -0
- package/dist/types/components/Popup/types.d.ts +60 -0
- package/dist/types/components/Popup/utils.d.ts +7 -0
- package/dist/types/components/QRScanner/QRScanner.d.ts +40 -0
- package/dist/types/components/QRScanner/index.d.ts +2 -0
- package/dist/types/components/QRScanner/types.d.ts +7 -0
- package/dist/types/components/ThemeParams/ThemeParams.d.ts +73 -0
- package/dist/types/components/ThemeParams/index.d.ts +2 -0
- package/dist/types/components/ThemeParams/types.d.ts +9 -0
- package/dist/types/components/Viewport/Viewport.d.ts +108 -0
- package/dist/types/components/Viewport/index.d.ts +2 -0
- package/dist/types/components/Viewport/types.d.ts +10 -0
- package/dist/types/components/WebApp/WebApp.d.ts +145 -0
- package/dist/types/components/WebApp/index.d.ts +2 -0
- package/dist/types/components/WebApp/types.d.ts +11 -0
- package/dist/types/components/index.d.ts +11 -0
- package/dist/types/env.d.ts +8 -0
- package/dist/types/errors/MethodNotSupportedError.d.ts +6 -0
- package/dist/types/errors/ParameterNotSupportedError.d.ts +6 -0
- package/dist/types/errors/index.d.ts +2 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/init/creators/createBackButton.d.ts +9 -0
- package/dist/types/init/creators/createClosingBehavior.d.ts +8 -0
- package/dist/types/init/creators/createMainButton.d.ts +11 -0
- package/dist/types/init/creators/createPostEvent.d.ts +7 -0
- package/dist/types/init/creators/createRequestIdGenerator.d.ts +5 -0
- package/dist/types/init/creators/createSyncedThemeParams.d.ts +7 -0
- package/dist/types/init/creators/createViewport.d.ts +10 -0
- package/dist/types/init/creators/createWebApp.d.ts +14 -0
- package/dist/types/init/creators/index.d.ts +8 -0
- package/dist/types/init/css.d.ts +57 -0
- package/dist/types/init/index.d.ts +2 -0
- package/dist/types/init/init.d.ts +6 -0
- package/dist/types/init/types.d.ts +107 -0
- package/dist/types/launch-params.d.ts +20 -0
- package/dist/types/state/State.d.ts +15 -0
- package/dist/types/state/index.d.ts +2 -0
- package/dist/types/state/types.d.ts +30 -0
- package/dist/types/storage.d.ts +48 -0
- package/dist/types/supports.d.ts +22 -0
- package/dist/types/theme-params.d.ts +18 -0
- package/dist/types/types.d.ts +14 -0
- package/dist/types/url.d.ts +7 -0
- package/package.json +67 -0
- package/src/components/BackButton/BackButton.ts +90 -0
- package/src/components/BackButton/index.ts +2 -0
- package/src/components/BackButton/types.ts +13 -0
- package/src/components/ClosingBehaviour/ClosingBehaviour.ts +62 -0
- package/src/components/ClosingBehaviour/index.ts +6 -0
- package/src/components/ClosingBehaviour/types.ts +12 -0
- package/src/components/CloudStorage/CloudStorage.ts +135 -0
- package/src/components/CloudStorage/index.ts +1 -0
- package/src/components/HapticFeedback/HapticFeedback.ts +62 -0
- package/src/components/HapticFeedback/index.ts +1 -0
- package/src/components/InitData/InitData.ts +116 -0
- package/src/components/InitData/index.ts +1 -0
- package/src/components/MainButton/MainButton.ts +243 -0
- package/src/components/MainButton/index.ts +2 -0
- package/src/components/MainButton/types.ts +20 -0
- package/src/components/Popup/Popup.ts +81 -0
- package/src/components/Popup/index.ts +8 -0
- package/src/components/Popup/types.ts +69 -0
- package/src/components/Popup/utils.ts +59 -0
- package/src/components/QRScanner/QRScanner.ts +87 -0
- package/src/components/QRScanner/index.ts +2 -0
- package/src/components/QRScanner/types.ts +11 -0
- package/src/components/ThemeParams/ThemeParams.ts +154 -0
- package/src/components/ThemeParams/index.ts +2 -0
- package/src/components/ThemeParams/types.ts +18 -0
- package/src/components/Viewport/Viewport.ts +197 -0
- package/src/components/Viewport/index.ts +2 -0
- package/src/components/Viewport/types.ts +14 -0
- package/src/components/WebApp/WebApp.ts +310 -0
- package/src/components/WebApp/index.ts +2 -0
- package/src/components/WebApp/types.ts +17 -0
- package/src/components/index.ts +11 -0
- package/src/env.ts +17 -0
- package/src/errors/MethodNotSupportedError.ts +9 -0
- package/src/errors/ParameterNotSupportedError.ts +9 -0
- package/src/errors/index.ts +2 -0
- package/src/index.ts +8 -0
- package/src/init/creators/createBackButton.ts +22 -0
- package/src/init/creators/createClosingBehavior.ts +22 -0
- package/src/init/creators/createMainButton.ts +56 -0
- package/src/init/creators/createPostEvent.ts +36 -0
- package/src/init/creators/createRequestIdGenerator.ts +13 -0
- package/src/init/creators/createSyncedThemeParams.ts +14 -0
- package/src/init/creators/createViewport.ts +50 -0
- package/src/init/creators/createWebApp.ts +49 -0
- package/src/init/creators/index.ts +8 -0
- package/src/init/css.ts +166 -0
- package/src/init/index.ts +2 -0
- package/src/init/init.ts +160 -0
- package/src/init/types.ts +133 -0
- package/src/launch-params.ts +70 -0
- package/src/state/State.ts +53 -0
- package/src/state/index.ts +2 -0
- package/src/state/types.ts +34 -0
- package/src/storage.ts +65 -0
- package/src/supports.ts +44 -0
- package/src/theme-params.ts +34 -0
- package/src/types.ts +28 -0
- package/src/url.ts +24 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { EventEmitter } from '@tma.js/event-emitter';
|
|
2
|
+
import { compareVersions, type Version } from '@tma.js/utils';
|
|
3
|
+
import { isRGB, isColorDark, type RGB } from '@tma.js/colors';
|
|
4
|
+
import {
|
|
5
|
+
postEvent as defaultPostEvent,
|
|
6
|
+
supports,
|
|
7
|
+
request,
|
|
8
|
+
type PhoneRequestedStatus,
|
|
9
|
+
type WriteAccessRequestedStatus,
|
|
10
|
+
type InvoiceStatus,
|
|
11
|
+
type PostEvent,
|
|
12
|
+
} from '@tma.js/bridge';
|
|
13
|
+
|
|
14
|
+
import { formatURL } from '../../url.js';
|
|
15
|
+
import { State } from '../../state/index.js';
|
|
16
|
+
import { createSupportsFunc, createSupportsParamFunc, type SupportsFunc } from '../../supports.js';
|
|
17
|
+
|
|
18
|
+
import type { ColorScheme, Platform } from '../../types.js';
|
|
19
|
+
import type { WebAppEvents, WebAppHeaderColor, WebAppState } from './types.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Provides common Web Apps functionality not covered by other system
|
|
23
|
+
* components.
|
|
24
|
+
*/
|
|
25
|
+
export class WebApp {
|
|
26
|
+
private readonly ee = new EventEmitter<WebAppEvents>();
|
|
27
|
+
|
|
28
|
+
private readonly state: State<WebAppState>;
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
headerColor: WebAppHeaderColor,
|
|
32
|
+
backgroundColor: RGB,
|
|
33
|
+
private readonly currentVersion: Version,
|
|
34
|
+
private readonly currentPlatform: Platform,
|
|
35
|
+
private readonly createRequestId: () => string,
|
|
36
|
+
private readonly postEvent: PostEvent = defaultPostEvent,
|
|
37
|
+
) {
|
|
38
|
+
this.state = new State({
|
|
39
|
+
backgroundColor,
|
|
40
|
+
headerColor,
|
|
41
|
+
}, this.ee);
|
|
42
|
+
this.supports = createSupportsFunc(currentVersion, {
|
|
43
|
+
openInvoice: 'web_app_open_invoice',
|
|
44
|
+
readTextFromClipboard: 'web_app_read_text_from_clipboard',
|
|
45
|
+
setHeaderColor: 'web_app_set_header_color',
|
|
46
|
+
setBackgroundColor: 'web_app_set_background_color',
|
|
47
|
+
requestPhoneAccess: 'web_app_request_phone',
|
|
48
|
+
requestWriteAccess: 'web_app_request_write_access',
|
|
49
|
+
});
|
|
50
|
+
this.supportsParam = createSupportsParamFunc(currentVersion, {
|
|
51
|
+
'setHeaderColor.color': ['web_app_set_header_color', 'color'],
|
|
52
|
+
'openLink.tryInstantView': ['web_app_open_link', 'try_instant_view'],
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns current application background color.
|
|
58
|
+
*/
|
|
59
|
+
get backgroundColor(): RGB {
|
|
60
|
+
return this.state.get('backgroundColor');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns current application color scheme. This value is
|
|
65
|
+
* computed based on the current background color.
|
|
66
|
+
*/
|
|
67
|
+
get colorScheme(): ColorScheme {
|
|
68
|
+
return isColorDark(this.backgroundColor) ? 'dark' : 'light';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Closes the Web App.
|
|
73
|
+
*/
|
|
74
|
+
close(): void {
|
|
75
|
+
this.postEvent('web_app_close');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Returns current application header color.
|
|
80
|
+
*/
|
|
81
|
+
get headerColor(): WebAppHeaderColor {
|
|
82
|
+
return this.state.get('headerColor');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns true if passed version is more than or equal to current
|
|
87
|
+
* Web App version.
|
|
88
|
+
* @param version - compared version.
|
|
89
|
+
*/
|
|
90
|
+
isVersionAtLeast(version: Version): boolean {
|
|
91
|
+
return compareVersions(version, this.version) >= 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Opens a link in an external browser. The Web App will not be closed.
|
|
96
|
+
*
|
|
97
|
+
* Note that this method can be called only in response to the user
|
|
98
|
+
* interaction with the Web App interface (e.g. click inside the Web App
|
|
99
|
+
* or on the main button).
|
|
100
|
+
* @param url - URL to be opened.
|
|
101
|
+
* @param tryInstantView
|
|
102
|
+
*/
|
|
103
|
+
openLink(url: string, tryInstantView?: boolean): void {
|
|
104
|
+
const formattedUrl = formatURL(url);
|
|
105
|
+
|
|
106
|
+
// If method is not supported, we are doing it in legacy way.
|
|
107
|
+
if (!supports('web_app_open_link', this.version)) {
|
|
108
|
+
window.open(formattedUrl, '_blank');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Otherwise, do it normally.
|
|
113
|
+
return this.postEvent('web_app_open_link', {
|
|
114
|
+
url: formattedUrl,
|
|
115
|
+
...(typeof tryInstantView === 'boolean' ? { try_instant_view: tryInstantView } : {}),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Opens a Telegram link inside Telegram app. The Web App will be closed.
|
|
121
|
+
* It expects passing link in full format, with hostname "t.me".
|
|
122
|
+
* @param url - URL to be opened.
|
|
123
|
+
* @throws {Error} URL has not allowed hostname.
|
|
124
|
+
*/
|
|
125
|
+
openTelegramLink(url: string): void {
|
|
126
|
+
const { hostname, pathname, search } = new URL(formatURL(url));
|
|
127
|
+
|
|
128
|
+
if (hostname !== 't.me') {
|
|
129
|
+
throw new Error(`URL has not allowed hostname: ${hostname}. Only "t.me" is allowed`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!supports('web_app_open_tg_link', this.version)) {
|
|
133
|
+
window.location.href = url;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return this.postEvent('web_app_open_tg_link', { path_full: pathname + search });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Opens an invoice using its url. It expects passing link in full format,
|
|
142
|
+
* with hostname "t.me".
|
|
143
|
+
* @param url - invoice URL.
|
|
144
|
+
*/
|
|
145
|
+
async openInvoice(url: string): Promise<InvoiceStatus> {
|
|
146
|
+
// TODO: Allow opening with slug.
|
|
147
|
+
const { hostname, pathname } = new URL(formatURL(url));
|
|
148
|
+
|
|
149
|
+
if (hostname !== 't.me') {
|
|
150
|
+
throw new Error(`Incorrect hostname: ${hostname}`);
|
|
151
|
+
}
|
|
152
|
+
// Valid examples:
|
|
153
|
+
// "/invoice/my-slug"
|
|
154
|
+
// "/$my-slug"
|
|
155
|
+
const match = pathname.match(/^\/(\$|invoice\/)([A-Za-z0-9\-_=]+)$/);
|
|
156
|
+
|
|
157
|
+
if (match === null) {
|
|
158
|
+
throw new Error('Link pathname has incorrect format. Expected to receive "/invoice/slug" or "/$slug"');
|
|
159
|
+
}
|
|
160
|
+
const [, , slug] = match;
|
|
161
|
+
|
|
162
|
+
const result = await request('web_app_open_invoice', { slug }, 'invoice_closed', {
|
|
163
|
+
postEvent: this.postEvent,
|
|
164
|
+
capture: ({ slug: eventSlug }) => slug === eventSlug,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return result.status;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Adds new event listener.
|
|
172
|
+
*/
|
|
173
|
+
on = this.ee.on.bind(this.ee);
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Removes event listener.
|
|
177
|
+
*/
|
|
178
|
+
off = this.ee.off.bind(this.ee);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Returns current Web App platform.
|
|
182
|
+
*/
|
|
183
|
+
get platform(): Platform {
|
|
184
|
+
return this.currentPlatform;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Informs the Telegram app that the Web App is ready to be displayed.
|
|
189
|
+
*
|
|
190
|
+
* It is recommended to call this method as early as possible, as soon as
|
|
191
|
+
* all essential interface elements loaded. Once this method called,
|
|
192
|
+
* the loading placeholder is hidden and the Web App shown.
|
|
193
|
+
*
|
|
194
|
+
* If the method not called, the placeholder will be hidden only when
|
|
195
|
+
* the page fully loaded.
|
|
196
|
+
*/
|
|
197
|
+
ready(): void {
|
|
198
|
+
this.postEvent('web_app_ready');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Reads text from clipboard and returns string or null. null is returned
|
|
203
|
+
* in cases:
|
|
204
|
+
* - Value in clipboard is not text
|
|
205
|
+
* - Access to clipboard is not allowed
|
|
206
|
+
*/
|
|
207
|
+
async readTextFromClipboard(): Promise<string | null> {
|
|
208
|
+
// TODO: Generate request id.
|
|
209
|
+
const { data = null } = await request(
|
|
210
|
+
'web_app_read_text_from_clipboard',
|
|
211
|
+
{ req_id: this.createRequestId() },
|
|
212
|
+
'clipboard_text_received',
|
|
213
|
+
{ postEvent: this.postEvent },
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Requests current user phone access.
|
|
221
|
+
*/
|
|
222
|
+
async requestPhoneAccess(): Promise<PhoneRequestedStatus> {
|
|
223
|
+
const { status } = await request('web_app_request_phone', 'phone_requested', {
|
|
224
|
+
postEvent: this.postEvent,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
return status;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Requests write message access to current user.
|
|
232
|
+
*/
|
|
233
|
+
async requestWriteAccess(): Promise<WriteAccessRequestedStatus> {
|
|
234
|
+
const { status } = await request('web_app_request_write_access', 'write_access_requested', {
|
|
235
|
+
postEvent: this.postEvent,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return status;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* A method used to send data to the bot. When this method called, a
|
|
243
|
+
* service message sent to the bot containing the data of the
|
|
244
|
+
* length up to 4096 bytes, and the Web App closed. See the field
|
|
245
|
+
* `web_app_data` in the class Message.
|
|
246
|
+
*
|
|
247
|
+
* This method is only available for Web Apps launched via a Keyboard button.
|
|
248
|
+
* @param data - data to send to bot.
|
|
249
|
+
* @throws {Error} data has incorrect size.
|
|
250
|
+
*/
|
|
251
|
+
sendData(data: string): void {
|
|
252
|
+
// Firstly, compute passed text size in bytes.
|
|
253
|
+
const { size } = new Blob([data]);
|
|
254
|
+
if (size === 0 || size > 4096) {
|
|
255
|
+
throw new Error(`Passed data has incorrect size: ${size}`);
|
|
256
|
+
}
|
|
257
|
+
this.postEvent('web_app_data_send', { data });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Updates current application header color.
|
|
262
|
+
* FIXME: Has no effect on desktop, works incorrectly on Android.
|
|
263
|
+
* Issues:
|
|
264
|
+
* https://github.com/Telegram-Mini-Apps/tma.js/issues/9
|
|
265
|
+
* https://github.com/Telegram-Mini-Apps/tma.js/issues/8
|
|
266
|
+
* @param color - color key or RGB color.
|
|
267
|
+
*/
|
|
268
|
+
setHeaderColor(color: WebAppHeaderColor) {
|
|
269
|
+
this.postEvent('web_app_set_header_color', isRGB(color) ? { color } : { color_key: color });
|
|
270
|
+
this.state.set('headerColor', color);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Updates current application background color.
|
|
275
|
+
* FIXME: Has no effect on desktop, works incorrectly in Android.
|
|
276
|
+
* Issues:
|
|
277
|
+
* https://github.com/Telegram-Mini-Apps/tma.js/issues/9
|
|
278
|
+
* https://github.com/Telegram-Mini-Apps/tma.js/issues/8
|
|
279
|
+
* @param color - RGB color.
|
|
280
|
+
*/
|
|
281
|
+
setBackgroundColor(color: RGB) {
|
|
282
|
+
this.postEvent('web_app_set_background_color', { color });
|
|
283
|
+
this.state.set('backgroundColor', color);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Checks if specified method is supported by current component.
|
|
288
|
+
*/
|
|
289
|
+
supports: SupportsFunc<
|
|
290
|
+
| 'openInvoice'
|
|
291
|
+
| 'readTextFromClipboard'
|
|
292
|
+
| 'setHeaderColor'
|
|
293
|
+
| 'setBackgroundColor'
|
|
294
|
+
| 'requestWriteAccess'
|
|
295
|
+
| 'requestPhoneAccess'
|
|
296
|
+
>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Checks if specified method parameter is supported by current component.
|
|
300
|
+
*/
|
|
301
|
+
supportsParam: SupportsFunc<'setHeaderColor.color' | 'openLink.tryInstantView'>;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Current Web App version. This property is used by other components to check if
|
|
305
|
+
* some functionality is available on current device.
|
|
306
|
+
*/
|
|
307
|
+
get version(): Version {
|
|
308
|
+
return this.currentVersion;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RGB } from '@tma.js/colors';
|
|
2
|
+
import type { HeaderColorKey } from '@tma.js/bridge';
|
|
3
|
+
|
|
4
|
+
import type { StateEvents } from '../../state/index.js';
|
|
5
|
+
|
|
6
|
+
export type WebAppHeaderColor = HeaderColorKey | RGB;
|
|
7
|
+
|
|
8
|
+
export interface WebAppState {
|
|
9
|
+
backgroundColor: RGB;
|
|
10
|
+
headerColor: WebAppHeaderColor;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type WebAppEvents = StateEvents<WebAppState>;
|
|
14
|
+
|
|
15
|
+
export type WebAppEventName = keyof WebAppEvents;
|
|
16
|
+
|
|
17
|
+
export type WebAppEventListener<E extends WebAppEventName> = WebAppEvents[E];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './BackButton/index.js';
|
|
2
|
+
export * from './ClosingBehaviour/index.js';
|
|
3
|
+
export * from './CloudStorage/index.js';
|
|
4
|
+
export * from './HapticFeedback/index.js';
|
|
5
|
+
export * from './InitData/index.js';
|
|
6
|
+
export * from './MainButton/index.js';
|
|
7
|
+
export * from './Popup/index.js';
|
|
8
|
+
export * from './QRScanner/index.js';
|
|
9
|
+
export * from './ThemeParams/index.js';
|
|
10
|
+
export * from './Viewport/index.js';
|
|
11
|
+
export * from './WebApp/index.js';
|
package/src/env.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { retrieveLaunchParams } from './launch-params.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns true in case, current environment is Telegram Web Apps.
|
|
5
|
+
*
|
|
6
|
+
* `isTWA` utilizes such function as `retrieveLaunchParams`, which attempts to retrieve
|
|
7
|
+
* launch parameters from the current environment.
|
|
8
|
+
* @see retrieveLaunchParams
|
|
9
|
+
*/
|
|
10
|
+
export function isTWA(): boolean {
|
|
11
|
+
try {
|
|
12
|
+
retrieveLaunchParams();
|
|
13
|
+
return true;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown in case, unsupported method was called.
|
|
3
|
+
*/
|
|
4
|
+
export class MethodNotSupportedError extends Error {
|
|
5
|
+
constructor(method: string, version: string) {
|
|
6
|
+
super(`Method "${method}" is not supported in the Web Apps version ${version}.`);
|
|
7
|
+
Object.setPrototypeOf(this, MethodNotSupportedError.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown in case, unsupported parameter was used.
|
|
3
|
+
*/
|
|
4
|
+
export class ParameterUnsupportedError extends Error {
|
|
5
|
+
constructor(method: string, param: string, version: string) {
|
|
6
|
+
super(`Parameter "${param}" in method "${method}" is not supported in the Web Apps version ${version}.`);
|
|
7
|
+
Object.setPrototypeOf(this, ParameterUnsupportedError.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './components/index.js';
|
|
2
|
+
export { init, type InitResult, type InitOptions } from './init/index.js';
|
|
3
|
+
export { MethodNotSupportedError } from './errors/index.js';
|
|
4
|
+
export * from './env.js';
|
|
5
|
+
export * from './launch-params.js';
|
|
6
|
+
export * from './theme-params.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
export * from './url.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
2
|
+
|
|
3
|
+
import { BackButton } from '../../components/index.js';
|
|
4
|
+
|
|
5
|
+
import { getStorageValue, saveStorageValue } from '../../storage.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates BackButton instance using last locally saved data also saving each state in
|
|
9
|
+
* the storage.
|
|
10
|
+
* @param version - platform version.
|
|
11
|
+
* @param postEvent - Bridge postEvent function
|
|
12
|
+
*/
|
|
13
|
+
export function createBackButton(version: string, postEvent: PostEvent): BackButton {
|
|
14
|
+
const { isVisible = false } = getStorageValue('back-button') || {};
|
|
15
|
+
const component = new BackButton(isVisible, version, postEvent);
|
|
16
|
+
|
|
17
|
+
component.on('isVisibleChanged', () => {
|
|
18
|
+
saveStorageValue('back-button', { isVisible: component.isVisible });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return component;
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
2
|
+
|
|
3
|
+
import { ClosingBehaviour } from '../../components/index.js';
|
|
4
|
+
|
|
5
|
+
import { getStorageValue, saveStorageValue } from '../../storage.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates ClosingBehaviour instance using last locally saved data also saving each state in
|
|
9
|
+
* the storage.
|
|
10
|
+
* @param postEvent - Bridge postEvent function
|
|
11
|
+
*/
|
|
12
|
+
export function createClosingBehavior(postEvent: PostEvent): ClosingBehaviour {
|
|
13
|
+
const { isConfirmationNeeded = false } = getStorageValue('closing-behavior') || {};
|
|
14
|
+
|
|
15
|
+
const component = new ClosingBehaviour(isConfirmationNeeded, postEvent);
|
|
16
|
+
|
|
17
|
+
component.on('isConfirmationNeededChanged', () => saveStorageValue('closing-behavior', {
|
|
18
|
+
isConfirmationNeeded: component.isConfirmationNeeded,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
return component;
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { RGB } from '@tma.js/colors';
|
|
2
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
3
|
+
|
|
4
|
+
import { MainButton } from '../../components/index.js';
|
|
5
|
+
|
|
6
|
+
import { getStorageValue, saveStorageValue } from '../../storage.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates MainButton instance using last locally saved data also saving each state in
|
|
10
|
+
* the storage.
|
|
11
|
+
* @param backgroundColor - background color.
|
|
12
|
+
* @param textColor - text color.
|
|
13
|
+
* @param postEvent - Bridge postEvent function
|
|
14
|
+
*/
|
|
15
|
+
export function createMainButton(
|
|
16
|
+
backgroundColor: RGB,
|
|
17
|
+
textColor: RGB,
|
|
18
|
+
postEvent: PostEvent,
|
|
19
|
+
): MainButton {
|
|
20
|
+
const {
|
|
21
|
+
backgroundColor: stateBackgroundColor = backgroundColor,
|
|
22
|
+
isEnabled = false,
|
|
23
|
+
isVisible = false,
|
|
24
|
+
isProgressVisible = false,
|
|
25
|
+
textColor: stateTextColor = textColor,
|
|
26
|
+
text = '',
|
|
27
|
+
} = getStorageValue('main-button') || {};
|
|
28
|
+
|
|
29
|
+
const component = new MainButton(
|
|
30
|
+
stateBackgroundColor,
|
|
31
|
+
isEnabled,
|
|
32
|
+
isVisible,
|
|
33
|
+
isProgressVisible,
|
|
34
|
+
text,
|
|
35
|
+
stateTextColor,
|
|
36
|
+
postEvent,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const saveState = () => saveStorageValue('main-button', {
|
|
40
|
+
backgroundColor: component.backgroundColor,
|
|
41
|
+
isEnabled: component.isEnabled,
|
|
42
|
+
isVisible: component.isVisible,
|
|
43
|
+
isProgressVisible: component.isProgressVisible,
|
|
44
|
+
text: component.text,
|
|
45
|
+
textColor: component.textColor,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
component.on('backgroundColorChanged', saveState);
|
|
49
|
+
component.on('isEnabledChanged', saveState);
|
|
50
|
+
component.on('isVisibleChanged', saveState);
|
|
51
|
+
component.on('isProgressVisibleChanged', saveState);
|
|
52
|
+
component.on('textColorChanged', saveState);
|
|
53
|
+
component.on('textChanged', saveState);
|
|
54
|
+
|
|
55
|
+
return component;
|
|
56
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
supports,
|
|
3
|
+
postEvent as defaultPostEvent,
|
|
4
|
+
detectSupportParams,
|
|
5
|
+
type PostEvent,
|
|
6
|
+
} from '@tma.js/bridge';
|
|
7
|
+
import { isRecord } from '@tma.js/utils';
|
|
8
|
+
|
|
9
|
+
import { MethodNotSupportedError, ParameterUnsupportedError } from '../../errors/index.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates postEvent function.
|
|
13
|
+
* @param checkCompat - should compatibility check be enabled.
|
|
14
|
+
* @param version - platform version.
|
|
15
|
+
*/
|
|
16
|
+
export function createPostEvent(checkCompat: boolean, version: string): PostEvent {
|
|
17
|
+
return checkCompat
|
|
18
|
+
? (method: any, params: any) => {
|
|
19
|
+
// Firstly, check if method itself is supported.
|
|
20
|
+
if (!supports(method, version)) {
|
|
21
|
+
throw new MethodNotSupportedError(method, version);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Method could use parameters, which are supported only in specific versions of TWA.
|
|
25
|
+
if (isRecord(params)) {
|
|
26
|
+
detectSupportParams(method, params).forEach((param) => {
|
|
27
|
+
if (!supports(method as any, param, version)) {
|
|
28
|
+
throw new ParameterUnsupportedError(method, param, version);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return defaultPostEvent(method, params);
|
|
34
|
+
}
|
|
35
|
+
: defaultPostEvent;
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateRequestIdFunc } from '../../types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates function which generated request identifiers.
|
|
5
|
+
*/
|
|
6
|
+
export function createRequestIdGenerator(): CreateRequestIdFunc {
|
|
7
|
+
let requestId = 0;
|
|
8
|
+
|
|
9
|
+
return () => {
|
|
10
|
+
requestId += 1;
|
|
11
|
+
return requestId.toString();
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ThemeParams } from '../../components/index.js';
|
|
2
|
+
|
|
3
|
+
import type { ThemeParamsType } from '../../theme-params.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates synced instance of ThemeParams.
|
|
7
|
+
* @param params - theme parameters.
|
|
8
|
+
*/
|
|
9
|
+
export function createSyncedThemeParams(params: ThemeParamsType): ThemeParams {
|
|
10
|
+
const themeParams = new ThemeParams(params);
|
|
11
|
+
ThemeParams.sync(themeParams);
|
|
12
|
+
|
|
13
|
+
return themeParams;
|
|
14
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
2
|
+
|
|
3
|
+
import { Viewport } from '../../components/index.js';
|
|
4
|
+
|
|
5
|
+
import { getStorageValue, saveStorageValue } from '../../storage.js';
|
|
6
|
+
|
|
7
|
+
import type { Platform } from '../../types.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates Viewport instance using last locally saved data also saving each state in
|
|
11
|
+
* the storage.
|
|
12
|
+
* @param platform - Telegram Web Apps platform name.
|
|
13
|
+
* @param postEvent - Bridge postEvent function
|
|
14
|
+
*/
|
|
15
|
+
export async function createViewport(platform: Platform, postEvent: PostEvent): Promise<Viewport> {
|
|
16
|
+
const {
|
|
17
|
+
height = window.innerHeight,
|
|
18
|
+
stableHeight = window.innerHeight,
|
|
19
|
+
width = window.innerWidth,
|
|
20
|
+
isExpanded = false,
|
|
21
|
+
} = getStorageValue('viewport') || {};
|
|
22
|
+
|
|
23
|
+
const createSynced = () => {
|
|
24
|
+
const viewport = new Viewport(height, width, stableHeight, isExpanded, postEvent);
|
|
25
|
+
Viewport.sync(viewport);
|
|
26
|
+
|
|
27
|
+
return viewport;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// MacOS and Web K versions do not support requesting current viewport information. That's why we
|
|
31
|
+
// should construct Viewport instance by ourselves.
|
|
32
|
+
const component = platform === 'macos' || platform === 'web'
|
|
33
|
+
? createSynced()
|
|
34
|
+
: await Viewport.synced({ postEvent });
|
|
35
|
+
|
|
36
|
+
const saveState = () => saveStorageValue('viewport', {
|
|
37
|
+
height: component.height,
|
|
38
|
+
isExpanded: component.isExpanded,
|
|
39
|
+
stableHeight: component.stableHeight,
|
|
40
|
+
width: component.width,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// TODO: Should probably use throttle for height.
|
|
44
|
+
component.on('heightChanged', saveState);
|
|
45
|
+
component.on('isExpandedChanged', saveState);
|
|
46
|
+
component.on('stableHeightChanged', saveState);
|
|
47
|
+
component.on('widthChanged', saveState);
|
|
48
|
+
|
|
49
|
+
return component;
|
|
50
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RGB } from '@tma.js/colors';
|
|
2
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
3
|
+
|
|
4
|
+
import { WebApp } from '../../components/index.js';
|
|
5
|
+
|
|
6
|
+
import { getStorageValue, saveStorageValue } from '../../storage.js';
|
|
7
|
+
|
|
8
|
+
import type { CreateRequestIdFunc, Platform } from '../../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates WebApp instance using last locally saved data also saving each state in
|
|
12
|
+
* the storage.
|
|
13
|
+
* @param backgroundColor - web app background color.
|
|
14
|
+
* @param version - platform version.
|
|
15
|
+
* @param platform - Telegram Web Apps platform name.
|
|
16
|
+
* @param createRequestId - function which generates request identifiers.
|
|
17
|
+
* @param postEvent - Bridge postEvent function
|
|
18
|
+
*/
|
|
19
|
+
export function createWebApp(
|
|
20
|
+
backgroundColor: RGB,
|
|
21
|
+
version: string,
|
|
22
|
+
platform: Platform,
|
|
23
|
+
createRequestId: CreateRequestIdFunc,
|
|
24
|
+
postEvent: PostEvent,
|
|
25
|
+
): WebApp {
|
|
26
|
+
const {
|
|
27
|
+
backgroundColor: stateBackgroundColor = backgroundColor,
|
|
28
|
+
headerColor = 'bg_color',
|
|
29
|
+
} = getStorageValue('web-app') || {};
|
|
30
|
+
|
|
31
|
+
const component = new WebApp(
|
|
32
|
+
headerColor,
|
|
33
|
+
stateBackgroundColor,
|
|
34
|
+
version,
|
|
35
|
+
platform,
|
|
36
|
+
createRequestId,
|
|
37
|
+
postEvent,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const saveState = () => saveStorageValue('web-app', {
|
|
41
|
+
backgroundColor: component.backgroundColor,
|
|
42
|
+
headerColor: component.headerColor,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
component.on('backgroundColorChanged', saveState);
|
|
46
|
+
component.on('headerColorChanged', saveState);
|
|
47
|
+
|
|
48
|
+
return component;
|
|
49
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './createBackButton.js';
|
|
2
|
+
export * from './createClosingBehavior.js';
|
|
3
|
+
export * from './createMainButton.js';
|
|
4
|
+
export * from './createPostEvent.js';
|
|
5
|
+
export * from './createRequestIdGenerator.js';
|
|
6
|
+
export * from './createSyncedThemeParams.js';
|
|
7
|
+
export * from './createViewport.js';
|
|
8
|
+
export * from './createWebApp.js';
|