├── .eslintignore
├── .eslintrc
├── .github
└── workflows
│ ├── prerelease.yml
│ └── release.yml
├── .gitignore
├── .npmignore
├── .prettierrc
├── LICENSE
├── Readme.md
├── package-lock.json
├── package.json
├── src
├── index.ts
├── react
│ ├── BackButton
│ │ ├── BackButton.tsx
│ │ └── Readme.md
│ ├── BottomBar
│ │ ├── BottomBar.tsx
│ │ └── Readme.md
│ ├── MainButton
│ │ ├── MainButton.tsx
│ │ └── Readme.md
│ ├── SecondaryButton
│ │ ├── Readme.md
│ │ └── SecondaryButton.tsx
│ ├── bottomButton.ts
│ └── index.ts
├── sdk.ts
└── telegram-web-apps.js
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:@typescript-eslint/recommended", "plugin:react/recommended", "prettier"],
3 | "parser": "@typescript-eslint/parser",
4 | "env": {
5 | "node": false,
6 | "browser": true
7 | },
8 | "settings": {
9 | "react": {
10 | "version": "detect"
11 | }
12 | },
13 | "parserOptions": {
14 | "ecmaFeatures": {
15 | "jsx": true
16 | }
17 | },
18 | "ignorePatterns": ["telegram-web-apps.js"],
19 | "rules": {
20 | "react/react-in-jsx-scope": "off"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.github/workflows/prerelease.yml:
--------------------------------------------------------------------------------
1 | name: Prerelease
2 | on:
3 | release:
4 | types: [prereleased]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | contents: read
10 | id-token: write
11 | steps:
12 | - uses: actions/checkout@v4
13 | # Setup .npmrc file to publish to npm
14 | - uses: actions/setup-node@v4
15 | with:
16 | node-version: '18.x'
17 | registry-url: 'https://registry.npmjs.org'
18 | - run: npm ci
19 | - run: npm run build
20 | - run: npm publish --access public --tag beta
21 | env:
22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | release:
4 | types: [released]
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | permissions:
9 | contents: read
10 | id-token: write
11 | steps:
12 | - uses: actions/checkout@v4
13 | # Setup .npmrc file to publish to npm
14 | - uses: actions/setup-node@v4
15 | with:
16 | node-version: '18.x'
17 | registry-url: 'https://registry.npmjs.org'
18 | - run: npm ci
19 | - run: npm run build
20 | - run: npm publish --access public
21 | env:
22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | node_modules/
3 | dist/
4 | *.log
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | node_modules/
3 | tsconfig.json
4 | .eslintrc
5 | .eslintignore
6 | .prettierrc
7 | .gitignore
8 | *.log
9 | .github/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twa-dev/SDK/6bab68c05ca0b0cb5b5c9abe3f13b822ff8d1665/.prettierrc
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Artur Stambultsian
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## SDK
2 | [](https://www.npmjs.com/package/@twa-dev/sdk)
3 |
4 | npm package for [Telegram Web Apps (TWA)](https://core.telegram.org/bots/webapps) SDK.
5 |
6 | ```
7 | npm i @twa-dev/sdk
8 | ```
9 |
10 | ### Motivation
11 | Telegram distributes SDK via [link](https://core.telegram.org/bots/webapps#initializing-web-apps). It's kinda old fashion way to work with a library:
12 |
13 | ```html
14 |
15 |
16 | TWA
17 |
18 |
19 |
22 |
23 |
24 |
25 | ```
26 |
27 | This package allows to work with SDK as with a npm package:
28 |
29 | ```js
30 | import WebApp from '@twa-dev/sdk'
31 |
32 | WebApp.showAlert('Hey there!');
33 | ```
34 |
35 | And yes, it supports TS.
36 |
37 | ### Demo
38 | [Codesandbox](https://codesandbox.io/s/sdk-kj5961)
39 |
40 | ### React
41 | If you use React in your project, check out components that we have prepared for you.
42 | - [MainButton](src/react/MainButton/Readme.md)
43 | - [SecondaryButton](src/react/SecondaryButton/Readme.md)
44 | - [BottomBar](src/react/BottomBar/Readme.md)
45 | - [BackButton](src/react/BackButton/Readme.md)
46 |
47 | These components significantly simplify developer experience.
48 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@twa-dev/sdk",
3 | "version": "8.0.2",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "@twa-dev/sdk",
9 | "version": "8.0.2",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@twa-dev/types": "^8.0.1"
13 | },
14 | "devDependencies": {
15 | "@types/react": "^19.0.8",
16 | "@typescript-eslint/eslint-plugin": "^5.33.0",
17 | "@typescript-eslint/parser": "^5.33.0",
18 | "eslint": "^8.21.0",
19 | "eslint-config-prettier": "^8.5.0",
20 | "eslint-plugin-react": "^7.31.8",
21 | "prettier": "^2.7.1",
22 | "react": "^18.3.1",
23 | "typescript": "^4.7.4"
24 | },
25 | "peerDependencies": {
26 | "react": "^18.0.0 || ^19.0.0"
27 | }
28 | },
29 | "node_modules/@eslint/eslintrc": {
30 | "version": "1.3.0",
31 | "dev": true,
32 | "license": "MIT",
33 | "dependencies": {
34 | "ajv": "^6.12.4",
35 | "debug": "^4.3.2",
36 | "espree": "^9.3.2",
37 | "globals": "^13.15.0",
38 | "ignore": "^5.2.0",
39 | "import-fresh": "^3.2.1",
40 | "js-yaml": "^4.1.0",
41 | "minimatch": "^3.1.2",
42 | "strip-json-comments": "^3.1.1"
43 | },
44 | "engines": {
45 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
46 | }
47 | },
48 | "node_modules/@humanwhocodes/config-array": {
49 | "version": "0.10.4",
50 | "dev": true,
51 | "license": "Apache-2.0",
52 | "dependencies": {
53 | "@humanwhocodes/object-schema": "^1.2.1",
54 | "debug": "^4.1.1",
55 | "minimatch": "^3.0.4"
56 | },
57 | "engines": {
58 | "node": ">=10.10.0"
59 | }
60 | },
61 | "node_modules/@humanwhocodes/gitignore-to-minimatch": {
62 | "version": "1.0.2",
63 | "dev": true,
64 | "license": "Apache-2.0",
65 | "funding": {
66 | "type": "github",
67 | "url": "https://github.com/sponsors/nzakas"
68 | }
69 | },
70 | "node_modules/@humanwhocodes/object-schema": {
71 | "version": "1.2.1",
72 | "dev": true,
73 | "license": "BSD-3-Clause"
74 | },
75 | "node_modules/@nodelib/fs.scandir": {
76 | "version": "2.1.5",
77 | "dev": true,
78 | "license": "MIT",
79 | "dependencies": {
80 | "@nodelib/fs.stat": "2.0.5",
81 | "run-parallel": "^1.1.9"
82 | },
83 | "engines": {
84 | "node": ">= 8"
85 | }
86 | },
87 | "node_modules/@nodelib/fs.stat": {
88 | "version": "2.0.5",
89 | "dev": true,
90 | "license": "MIT",
91 | "engines": {
92 | "node": ">= 8"
93 | }
94 | },
95 | "node_modules/@nodelib/fs.walk": {
96 | "version": "1.2.8",
97 | "dev": true,
98 | "license": "MIT",
99 | "dependencies": {
100 | "@nodelib/fs.scandir": "2.1.5",
101 | "fastq": "^1.6.0"
102 | },
103 | "engines": {
104 | "node": ">= 8"
105 | }
106 | },
107 | "node_modules/@twa-dev/types": {
108 | "version": "8.0.1",
109 | "resolved": "https://registry.npmjs.org/@twa-dev/types/-/types-8.0.1.tgz",
110 | "integrity": "sha512-/m3KiULhI4fdeoI5K9Op9jFbmdPjxaAdrZBJ3BA1fS4lVmKCx9XuLTeumzYeuOW577eHAJWaZkcSpWBOss4Epw=="
111 | },
112 | "node_modules/@types/json-schema": {
113 | "version": "7.0.11",
114 | "dev": true,
115 | "license": "MIT"
116 | },
117 | "node_modules/@types/react": {
118 | "version": "19.0.8",
119 | "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz",
120 | "integrity": "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==",
121 | "dev": true,
122 | "dependencies": {
123 | "csstype": "^3.0.2"
124 | }
125 | },
126 | "node_modules/@typescript-eslint/eslint-plugin": {
127 | "version": "5.33.1",
128 | "dev": true,
129 | "license": "MIT",
130 | "dependencies": {
131 | "@typescript-eslint/scope-manager": "5.33.1",
132 | "@typescript-eslint/type-utils": "5.33.1",
133 | "@typescript-eslint/utils": "5.33.1",
134 | "debug": "^4.3.4",
135 | "functional-red-black-tree": "^1.0.1",
136 | "ignore": "^5.2.0",
137 | "regexpp": "^3.2.0",
138 | "semver": "^7.3.7",
139 | "tsutils": "^3.21.0"
140 | },
141 | "engines": {
142 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
143 | },
144 | "funding": {
145 | "type": "opencollective",
146 | "url": "https://opencollective.com/typescript-eslint"
147 | },
148 | "peerDependencies": {
149 | "@typescript-eslint/parser": "^5.0.0",
150 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
151 | },
152 | "peerDependenciesMeta": {
153 | "typescript": {
154 | "optional": true
155 | }
156 | }
157 | },
158 | "node_modules/@typescript-eslint/parser": {
159 | "version": "5.33.1",
160 | "dev": true,
161 | "license": "BSD-2-Clause",
162 | "dependencies": {
163 | "@typescript-eslint/scope-manager": "5.33.1",
164 | "@typescript-eslint/types": "5.33.1",
165 | "@typescript-eslint/typescript-estree": "5.33.1",
166 | "debug": "^4.3.4"
167 | },
168 | "engines": {
169 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
170 | },
171 | "funding": {
172 | "type": "opencollective",
173 | "url": "https://opencollective.com/typescript-eslint"
174 | },
175 | "peerDependencies": {
176 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
177 | },
178 | "peerDependenciesMeta": {
179 | "typescript": {
180 | "optional": true
181 | }
182 | }
183 | },
184 | "node_modules/@typescript-eslint/scope-manager": {
185 | "version": "5.33.1",
186 | "dev": true,
187 | "license": "MIT",
188 | "dependencies": {
189 | "@typescript-eslint/types": "5.33.1",
190 | "@typescript-eslint/visitor-keys": "5.33.1"
191 | },
192 | "engines": {
193 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
194 | },
195 | "funding": {
196 | "type": "opencollective",
197 | "url": "https://opencollective.com/typescript-eslint"
198 | }
199 | },
200 | "node_modules/@typescript-eslint/type-utils": {
201 | "version": "5.33.1",
202 | "dev": true,
203 | "license": "MIT",
204 | "dependencies": {
205 | "@typescript-eslint/utils": "5.33.1",
206 | "debug": "^4.3.4",
207 | "tsutils": "^3.21.0"
208 | },
209 | "engines": {
210 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
211 | },
212 | "funding": {
213 | "type": "opencollective",
214 | "url": "https://opencollective.com/typescript-eslint"
215 | },
216 | "peerDependencies": {
217 | "eslint": "*"
218 | },
219 | "peerDependenciesMeta": {
220 | "typescript": {
221 | "optional": true
222 | }
223 | }
224 | },
225 | "node_modules/@typescript-eslint/types": {
226 | "version": "5.33.1",
227 | "dev": true,
228 | "license": "MIT",
229 | "engines": {
230 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
231 | },
232 | "funding": {
233 | "type": "opencollective",
234 | "url": "https://opencollective.com/typescript-eslint"
235 | }
236 | },
237 | "node_modules/@typescript-eslint/typescript-estree": {
238 | "version": "5.33.1",
239 | "dev": true,
240 | "license": "BSD-2-Clause",
241 | "dependencies": {
242 | "@typescript-eslint/types": "5.33.1",
243 | "@typescript-eslint/visitor-keys": "5.33.1",
244 | "debug": "^4.3.4",
245 | "globby": "^11.1.0",
246 | "is-glob": "^4.0.3",
247 | "semver": "^7.3.7",
248 | "tsutils": "^3.21.0"
249 | },
250 | "engines": {
251 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
252 | },
253 | "funding": {
254 | "type": "opencollective",
255 | "url": "https://opencollective.com/typescript-eslint"
256 | },
257 | "peerDependenciesMeta": {
258 | "typescript": {
259 | "optional": true
260 | }
261 | }
262 | },
263 | "node_modules/@typescript-eslint/utils": {
264 | "version": "5.33.1",
265 | "dev": true,
266 | "license": "MIT",
267 | "dependencies": {
268 | "@types/json-schema": "^7.0.9",
269 | "@typescript-eslint/scope-manager": "5.33.1",
270 | "@typescript-eslint/types": "5.33.1",
271 | "@typescript-eslint/typescript-estree": "5.33.1",
272 | "eslint-scope": "^5.1.1",
273 | "eslint-utils": "^3.0.0"
274 | },
275 | "engines": {
276 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
277 | },
278 | "funding": {
279 | "type": "opencollective",
280 | "url": "https://opencollective.com/typescript-eslint"
281 | },
282 | "peerDependencies": {
283 | "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
284 | }
285 | },
286 | "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": {
287 | "version": "5.1.1",
288 | "dev": true,
289 | "license": "BSD-2-Clause",
290 | "dependencies": {
291 | "esrecurse": "^4.3.0",
292 | "estraverse": "^4.1.1"
293 | },
294 | "engines": {
295 | "node": ">=8.0.0"
296 | }
297 | },
298 | "node_modules/@typescript-eslint/utils/node_modules/estraverse": {
299 | "version": "4.3.0",
300 | "dev": true,
301 | "license": "BSD-2-Clause",
302 | "engines": {
303 | "node": ">=4.0"
304 | }
305 | },
306 | "node_modules/@typescript-eslint/visitor-keys": {
307 | "version": "5.33.1",
308 | "dev": true,
309 | "license": "MIT",
310 | "dependencies": {
311 | "@typescript-eslint/types": "5.33.1",
312 | "eslint-visitor-keys": "^3.3.0"
313 | },
314 | "engines": {
315 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
316 | },
317 | "funding": {
318 | "type": "opencollective",
319 | "url": "https://opencollective.com/typescript-eslint"
320 | }
321 | },
322 | "node_modules/acorn": {
323 | "version": "8.8.0",
324 | "dev": true,
325 | "license": "MIT",
326 | "bin": {
327 | "acorn": "bin/acorn"
328 | },
329 | "engines": {
330 | "node": ">=0.4.0"
331 | }
332 | },
333 | "node_modules/acorn-jsx": {
334 | "version": "5.3.2",
335 | "dev": true,
336 | "license": "MIT",
337 | "peerDependencies": {
338 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
339 | }
340 | },
341 | "node_modules/ajv": {
342 | "version": "6.12.6",
343 | "dev": true,
344 | "license": "MIT",
345 | "dependencies": {
346 | "fast-deep-equal": "^3.1.1",
347 | "fast-json-stable-stringify": "^2.0.0",
348 | "json-schema-traverse": "^0.4.1",
349 | "uri-js": "^4.2.2"
350 | },
351 | "funding": {
352 | "type": "github",
353 | "url": "https://github.com/sponsors/epoberezkin"
354 | }
355 | },
356 | "node_modules/ansi-regex": {
357 | "version": "5.0.1",
358 | "dev": true,
359 | "license": "MIT",
360 | "engines": {
361 | "node": ">=8"
362 | }
363 | },
364 | "node_modules/ansi-styles": {
365 | "version": "4.3.0",
366 | "dev": true,
367 | "license": "MIT",
368 | "dependencies": {
369 | "color-convert": "^2.0.1"
370 | },
371 | "engines": {
372 | "node": ">=8"
373 | },
374 | "funding": {
375 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
376 | }
377 | },
378 | "node_modules/argparse": {
379 | "version": "2.0.1",
380 | "dev": true,
381 | "license": "Python-2.0"
382 | },
383 | "node_modules/array-includes": {
384 | "version": "3.1.5",
385 | "dev": true,
386 | "license": "MIT",
387 | "dependencies": {
388 | "call-bind": "^1.0.2",
389 | "define-properties": "^1.1.4",
390 | "es-abstract": "^1.19.5",
391 | "get-intrinsic": "^1.1.1",
392 | "is-string": "^1.0.7"
393 | },
394 | "engines": {
395 | "node": ">= 0.4"
396 | },
397 | "funding": {
398 | "url": "https://github.com/sponsors/ljharb"
399 | }
400 | },
401 | "node_modules/array-union": {
402 | "version": "2.1.0",
403 | "dev": true,
404 | "license": "MIT",
405 | "engines": {
406 | "node": ">=8"
407 | }
408 | },
409 | "node_modules/array.prototype.flatmap": {
410 | "version": "1.3.0",
411 | "dev": true,
412 | "license": "MIT",
413 | "dependencies": {
414 | "call-bind": "^1.0.2",
415 | "define-properties": "^1.1.3",
416 | "es-abstract": "^1.19.2",
417 | "es-shim-unscopables": "^1.0.0"
418 | },
419 | "engines": {
420 | "node": ">= 0.4"
421 | },
422 | "funding": {
423 | "url": "https://github.com/sponsors/ljharb"
424 | }
425 | },
426 | "node_modules/balanced-match": {
427 | "version": "1.0.2",
428 | "dev": true,
429 | "license": "MIT"
430 | },
431 | "node_modules/brace-expansion": {
432 | "version": "1.1.11",
433 | "dev": true,
434 | "license": "MIT",
435 | "dependencies": {
436 | "balanced-match": "^1.0.0",
437 | "concat-map": "0.0.1"
438 | }
439 | },
440 | "node_modules/braces": {
441 | "version": "3.0.2",
442 | "dev": true,
443 | "license": "MIT",
444 | "dependencies": {
445 | "fill-range": "^7.0.1"
446 | },
447 | "engines": {
448 | "node": ">=8"
449 | }
450 | },
451 | "node_modules/call-bind": {
452 | "version": "1.0.2",
453 | "dev": true,
454 | "license": "MIT",
455 | "dependencies": {
456 | "function-bind": "^1.1.1",
457 | "get-intrinsic": "^1.0.2"
458 | },
459 | "funding": {
460 | "url": "https://github.com/sponsors/ljharb"
461 | }
462 | },
463 | "node_modules/callsites": {
464 | "version": "3.1.0",
465 | "dev": true,
466 | "license": "MIT",
467 | "engines": {
468 | "node": ">=6"
469 | }
470 | },
471 | "node_modules/chalk": {
472 | "version": "4.1.2",
473 | "dev": true,
474 | "license": "MIT",
475 | "dependencies": {
476 | "ansi-styles": "^4.1.0",
477 | "supports-color": "^7.1.0"
478 | },
479 | "engines": {
480 | "node": ">=10"
481 | },
482 | "funding": {
483 | "url": "https://github.com/chalk/chalk?sponsor=1"
484 | }
485 | },
486 | "node_modules/color-convert": {
487 | "version": "2.0.1",
488 | "dev": true,
489 | "license": "MIT",
490 | "dependencies": {
491 | "color-name": "~1.1.4"
492 | },
493 | "engines": {
494 | "node": ">=7.0.0"
495 | }
496 | },
497 | "node_modules/color-name": {
498 | "version": "1.1.4",
499 | "dev": true,
500 | "license": "MIT"
501 | },
502 | "node_modules/concat-map": {
503 | "version": "0.0.1",
504 | "dev": true,
505 | "license": "MIT"
506 | },
507 | "node_modules/cross-spawn": {
508 | "version": "7.0.3",
509 | "dev": true,
510 | "license": "MIT",
511 | "dependencies": {
512 | "path-key": "^3.1.0",
513 | "shebang-command": "^2.0.0",
514 | "which": "^2.0.1"
515 | },
516 | "engines": {
517 | "node": ">= 8"
518 | }
519 | },
520 | "node_modules/csstype": {
521 | "version": "3.1.0",
522 | "dev": true,
523 | "license": "MIT"
524 | },
525 | "node_modules/debug": {
526 | "version": "4.3.4",
527 | "dev": true,
528 | "license": "MIT",
529 | "dependencies": {
530 | "ms": "2.1.2"
531 | },
532 | "engines": {
533 | "node": ">=6.0"
534 | },
535 | "peerDependenciesMeta": {
536 | "supports-color": {
537 | "optional": true
538 | }
539 | }
540 | },
541 | "node_modules/deep-is": {
542 | "version": "0.1.4",
543 | "dev": true,
544 | "license": "MIT"
545 | },
546 | "node_modules/define-properties": {
547 | "version": "1.1.4",
548 | "dev": true,
549 | "license": "MIT",
550 | "dependencies": {
551 | "has-property-descriptors": "^1.0.0",
552 | "object-keys": "^1.1.1"
553 | },
554 | "engines": {
555 | "node": ">= 0.4"
556 | },
557 | "funding": {
558 | "url": "https://github.com/sponsors/ljharb"
559 | }
560 | },
561 | "node_modules/dir-glob": {
562 | "version": "3.0.1",
563 | "dev": true,
564 | "license": "MIT",
565 | "dependencies": {
566 | "path-type": "^4.0.0"
567 | },
568 | "engines": {
569 | "node": ">=8"
570 | }
571 | },
572 | "node_modules/doctrine": {
573 | "version": "2.1.0",
574 | "dev": true,
575 | "license": "Apache-2.0",
576 | "dependencies": {
577 | "esutils": "^2.0.2"
578 | },
579 | "engines": {
580 | "node": ">=0.10.0"
581 | }
582 | },
583 | "node_modules/es-abstract": {
584 | "version": "1.20.2",
585 | "dev": true,
586 | "license": "MIT",
587 | "dependencies": {
588 | "call-bind": "^1.0.2",
589 | "es-to-primitive": "^1.2.1",
590 | "function-bind": "^1.1.1",
591 | "function.prototype.name": "^1.1.5",
592 | "get-intrinsic": "^1.1.2",
593 | "get-symbol-description": "^1.0.0",
594 | "has": "^1.0.3",
595 | "has-property-descriptors": "^1.0.0",
596 | "has-symbols": "^1.0.3",
597 | "internal-slot": "^1.0.3",
598 | "is-callable": "^1.2.4",
599 | "is-negative-zero": "^2.0.2",
600 | "is-regex": "^1.1.4",
601 | "is-shared-array-buffer": "^1.0.2",
602 | "is-string": "^1.0.7",
603 | "is-weakref": "^1.0.2",
604 | "object-inspect": "^1.12.2",
605 | "object-keys": "^1.1.1",
606 | "object.assign": "^4.1.4",
607 | "regexp.prototype.flags": "^1.4.3",
608 | "string.prototype.trimend": "^1.0.5",
609 | "string.prototype.trimstart": "^1.0.5",
610 | "unbox-primitive": "^1.0.2"
611 | },
612 | "engines": {
613 | "node": ">= 0.4"
614 | },
615 | "funding": {
616 | "url": "https://github.com/sponsors/ljharb"
617 | }
618 | },
619 | "node_modules/es-shim-unscopables": {
620 | "version": "1.0.0",
621 | "dev": true,
622 | "license": "MIT",
623 | "dependencies": {
624 | "has": "^1.0.3"
625 | }
626 | },
627 | "node_modules/es-to-primitive": {
628 | "version": "1.2.1",
629 | "dev": true,
630 | "license": "MIT",
631 | "dependencies": {
632 | "is-callable": "^1.1.4",
633 | "is-date-object": "^1.0.1",
634 | "is-symbol": "^1.0.2"
635 | },
636 | "engines": {
637 | "node": ">= 0.4"
638 | },
639 | "funding": {
640 | "url": "https://github.com/sponsors/ljharb"
641 | }
642 | },
643 | "node_modules/escape-string-regexp": {
644 | "version": "4.0.0",
645 | "dev": true,
646 | "license": "MIT",
647 | "engines": {
648 | "node": ">=10"
649 | },
650 | "funding": {
651 | "url": "https://github.com/sponsors/sindresorhus"
652 | }
653 | },
654 | "node_modules/eslint": {
655 | "version": "8.22.0",
656 | "dev": true,
657 | "license": "MIT",
658 | "dependencies": {
659 | "@eslint/eslintrc": "^1.3.0",
660 | "@humanwhocodes/config-array": "^0.10.4",
661 | "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
662 | "ajv": "^6.10.0",
663 | "chalk": "^4.0.0",
664 | "cross-spawn": "^7.0.2",
665 | "debug": "^4.3.2",
666 | "doctrine": "^3.0.0",
667 | "escape-string-regexp": "^4.0.0",
668 | "eslint-scope": "^7.1.1",
669 | "eslint-utils": "^3.0.0",
670 | "eslint-visitor-keys": "^3.3.0",
671 | "espree": "^9.3.3",
672 | "esquery": "^1.4.0",
673 | "esutils": "^2.0.2",
674 | "fast-deep-equal": "^3.1.3",
675 | "file-entry-cache": "^6.0.1",
676 | "find-up": "^5.0.0",
677 | "functional-red-black-tree": "^1.0.1",
678 | "glob-parent": "^6.0.1",
679 | "globals": "^13.15.0",
680 | "globby": "^11.1.0",
681 | "grapheme-splitter": "^1.0.4",
682 | "ignore": "^5.2.0",
683 | "import-fresh": "^3.0.0",
684 | "imurmurhash": "^0.1.4",
685 | "is-glob": "^4.0.0",
686 | "js-yaml": "^4.1.0",
687 | "json-stable-stringify-without-jsonify": "^1.0.1",
688 | "levn": "^0.4.1",
689 | "lodash.merge": "^4.6.2",
690 | "minimatch": "^3.1.2",
691 | "natural-compare": "^1.4.0",
692 | "optionator": "^0.9.1",
693 | "regexpp": "^3.2.0",
694 | "strip-ansi": "^6.0.1",
695 | "strip-json-comments": "^3.1.0",
696 | "text-table": "^0.2.0",
697 | "v8-compile-cache": "^2.0.3"
698 | },
699 | "bin": {
700 | "eslint": "bin/eslint.js"
701 | },
702 | "engines": {
703 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
704 | },
705 | "funding": {
706 | "url": "https://opencollective.com/eslint"
707 | }
708 | },
709 | "node_modules/eslint-config-prettier": {
710 | "version": "8.5.0",
711 | "dev": true,
712 | "license": "MIT",
713 | "bin": {
714 | "eslint-config-prettier": "bin/cli.js"
715 | },
716 | "peerDependencies": {
717 | "eslint": ">=7.0.0"
718 | }
719 | },
720 | "node_modules/eslint-plugin-react": {
721 | "version": "7.31.8",
722 | "dev": true,
723 | "license": "MIT",
724 | "dependencies": {
725 | "array-includes": "^3.1.5",
726 | "array.prototype.flatmap": "^1.3.0",
727 | "doctrine": "^2.1.0",
728 | "estraverse": "^5.3.0",
729 | "jsx-ast-utils": "^2.4.1 || ^3.0.0",
730 | "minimatch": "^3.1.2",
731 | "object.entries": "^1.1.5",
732 | "object.fromentries": "^2.0.5",
733 | "object.hasown": "^1.1.1",
734 | "object.values": "^1.1.5",
735 | "prop-types": "^15.8.1",
736 | "resolve": "^2.0.0-next.3",
737 | "semver": "^6.3.0",
738 | "string.prototype.matchall": "^4.0.7"
739 | },
740 | "engines": {
741 | "node": ">=4"
742 | },
743 | "peerDependencies": {
744 | "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
745 | }
746 | },
747 | "node_modules/eslint-plugin-react/node_modules/semver": {
748 | "version": "6.3.0",
749 | "dev": true,
750 | "license": "ISC",
751 | "bin": {
752 | "semver": "bin/semver.js"
753 | }
754 | },
755 | "node_modules/eslint-scope": {
756 | "version": "7.1.1",
757 | "dev": true,
758 | "license": "BSD-2-Clause",
759 | "dependencies": {
760 | "esrecurse": "^4.3.0",
761 | "estraverse": "^5.2.0"
762 | },
763 | "engines": {
764 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
765 | }
766 | },
767 | "node_modules/eslint-utils": {
768 | "version": "3.0.0",
769 | "dev": true,
770 | "license": "MIT",
771 | "dependencies": {
772 | "eslint-visitor-keys": "^2.0.0"
773 | },
774 | "engines": {
775 | "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
776 | },
777 | "funding": {
778 | "url": "https://github.com/sponsors/mysticatea"
779 | },
780 | "peerDependencies": {
781 | "eslint": ">=5"
782 | }
783 | },
784 | "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
785 | "version": "2.1.0",
786 | "dev": true,
787 | "license": "Apache-2.0",
788 | "engines": {
789 | "node": ">=10"
790 | }
791 | },
792 | "node_modules/eslint-visitor-keys": {
793 | "version": "3.3.0",
794 | "dev": true,
795 | "license": "Apache-2.0",
796 | "engines": {
797 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
798 | }
799 | },
800 | "node_modules/eslint/node_modules/doctrine": {
801 | "version": "3.0.0",
802 | "dev": true,
803 | "license": "Apache-2.0",
804 | "dependencies": {
805 | "esutils": "^2.0.2"
806 | },
807 | "engines": {
808 | "node": ">=6.0.0"
809 | }
810 | },
811 | "node_modules/espree": {
812 | "version": "9.3.3",
813 | "dev": true,
814 | "license": "BSD-2-Clause",
815 | "dependencies": {
816 | "acorn": "^8.8.0",
817 | "acorn-jsx": "^5.3.2",
818 | "eslint-visitor-keys": "^3.3.0"
819 | },
820 | "engines": {
821 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
822 | },
823 | "funding": {
824 | "url": "https://opencollective.com/eslint"
825 | }
826 | },
827 | "node_modules/esquery": {
828 | "version": "1.4.0",
829 | "dev": true,
830 | "license": "BSD-3-Clause",
831 | "dependencies": {
832 | "estraverse": "^5.1.0"
833 | },
834 | "engines": {
835 | "node": ">=0.10"
836 | }
837 | },
838 | "node_modules/esrecurse": {
839 | "version": "4.3.0",
840 | "dev": true,
841 | "license": "BSD-2-Clause",
842 | "dependencies": {
843 | "estraverse": "^5.2.0"
844 | },
845 | "engines": {
846 | "node": ">=4.0"
847 | }
848 | },
849 | "node_modules/estraverse": {
850 | "version": "5.3.0",
851 | "dev": true,
852 | "license": "BSD-2-Clause",
853 | "engines": {
854 | "node": ">=4.0"
855 | }
856 | },
857 | "node_modules/esutils": {
858 | "version": "2.0.3",
859 | "dev": true,
860 | "license": "BSD-2-Clause",
861 | "engines": {
862 | "node": ">=0.10.0"
863 | }
864 | },
865 | "node_modules/fast-deep-equal": {
866 | "version": "3.1.3",
867 | "dev": true,
868 | "license": "MIT"
869 | },
870 | "node_modules/fast-glob": {
871 | "version": "3.2.11",
872 | "dev": true,
873 | "license": "MIT",
874 | "dependencies": {
875 | "@nodelib/fs.stat": "^2.0.2",
876 | "@nodelib/fs.walk": "^1.2.3",
877 | "glob-parent": "^5.1.2",
878 | "merge2": "^1.3.0",
879 | "micromatch": "^4.0.4"
880 | },
881 | "engines": {
882 | "node": ">=8.6.0"
883 | }
884 | },
885 | "node_modules/fast-glob/node_modules/glob-parent": {
886 | "version": "5.1.2",
887 | "dev": true,
888 | "license": "ISC",
889 | "dependencies": {
890 | "is-glob": "^4.0.1"
891 | },
892 | "engines": {
893 | "node": ">= 6"
894 | }
895 | },
896 | "node_modules/fast-json-stable-stringify": {
897 | "version": "2.1.0",
898 | "dev": true,
899 | "license": "MIT"
900 | },
901 | "node_modules/fast-levenshtein": {
902 | "version": "2.0.6",
903 | "dev": true,
904 | "license": "MIT"
905 | },
906 | "node_modules/fastq": {
907 | "version": "1.13.0",
908 | "dev": true,
909 | "license": "ISC",
910 | "dependencies": {
911 | "reusify": "^1.0.4"
912 | }
913 | },
914 | "node_modules/file-entry-cache": {
915 | "version": "6.0.1",
916 | "dev": true,
917 | "license": "MIT",
918 | "dependencies": {
919 | "flat-cache": "^3.0.4"
920 | },
921 | "engines": {
922 | "node": "^10.12.0 || >=12.0.0"
923 | }
924 | },
925 | "node_modules/fill-range": {
926 | "version": "7.0.1",
927 | "dev": true,
928 | "license": "MIT",
929 | "dependencies": {
930 | "to-regex-range": "^5.0.1"
931 | },
932 | "engines": {
933 | "node": ">=8"
934 | }
935 | },
936 | "node_modules/find-up": {
937 | "version": "5.0.0",
938 | "dev": true,
939 | "license": "MIT",
940 | "dependencies": {
941 | "locate-path": "^6.0.0",
942 | "path-exists": "^4.0.0"
943 | },
944 | "engines": {
945 | "node": ">=10"
946 | },
947 | "funding": {
948 | "url": "https://github.com/sponsors/sindresorhus"
949 | }
950 | },
951 | "node_modules/flat-cache": {
952 | "version": "3.0.4",
953 | "dev": true,
954 | "license": "MIT",
955 | "dependencies": {
956 | "flatted": "^3.1.0",
957 | "rimraf": "^3.0.2"
958 | },
959 | "engines": {
960 | "node": "^10.12.0 || >=12.0.0"
961 | }
962 | },
963 | "node_modules/flatted": {
964 | "version": "3.2.6",
965 | "dev": true,
966 | "license": "ISC"
967 | },
968 | "node_modules/fs.realpath": {
969 | "version": "1.0.0",
970 | "dev": true,
971 | "license": "ISC"
972 | },
973 | "node_modules/function-bind": {
974 | "version": "1.1.1",
975 | "dev": true,
976 | "license": "MIT"
977 | },
978 | "node_modules/function.prototype.name": {
979 | "version": "1.1.5",
980 | "dev": true,
981 | "license": "MIT",
982 | "dependencies": {
983 | "call-bind": "^1.0.2",
984 | "define-properties": "^1.1.3",
985 | "es-abstract": "^1.19.0",
986 | "functions-have-names": "^1.2.2"
987 | },
988 | "engines": {
989 | "node": ">= 0.4"
990 | },
991 | "funding": {
992 | "url": "https://github.com/sponsors/ljharb"
993 | }
994 | },
995 | "node_modules/functional-red-black-tree": {
996 | "version": "1.0.1",
997 | "dev": true,
998 | "license": "MIT"
999 | },
1000 | "node_modules/functions-have-names": {
1001 | "version": "1.2.3",
1002 | "dev": true,
1003 | "license": "MIT",
1004 | "funding": {
1005 | "url": "https://github.com/sponsors/ljharb"
1006 | }
1007 | },
1008 | "node_modules/get-intrinsic": {
1009 | "version": "1.1.2",
1010 | "dev": true,
1011 | "license": "MIT",
1012 | "dependencies": {
1013 | "function-bind": "^1.1.1",
1014 | "has": "^1.0.3",
1015 | "has-symbols": "^1.0.3"
1016 | },
1017 | "funding": {
1018 | "url": "https://github.com/sponsors/ljharb"
1019 | }
1020 | },
1021 | "node_modules/get-symbol-description": {
1022 | "version": "1.0.0",
1023 | "dev": true,
1024 | "license": "MIT",
1025 | "dependencies": {
1026 | "call-bind": "^1.0.2",
1027 | "get-intrinsic": "^1.1.1"
1028 | },
1029 | "engines": {
1030 | "node": ">= 0.4"
1031 | },
1032 | "funding": {
1033 | "url": "https://github.com/sponsors/ljharb"
1034 | }
1035 | },
1036 | "node_modules/glob": {
1037 | "version": "7.2.3",
1038 | "dev": true,
1039 | "license": "ISC",
1040 | "dependencies": {
1041 | "fs.realpath": "^1.0.0",
1042 | "inflight": "^1.0.4",
1043 | "inherits": "2",
1044 | "minimatch": "^3.1.1",
1045 | "once": "^1.3.0",
1046 | "path-is-absolute": "^1.0.0"
1047 | },
1048 | "engines": {
1049 | "node": "*"
1050 | },
1051 | "funding": {
1052 | "url": "https://github.com/sponsors/isaacs"
1053 | }
1054 | },
1055 | "node_modules/glob-parent": {
1056 | "version": "6.0.2",
1057 | "dev": true,
1058 | "license": "ISC",
1059 | "dependencies": {
1060 | "is-glob": "^4.0.3"
1061 | },
1062 | "engines": {
1063 | "node": ">=10.13.0"
1064 | }
1065 | },
1066 | "node_modules/globals": {
1067 | "version": "13.17.0",
1068 | "dev": true,
1069 | "license": "MIT",
1070 | "dependencies": {
1071 | "type-fest": "^0.20.2"
1072 | },
1073 | "engines": {
1074 | "node": ">=8"
1075 | },
1076 | "funding": {
1077 | "url": "https://github.com/sponsors/sindresorhus"
1078 | }
1079 | },
1080 | "node_modules/globby": {
1081 | "version": "11.1.0",
1082 | "dev": true,
1083 | "license": "MIT",
1084 | "dependencies": {
1085 | "array-union": "^2.1.0",
1086 | "dir-glob": "^3.0.1",
1087 | "fast-glob": "^3.2.9",
1088 | "ignore": "^5.2.0",
1089 | "merge2": "^1.4.1",
1090 | "slash": "^3.0.0"
1091 | },
1092 | "engines": {
1093 | "node": ">=10"
1094 | },
1095 | "funding": {
1096 | "url": "https://github.com/sponsors/sindresorhus"
1097 | }
1098 | },
1099 | "node_modules/grapheme-splitter": {
1100 | "version": "1.0.4",
1101 | "dev": true,
1102 | "license": "MIT"
1103 | },
1104 | "node_modules/has": {
1105 | "version": "1.0.3",
1106 | "dev": true,
1107 | "license": "MIT",
1108 | "dependencies": {
1109 | "function-bind": "^1.1.1"
1110 | },
1111 | "engines": {
1112 | "node": ">= 0.4.0"
1113 | }
1114 | },
1115 | "node_modules/has-bigints": {
1116 | "version": "1.0.2",
1117 | "dev": true,
1118 | "license": "MIT",
1119 | "funding": {
1120 | "url": "https://github.com/sponsors/ljharb"
1121 | }
1122 | },
1123 | "node_modules/has-flag": {
1124 | "version": "4.0.0",
1125 | "dev": true,
1126 | "license": "MIT",
1127 | "engines": {
1128 | "node": ">=8"
1129 | }
1130 | },
1131 | "node_modules/has-property-descriptors": {
1132 | "version": "1.0.0",
1133 | "dev": true,
1134 | "license": "MIT",
1135 | "dependencies": {
1136 | "get-intrinsic": "^1.1.1"
1137 | },
1138 | "funding": {
1139 | "url": "https://github.com/sponsors/ljharb"
1140 | }
1141 | },
1142 | "node_modules/has-symbols": {
1143 | "version": "1.0.3",
1144 | "dev": true,
1145 | "license": "MIT",
1146 | "engines": {
1147 | "node": ">= 0.4"
1148 | },
1149 | "funding": {
1150 | "url": "https://github.com/sponsors/ljharb"
1151 | }
1152 | },
1153 | "node_modules/has-tostringtag": {
1154 | "version": "1.0.0",
1155 | "dev": true,
1156 | "license": "MIT",
1157 | "dependencies": {
1158 | "has-symbols": "^1.0.2"
1159 | },
1160 | "engines": {
1161 | "node": ">= 0.4"
1162 | },
1163 | "funding": {
1164 | "url": "https://github.com/sponsors/ljharb"
1165 | }
1166 | },
1167 | "node_modules/ignore": {
1168 | "version": "5.2.0",
1169 | "dev": true,
1170 | "license": "MIT",
1171 | "engines": {
1172 | "node": ">= 4"
1173 | }
1174 | },
1175 | "node_modules/import-fresh": {
1176 | "version": "3.3.0",
1177 | "dev": true,
1178 | "license": "MIT",
1179 | "dependencies": {
1180 | "parent-module": "^1.0.0",
1181 | "resolve-from": "^4.0.0"
1182 | },
1183 | "engines": {
1184 | "node": ">=6"
1185 | },
1186 | "funding": {
1187 | "url": "https://github.com/sponsors/sindresorhus"
1188 | }
1189 | },
1190 | "node_modules/imurmurhash": {
1191 | "version": "0.1.4",
1192 | "dev": true,
1193 | "license": "MIT",
1194 | "engines": {
1195 | "node": ">=0.8.19"
1196 | }
1197 | },
1198 | "node_modules/inflight": {
1199 | "version": "1.0.6",
1200 | "dev": true,
1201 | "license": "ISC",
1202 | "dependencies": {
1203 | "once": "^1.3.0",
1204 | "wrappy": "1"
1205 | }
1206 | },
1207 | "node_modules/inherits": {
1208 | "version": "2.0.4",
1209 | "dev": true,
1210 | "license": "ISC"
1211 | },
1212 | "node_modules/internal-slot": {
1213 | "version": "1.0.3",
1214 | "dev": true,
1215 | "license": "MIT",
1216 | "dependencies": {
1217 | "get-intrinsic": "^1.1.0",
1218 | "has": "^1.0.3",
1219 | "side-channel": "^1.0.4"
1220 | },
1221 | "engines": {
1222 | "node": ">= 0.4"
1223 | }
1224 | },
1225 | "node_modules/is-bigint": {
1226 | "version": "1.0.4",
1227 | "dev": true,
1228 | "license": "MIT",
1229 | "dependencies": {
1230 | "has-bigints": "^1.0.1"
1231 | },
1232 | "funding": {
1233 | "url": "https://github.com/sponsors/ljharb"
1234 | }
1235 | },
1236 | "node_modules/is-boolean-object": {
1237 | "version": "1.1.2",
1238 | "dev": true,
1239 | "license": "MIT",
1240 | "dependencies": {
1241 | "call-bind": "^1.0.2",
1242 | "has-tostringtag": "^1.0.0"
1243 | },
1244 | "engines": {
1245 | "node": ">= 0.4"
1246 | },
1247 | "funding": {
1248 | "url": "https://github.com/sponsors/ljharb"
1249 | }
1250 | },
1251 | "node_modules/is-callable": {
1252 | "version": "1.2.5",
1253 | "dev": true,
1254 | "license": "MIT",
1255 | "engines": {
1256 | "node": ">= 0.4"
1257 | },
1258 | "funding": {
1259 | "url": "https://github.com/sponsors/ljharb"
1260 | }
1261 | },
1262 | "node_modules/is-core-module": {
1263 | "version": "2.10.0",
1264 | "dev": true,
1265 | "license": "MIT",
1266 | "dependencies": {
1267 | "has": "^1.0.3"
1268 | },
1269 | "funding": {
1270 | "url": "https://github.com/sponsors/ljharb"
1271 | }
1272 | },
1273 | "node_modules/is-date-object": {
1274 | "version": "1.0.5",
1275 | "dev": true,
1276 | "license": "MIT",
1277 | "dependencies": {
1278 | "has-tostringtag": "^1.0.0"
1279 | },
1280 | "engines": {
1281 | "node": ">= 0.4"
1282 | },
1283 | "funding": {
1284 | "url": "https://github.com/sponsors/ljharb"
1285 | }
1286 | },
1287 | "node_modules/is-extglob": {
1288 | "version": "2.1.1",
1289 | "dev": true,
1290 | "license": "MIT",
1291 | "engines": {
1292 | "node": ">=0.10.0"
1293 | }
1294 | },
1295 | "node_modules/is-glob": {
1296 | "version": "4.0.3",
1297 | "dev": true,
1298 | "license": "MIT",
1299 | "dependencies": {
1300 | "is-extglob": "^2.1.1"
1301 | },
1302 | "engines": {
1303 | "node": ">=0.10.0"
1304 | }
1305 | },
1306 | "node_modules/is-negative-zero": {
1307 | "version": "2.0.2",
1308 | "dev": true,
1309 | "license": "MIT",
1310 | "engines": {
1311 | "node": ">= 0.4"
1312 | },
1313 | "funding": {
1314 | "url": "https://github.com/sponsors/ljharb"
1315 | }
1316 | },
1317 | "node_modules/is-number": {
1318 | "version": "7.0.0",
1319 | "dev": true,
1320 | "license": "MIT",
1321 | "engines": {
1322 | "node": ">=0.12.0"
1323 | }
1324 | },
1325 | "node_modules/is-number-object": {
1326 | "version": "1.0.7",
1327 | "dev": true,
1328 | "license": "MIT",
1329 | "dependencies": {
1330 | "has-tostringtag": "^1.0.0"
1331 | },
1332 | "engines": {
1333 | "node": ">= 0.4"
1334 | },
1335 | "funding": {
1336 | "url": "https://github.com/sponsors/ljharb"
1337 | }
1338 | },
1339 | "node_modules/is-regex": {
1340 | "version": "1.1.4",
1341 | "dev": true,
1342 | "license": "MIT",
1343 | "dependencies": {
1344 | "call-bind": "^1.0.2",
1345 | "has-tostringtag": "^1.0.0"
1346 | },
1347 | "engines": {
1348 | "node": ">= 0.4"
1349 | },
1350 | "funding": {
1351 | "url": "https://github.com/sponsors/ljharb"
1352 | }
1353 | },
1354 | "node_modules/is-shared-array-buffer": {
1355 | "version": "1.0.2",
1356 | "dev": true,
1357 | "license": "MIT",
1358 | "dependencies": {
1359 | "call-bind": "^1.0.2"
1360 | },
1361 | "funding": {
1362 | "url": "https://github.com/sponsors/ljharb"
1363 | }
1364 | },
1365 | "node_modules/is-string": {
1366 | "version": "1.0.7",
1367 | "dev": true,
1368 | "license": "MIT",
1369 | "dependencies": {
1370 | "has-tostringtag": "^1.0.0"
1371 | },
1372 | "engines": {
1373 | "node": ">= 0.4"
1374 | },
1375 | "funding": {
1376 | "url": "https://github.com/sponsors/ljharb"
1377 | }
1378 | },
1379 | "node_modules/is-symbol": {
1380 | "version": "1.0.4",
1381 | "dev": true,
1382 | "license": "MIT",
1383 | "dependencies": {
1384 | "has-symbols": "^1.0.2"
1385 | },
1386 | "engines": {
1387 | "node": ">= 0.4"
1388 | },
1389 | "funding": {
1390 | "url": "https://github.com/sponsors/ljharb"
1391 | }
1392 | },
1393 | "node_modules/is-weakref": {
1394 | "version": "1.0.2",
1395 | "dev": true,
1396 | "license": "MIT",
1397 | "dependencies": {
1398 | "call-bind": "^1.0.2"
1399 | },
1400 | "funding": {
1401 | "url": "https://github.com/sponsors/ljharb"
1402 | }
1403 | },
1404 | "node_modules/isexe": {
1405 | "version": "2.0.0",
1406 | "dev": true,
1407 | "license": "ISC"
1408 | },
1409 | "node_modules/js-tokens": {
1410 | "version": "4.0.0",
1411 | "dev": true,
1412 | "license": "MIT"
1413 | },
1414 | "node_modules/js-yaml": {
1415 | "version": "4.1.0",
1416 | "dev": true,
1417 | "license": "MIT",
1418 | "dependencies": {
1419 | "argparse": "^2.0.1"
1420 | },
1421 | "bin": {
1422 | "js-yaml": "bin/js-yaml.js"
1423 | }
1424 | },
1425 | "node_modules/json-schema-traverse": {
1426 | "version": "0.4.1",
1427 | "dev": true,
1428 | "license": "MIT"
1429 | },
1430 | "node_modules/json-stable-stringify-without-jsonify": {
1431 | "version": "1.0.1",
1432 | "dev": true,
1433 | "license": "MIT"
1434 | },
1435 | "node_modules/jsx-ast-utils": {
1436 | "version": "3.3.3",
1437 | "dev": true,
1438 | "license": "MIT",
1439 | "dependencies": {
1440 | "array-includes": "^3.1.5",
1441 | "object.assign": "^4.1.3"
1442 | },
1443 | "engines": {
1444 | "node": ">=4.0"
1445 | }
1446 | },
1447 | "node_modules/levn": {
1448 | "version": "0.4.1",
1449 | "dev": true,
1450 | "license": "MIT",
1451 | "dependencies": {
1452 | "prelude-ls": "^1.2.1",
1453 | "type-check": "~0.4.0"
1454 | },
1455 | "engines": {
1456 | "node": ">= 0.8.0"
1457 | }
1458 | },
1459 | "node_modules/locate-path": {
1460 | "version": "6.0.0",
1461 | "dev": true,
1462 | "license": "MIT",
1463 | "dependencies": {
1464 | "p-locate": "^5.0.0"
1465 | },
1466 | "engines": {
1467 | "node": ">=10"
1468 | },
1469 | "funding": {
1470 | "url": "https://github.com/sponsors/sindresorhus"
1471 | }
1472 | },
1473 | "node_modules/lodash.merge": {
1474 | "version": "4.6.2",
1475 | "dev": true,
1476 | "license": "MIT"
1477 | },
1478 | "node_modules/loose-envify": {
1479 | "version": "1.4.0",
1480 | "dev": true,
1481 | "license": "MIT",
1482 | "dependencies": {
1483 | "js-tokens": "^3.0.0 || ^4.0.0"
1484 | },
1485 | "bin": {
1486 | "loose-envify": "cli.js"
1487 | }
1488 | },
1489 | "node_modules/lru-cache": {
1490 | "version": "6.0.0",
1491 | "dev": true,
1492 | "license": "ISC",
1493 | "dependencies": {
1494 | "yallist": "^4.0.0"
1495 | },
1496 | "engines": {
1497 | "node": ">=10"
1498 | }
1499 | },
1500 | "node_modules/merge2": {
1501 | "version": "1.4.1",
1502 | "dev": true,
1503 | "license": "MIT",
1504 | "engines": {
1505 | "node": ">= 8"
1506 | }
1507 | },
1508 | "node_modules/micromatch": {
1509 | "version": "4.0.5",
1510 | "dev": true,
1511 | "license": "MIT",
1512 | "dependencies": {
1513 | "braces": "^3.0.2",
1514 | "picomatch": "^2.3.1"
1515 | },
1516 | "engines": {
1517 | "node": ">=8.6"
1518 | }
1519 | },
1520 | "node_modules/minimatch": {
1521 | "version": "3.1.2",
1522 | "dev": true,
1523 | "license": "ISC",
1524 | "dependencies": {
1525 | "brace-expansion": "^1.1.7"
1526 | },
1527 | "engines": {
1528 | "node": "*"
1529 | }
1530 | },
1531 | "node_modules/ms": {
1532 | "version": "2.1.2",
1533 | "dev": true,
1534 | "license": "MIT"
1535 | },
1536 | "node_modules/natural-compare": {
1537 | "version": "1.4.0",
1538 | "dev": true,
1539 | "license": "MIT"
1540 | },
1541 | "node_modules/object-assign": {
1542 | "version": "4.1.1",
1543 | "dev": true,
1544 | "license": "MIT",
1545 | "engines": {
1546 | "node": ">=0.10.0"
1547 | }
1548 | },
1549 | "node_modules/object-inspect": {
1550 | "version": "1.12.2",
1551 | "dev": true,
1552 | "license": "MIT",
1553 | "funding": {
1554 | "url": "https://github.com/sponsors/ljharb"
1555 | }
1556 | },
1557 | "node_modules/object-keys": {
1558 | "version": "1.1.1",
1559 | "dev": true,
1560 | "license": "MIT",
1561 | "engines": {
1562 | "node": ">= 0.4"
1563 | }
1564 | },
1565 | "node_modules/object.assign": {
1566 | "version": "4.1.4",
1567 | "dev": true,
1568 | "license": "MIT",
1569 | "dependencies": {
1570 | "call-bind": "^1.0.2",
1571 | "define-properties": "^1.1.4",
1572 | "has-symbols": "^1.0.3",
1573 | "object-keys": "^1.1.1"
1574 | },
1575 | "engines": {
1576 | "node": ">= 0.4"
1577 | },
1578 | "funding": {
1579 | "url": "https://github.com/sponsors/ljharb"
1580 | }
1581 | },
1582 | "node_modules/object.entries": {
1583 | "version": "1.1.5",
1584 | "dev": true,
1585 | "license": "MIT",
1586 | "dependencies": {
1587 | "call-bind": "^1.0.2",
1588 | "define-properties": "^1.1.3",
1589 | "es-abstract": "^1.19.1"
1590 | },
1591 | "engines": {
1592 | "node": ">= 0.4"
1593 | }
1594 | },
1595 | "node_modules/object.fromentries": {
1596 | "version": "2.0.5",
1597 | "dev": true,
1598 | "license": "MIT",
1599 | "dependencies": {
1600 | "call-bind": "^1.0.2",
1601 | "define-properties": "^1.1.3",
1602 | "es-abstract": "^1.19.1"
1603 | },
1604 | "engines": {
1605 | "node": ">= 0.4"
1606 | },
1607 | "funding": {
1608 | "url": "https://github.com/sponsors/ljharb"
1609 | }
1610 | },
1611 | "node_modules/object.hasown": {
1612 | "version": "1.1.1",
1613 | "dev": true,
1614 | "license": "MIT",
1615 | "dependencies": {
1616 | "define-properties": "^1.1.4",
1617 | "es-abstract": "^1.19.5"
1618 | },
1619 | "funding": {
1620 | "url": "https://github.com/sponsors/ljharb"
1621 | }
1622 | },
1623 | "node_modules/object.values": {
1624 | "version": "1.1.5",
1625 | "dev": true,
1626 | "license": "MIT",
1627 | "dependencies": {
1628 | "call-bind": "^1.0.2",
1629 | "define-properties": "^1.1.3",
1630 | "es-abstract": "^1.19.1"
1631 | },
1632 | "engines": {
1633 | "node": ">= 0.4"
1634 | },
1635 | "funding": {
1636 | "url": "https://github.com/sponsors/ljharb"
1637 | }
1638 | },
1639 | "node_modules/once": {
1640 | "version": "1.4.0",
1641 | "dev": true,
1642 | "license": "ISC",
1643 | "dependencies": {
1644 | "wrappy": "1"
1645 | }
1646 | },
1647 | "node_modules/optionator": {
1648 | "version": "0.9.1",
1649 | "dev": true,
1650 | "license": "MIT",
1651 | "dependencies": {
1652 | "deep-is": "^0.1.3",
1653 | "fast-levenshtein": "^2.0.6",
1654 | "levn": "^0.4.1",
1655 | "prelude-ls": "^1.2.1",
1656 | "type-check": "^0.4.0",
1657 | "word-wrap": "^1.2.3"
1658 | },
1659 | "engines": {
1660 | "node": ">= 0.8.0"
1661 | }
1662 | },
1663 | "node_modules/p-limit": {
1664 | "version": "3.1.0",
1665 | "dev": true,
1666 | "license": "MIT",
1667 | "dependencies": {
1668 | "yocto-queue": "^0.1.0"
1669 | },
1670 | "engines": {
1671 | "node": ">=10"
1672 | },
1673 | "funding": {
1674 | "url": "https://github.com/sponsors/sindresorhus"
1675 | }
1676 | },
1677 | "node_modules/p-locate": {
1678 | "version": "5.0.0",
1679 | "dev": true,
1680 | "license": "MIT",
1681 | "dependencies": {
1682 | "p-limit": "^3.0.2"
1683 | },
1684 | "engines": {
1685 | "node": ">=10"
1686 | },
1687 | "funding": {
1688 | "url": "https://github.com/sponsors/sindresorhus"
1689 | }
1690 | },
1691 | "node_modules/parent-module": {
1692 | "version": "1.0.1",
1693 | "dev": true,
1694 | "license": "MIT",
1695 | "dependencies": {
1696 | "callsites": "^3.0.0"
1697 | },
1698 | "engines": {
1699 | "node": ">=6"
1700 | }
1701 | },
1702 | "node_modules/path-exists": {
1703 | "version": "4.0.0",
1704 | "dev": true,
1705 | "license": "MIT",
1706 | "engines": {
1707 | "node": ">=8"
1708 | }
1709 | },
1710 | "node_modules/path-is-absolute": {
1711 | "version": "1.0.1",
1712 | "dev": true,
1713 | "license": "MIT",
1714 | "engines": {
1715 | "node": ">=0.10.0"
1716 | }
1717 | },
1718 | "node_modules/path-key": {
1719 | "version": "3.1.1",
1720 | "dev": true,
1721 | "license": "MIT",
1722 | "engines": {
1723 | "node": ">=8"
1724 | }
1725 | },
1726 | "node_modules/path-parse": {
1727 | "version": "1.0.7",
1728 | "dev": true,
1729 | "license": "MIT"
1730 | },
1731 | "node_modules/path-type": {
1732 | "version": "4.0.0",
1733 | "dev": true,
1734 | "license": "MIT",
1735 | "engines": {
1736 | "node": ">=8"
1737 | }
1738 | },
1739 | "node_modules/picomatch": {
1740 | "version": "2.3.1",
1741 | "dev": true,
1742 | "license": "MIT",
1743 | "engines": {
1744 | "node": ">=8.6"
1745 | },
1746 | "funding": {
1747 | "url": "https://github.com/sponsors/jonschlinkert"
1748 | }
1749 | },
1750 | "node_modules/prelude-ls": {
1751 | "version": "1.2.1",
1752 | "dev": true,
1753 | "license": "MIT",
1754 | "engines": {
1755 | "node": ">= 0.8.0"
1756 | }
1757 | },
1758 | "node_modules/prettier": {
1759 | "version": "2.7.1",
1760 | "dev": true,
1761 | "license": "MIT",
1762 | "bin": {
1763 | "prettier": "bin-prettier.js"
1764 | },
1765 | "engines": {
1766 | "node": ">=10.13.0"
1767 | },
1768 | "funding": {
1769 | "url": "https://github.com/prettier/prettier?sponsor=1"
1770 | }
1771 | },
1772 | "node_modules/prop-types": {
1773 | "version": "15.8.1",
1774 | "dev": true,
1775 | "license": "MIT",
1776 | "dependencies": {
1777 | "loose-envify": "^1.4.0",
1778 | "object-assign": "^4.1.1",
1779 | "react-is": "^16.13.1"
1780 | }
1781 | },
1782 | "node_modules/punycode": {
1783 | "version": "2.1.1",
1784 | "dev": true,
1785 | "license": "MIT",
1786 | "engines": {
1787 | "node": ">=6"
1788 | }
1789 | },
1790 | "node_modules/queue-microtask": {
1791 | "version": "1.2.3",
1792 | "dev": true,
1793 | "funding": [
1794 | {
1795 | "type": "github",
1796 | "url": "https://github.com/sponsors/feross"
1797 | },
1798 | {
1799 | "type": "patreon",
1800 | "url": "https://www.patreon.com/feross"
1801 | },
1802 | {
1803 | "type": "consulting",
1804 | "url": "https://feross.org/support"
1805 | }
1806 | ],
1807 | "license": "MIT"
1808 | },
1809 | "node_modules/react": {
1810 | "version": "18.3.1",
1811 | "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
1812 | "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
1813 | "dev": true,
1814 | "dependencies": {
1815 | "loose-envify": "^1.1.0"
1816 | },
1817 | "engines": {
1818 | "node": ">=0.10.0"
1819 | }
1820 | },
1821 | "node_modules/react-is": {
1822 | "version": "16.13.1",
1823 | "dev": true,
1824 | "license": "MIT"
1825 | },
1826 | "node_modules/regexp.prototype.flags": {
1827 | "version": "1.4.3",
1828 | "dev": true,
1829 | "license": "MIT",
1830 | "dependencies": {
1831 | "call-bind": "^1.0.2",
1832 | "define-properties": "^1.1.3",
1833 | "functions-have-names": "^1.2.2"
1834 | },
1835 | "engines": {
1836 | "node": ">= 0.4"
1837 | },
1838 | "funding": {
1839 | "url": "https://github.com/sponsors/ljharb"
1840 | }
1841 | },
1842 | "node_modules/regexpp": {
1843 | "version": "3.2.0",
1844 | "dev": true,
1845 | "license": "MIT",
1846 | "engines": {
1847 | "node": ">=8"
1848 | },
1849 | "funding": {
1850 | "url": "https://github.com/sponsors/mysticatea"
1851 | }
1852 | },
1853 | "node_modules/resolve": {
1854 | "version": "2.0.0-next.4",
1855 | "dev": true,
1856 | "license": "MIT",
1857 | "dependencies": {
1858 | "is-core-module": "^2.9.0",
1859 | "path-parse": "^1.0.7",
1860 | "supports-preserve-symlinks-flag": "^1.0.0"
1861 | },
1862 | "bin": {
1863 | "resolve": "bin/resolve"
1864 | },
1865 | "funding": {
1866 | "url": "https://github.com/sponsors/ljharb"
1867 | }
1868 | },
1869 | "node_modules/resolve-from": {
1870 | "version": "4.0.0",
1871 | "dev": true,
1872 | "license": "MIT",
1873 | "engines": {
1874 | "node": ">=4"
1875 | }
1876 | },
1877 | "node_modules/reusify": {
1878 | "version": "1.0.4",
1879 | "dev": true,
1880 | "license": "MIT",
1881 | "engines": {
1882 | "iojs": ">=1.0.0",
1883 | "node": ">=0.10.0"
1884 | }
1885 | },
1886 | "node_modules/rimraf": {
1887 | "version": "3.0.2",
1888 | "dev": true,
1889 | "license": "ISC",
1890 | "dependencies": {
1891 | "glob": "^7.1.3"
1892 | },
1893 | "bin": {
1894 | "rimraf": "bin.js"
1895 | },
1896 | "funding": {
1897 | "url": "https://github.com/sponsors/isaacs"
1898 | }
1899 | },
1900 | "node_modules/run-parallel": {
1901 | "version": "1.2.0",
1902 | "dev": true,
1903 | "funding": [
1904 | {
1905 | "type": "github",
1906 | "url": "https://github.com/sponsors/feross"
1907 | },
1908 | {
1909 | "type": "patreon",
1910 | "url": "https://www.patreon.com/feross"
1911 | },
1912 | {
1913 | "type": "consulting",
1914 | "url": "https://feross.org/support"
1915 | }
1916 | ],
1917 | "license": "MIT",
1918 | "dependencies": {
1919 | "queue-microtask": "^1.2.2"
1920 | }
1921 | },
1922 | "node_modules/semver": {
1923 | "version": "7.3.7",
1924 | "dev": true,
1925 | "license": "ISC",
1926 | "dependencies": {
1927 | "lru-cache": "^6.0.0"
1928 | },
1929 | "bin": {
1930 | "semver": "bin/semver.js"
1931 | },
1932 | "engines": {
1933 | "node": ">=10"
1934 | }
1935 | },
1936 | "node_modules/shebang-command": {
1937 | "version": "2.0.0",
1938 | "dev": true,
1939 | "license": "MIT",
1940 | "dependencies": {
1941 | "shebang-regex": "^3.0.0"
1942 | },
1943 | "engines": {
1944 | "node": ">=8"
1945 | }
1946 | },
1947 | "node_modules/shebang-regex": {
1948 | "version": "3.0.0",
1949 | "dev": true,
1950 | "license": "MIT",
1951 | "engines": {
1952 | "node": ">=8"
1953 | }
1954 | },
1955 | "node_modules/side-channel": {
1956 | "version": "1.0.4",
1957 | "dev": true,
1958 | "license": "MIT",
1959 | "dependencies": {
1960 | "call-bind": "^1.0.0",
1961 | "get-intrinsic": "^1.0.2",
1962 | "object-inspect": "^1.9.0"
1963 | },
1964 | "funding": {
1965 | "url": "https://github.com/sponsors/ljharb"
1966 | }
1967 | },
1968 | "node_modules/slash": {
1969 | "version": "3.0.0",
1970 | "dev": true,
1971 | "license": "MIT",
1972 | "engines": {
1973 | "node": ">=8"
1974 | }
1975 | },
1976 | "node_modules/string.prototype.matchall": {
1977 | "version": "4.0.7",
1978 | "dev": true,
1979 | "license": "MIT",
1980 | "dependencies": {
1981 | "call-bind": "^1.0.2",
1982 | "define-properties": "^1.1.3",
1983 | "es-abstract": "^1.19.1",
1984 | "get-intrinsic": "^1.1.1",
1985 | "has-symbols": "^1.0.3",
1986 | "internal-slot": "^1.0.3",
1987 | "regexp.prototype.flags": "^1.4.1",
1988 | "side-channel": "^1.0.4"
1989 | },
1990 | "funding": {
1991 | "url": "https://github.com/sponsors/ljharb"
1992 | }
1993 | },
1994 | "node_modules/string.prototype.trimend": {
1995 | "version": "1.0.5",
1996 | "dev": true,
1997 | "license": "MIT",
1998 | "dependencies": {
1999 | "call-bind": "^1.0.2",
2000 | "define-properties": "^1.1.4",
2001 | "es-abstract": "^1.19.5"
2002 | },
2003 | "funding": {
2004 | "url": "https://github.com/sponsors/ljharb"
2005 | }
2006 | },
2007 | "node_modules/string.prototype.trimstart": {
2008 | "version": "1.0.5",
2009 | "dev": true,
2010 | "license": "MIT",
2011 | "dependencies": {
2012 | "call-bind": "^1.0.2",
2013 | "define-properties": "^1.1.4",
2014 | "es-abstract": "^1.19.5"
2015 | },
2016 | "funding": {
2017 | "url": "https://github.com/sponsors/ljharb"
2018 | }
2019 | },
2020 | "node_modules/strip-ansi": {
2021 | "version": "6.0.1",
2022 | "dev": true,
2023 | "license": "MIT",
2024 | "dependencies": {
2025 | "ansi-regex": "^5.0.1"
2026 | },
2027 | "engines": {
2028 | "node": ">=8"
2029 | }
2030 | },
2031 | "node_modules/strip-json-comments": {
2032 | "version": "3.1.1",
2033 | "dev": true,
2034 | "license": "MIT",
2035 | "engines": {
2036 | "node": ">=8"
2037 | },
2038 | "funding": {
2039 | "url": "https://github.com/sponsors/sindresorhus"
2040 | }
2041 | },
2042 | "node_modules/supports-color": {
2043 | "version": "7.2.0",
2044 | "dev": true,
2045 | "license": "MIT",
2046 | "dependencies": {
2047 | "has-flag": "^4.0.0"
2048 | },
2049 | "engines": {
2050 | "node": ">=8"
2051 | }
2052 | },
2053 | "node_modules/supports-preserve-symlinks-flag": {
2054 | "version": "1.0.0",
2055 | "dev": true,
2056 | "license": "MIT",
2057 | "engines": {
2058 | "node": ">= 0.4"
2059 | },
2060 | "funding": {
2061 | "url": "https://github.com/sponsors/ljharb"
2062 | }
2063 | },
2064 | "node_modules/text-table": {
2065 | "version": "0.2.0",
2066 | "dev": true,
2067 | "license": "MIT"
2068 | },
2069 | "node_modules/to-regex-range": {
2070 | "version": "5.0.1",
2071 | "dev": true,
2072 | "license": "MIT",
2073 | "dependencies": {
2074 | "is-number": "^7.0.0"
2075 | },
2076 | "engines": {
2077 | "node": ">=8.0"
2078 | }
2079 | },
2080 | "node_modules/tslib": {
2081 | "version": "1.14.1",
2082 | "dev": true,
2083 | "license": "0BSD"
2084 | },
2085 | "node_modules/tsutils": {
2086 | "version": "3.21.0",
2087 | "dev": true,
2088 | "license": "MIT",
2089 | "dependencies": {
2090 | "tslib": "^1.8.1"
2091 | },
2092 | "engines": {
2093 | "node": ">= 6"
2094 | },
2095 | "peerDependencies": {
2096 | "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
2097 | }
2098 | },
2099 | "node_modules/type-check": {
2100 | "version": "0.4.0",
2101 | "dev": true,
2102 | "license": "MIT",
2103 | "dependencies": {
2104 | "prelude-ls": "^1.2.1"
2105 | },
2106 | "engines": {
2107 | "node": ">= 0.8.0"
2108 | }
2109 | },
2110 | "node_modules/type-fest": {
2111 | "version": "0.20.2",
2112 | "dev": true,
2113 | "license": "(MIT OR CC0-1.0)",
2114 | "engines": {
2115 | "node": ">=10"
2116 | },
2117 | "funding": {
2118 | "url": "https://github.com/sponsors/sindresorhus"
2119 | }
2120 | },
2121 | "node_modules/typescript": {
2122 | "version": "4.7.4",
2123 | "dev": true,
2124 | "license": "Apache-2.0",
2125 | "bin": {
2126 | "tsc": "bin/tsc",
2127 | "tsserver": "bin/tsserver"
2128 | },
2129 | "engines": {
2130 | "node": ">=4.2.0"
2131 | }
2132 | },
2133 | "node_modules/unbox-primitive": {
2134 | "version": "1.0.2",
2135 | "dev": true,
2136 | "license": "MIT",
2137 | "dependencies": {
2138 | "call-bind": "^1.0.2",
2139 | "has-bigints": "^1.0.2",
2140 | "has-symbols": "^1.0.3",
2141 | "which-boxed-primitive": "^1.0.2"
2142 | },
2143 | "funding": {
2144 | "url": "https://github.com/sponsors/ljharb"
2145 | }
2146 | },
2147 | "node_modules/uri-js": {
2148 | "version": "4.4.1",
2149 | "dev": true,
2150 | "license": "BSD-2-Clause",
2151 | "dependencies": {
2152 | "punycode": "^2.1.0"
2153 | }
2154 | },
2155 | "node_modules/v8-compile-cache": {
2156 | "version": "2.3.0",
2157 | "dev": true,
2158 | "license": "MIT"
2159 | },
2160 | "node_modules/which": {
2161 | "version": "2.0.2",
2162 | "dev": true,
2163 | "license": "ISC",
2164 | "dependencies": {
2165 | "isexe": "^2.0.0"
2166 | },
2167 | "bin": {
2168 | "node-which": "bin/node-which"
2169 | },
2170 | "engines": {
2171 | "node": ">= 8"
2172 | }
2173 | },
2174 | "node_modules/which-boxed-primitive": {
2175 | "version": "1.0.2",
2176 | "dev": true,
2177 | "license": "MIT",
2178 | "dependencies": {
2179 | "is-bigint": "^1.0.1",
2180 | "is-boolean-object": "^1.1.0",
2181 | "is-number-object": "^1.0.4",
2182 | "is-string": "^1.0.5",
2183 | "is-symbol": "^1.0.3"
2184 | },
2185 | "funding": {
2186 | "url": "https://github.com/sponsors/ljharb"
2187 | }
2188 | },
2189 | "node_modules/word-wrap": {
2190 | "version": "1.2.3",
2191 | "dev": true,
2192 | "license": "MIT",
2193 | "engines": {
2194 | "node": ">=0.10.0"
2195 | }
2196 | },
2197 | "node_modules/wrappy": {
2198 | "version": "1.0.2",
2199 | "dev": true,
2200 | "license": "ISC"
2201 | },
2202 | "node_modules/yallist": {
2203 | "version": "4.0.0",
2204 | "dev": true,
2205 | "license": "ISC"
2206 | },
2207 | "node_modules/yocto-queue": {
2208 | "version": "0.1.0",
2209 | "dev": true,
2210 | "license": "MIT",
2211 | "engines": {
2212 | "node": ">=10"
2213 | },
2214 | "funding": {
2215 | "url": "https://github.com/sponsors/sindresorhus"
2216 | }
2217 | }
2218 | }
2219 | }
2220 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@twa-dev/sdk",
3 | "version": "8.0.2",
4 | "main": "dist/index.js",
5 | "sideEffects": [
6 | "./dist/telegram-web-apps.js"
7 | ],
8 | "exports": {
9 | ".": {
10 | "import": "./dist/index.js",
11 | "types": "./dist/index.d.ts",
12 | "default": "./dist/index.js"
13 | },
14 | "./react": {
15 | "import": "./dist/react/index.js",
16 | "types": "./dist/react/index.d.ts",
17 | "default": "./dist/react/index.js"
18 | }
19 | },
20 | "typesVersions": {
21 | "*": {
22 | "react": [
23 | "./dist/react/index.d.ts"
24 | ]
25 | }
26 | },
27 | "repository": "https://github.com/twa-dev/sdk.git",
28 | "keywords": [
29 | "telegram",
30 | "telegram web apps",
31 | "telegram bot",
32 | "sdk",
33 | "bot"
34 | ],
35 | "author": "Artur Stambultsian ",
36 | "license": "MIT",
37 | "devDependencies": {
38 | "@types/react": "^19.0.8",
39 | "@typescript-eslint/eslint-plugin": "^5.33.0",
40 | "@typescript-eslint/parser": "^5.33.0",
41 | "eslint": "^8.21.0",
42 | "eslint-config-prettier": "^8.5.0",
43 | "eslint-plugin-react": "^7.31.8",
44 | "prettier": "^2.7.1",
45 | "react": "^18.3.1",
46 | "typescript": "^4.7.4"
47 | },
48 | "scripts": {
49 | "test": "eslint --ext .ts,.tsx ./",
50 | "build": "rm -rf dist && npm run test && tsc --outDir dist/"
51 | },
52 | "dependencies": {
53 | "@twa-dev/types": "^8.0.1"
54 | },
55 | "peerDependencies": {
56 | "react": "^18.0.0 || ^19.0.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { WebApp } from "./sdk";
2 |
3 | export default WebApp;
4 |
--------------------------------------------------------------------------------
/src/react/BackButton/BackButton.tsx:
--------------------------------------------------------------------------------
1 | import { FC, useEffect } from "react";
2 | import { WebApp } from "../../sdk";
3 |
4 | interface BackButtonProps {
5 | onClick?: VoidFunction;
6 | }
7 |
8 | const backButton = WebApp.BackButton;
9 |
10 | let isButtonShown = false;
11 |
12 | export const BackButton: FC = ({
13 | onClick = () => {
14 | window.history.back();
15 | },
16 | }) => {
17 | useEffect(() => {
18 | backButton.show();
19 | isButtonShown = true;
20 | return () => {
21 | isButtonShown = false;
22 | // Мы ждем 10мс на случай, если на следующем экране тоже нужен BackButton.
23 | // Если через это время isButtonShown не стал true, значит следующему экрану кнопка не нужна и мы её прячем
24 | setTimeout(() => {
25 | if (!isButtonShown) {
26 | backButton.hide();
27 | }
28 | }, 10);
29 | };
30 | }, []);
31 |
32 | useEffect(() => {
33 | WebApp.onEvent("backButtonClicked", onClick);
34 | return () => {
35 | WebApp.offEvent("backButtonClicked", onClick);
36 | };
37 | }, [onClick]);
38 |
39 | return null;
40 | };
41 |
--------------------------------------------------------------------------------
/src/react/BackButton/Readme.md:
--------------------------------------------------------------------------------
1 | # BackButton
2 | React component for [Telegram Web Apps (TWA)](https://core.telegram.org/bots/webapps) Back Button.
3 |
4 | ## Installation
5 | ```bash
6 | npm i @twa-dev/sdk
7 | ```
8 |
9 | ## Motivation
10 | TWA SDK contains an interface that controls [BackButton](https://core.telegram.org/bots/webapps#backbutton). It's written in imperative way:
11 |
12 | ```jsx
13 | const BackButton = window.Telegram.WebApp.BackButton;
14 |
15 | BackButton.show();
16 | BackButton.onClick(() => window.history.back());
17 | ```
18 |
19 | It's not the best way to write code, especially if you use libraries like React.
20 |
21 | This package exports React component that wraps TWA BackButton SDK:
22 |
23 | ```js
24 | import { BackButton } from '@twa-dev/sdk/react';
25 |
26 | window.history.back()} />
27 | ```
28 |
29 | ## Demo
30 | [@BackButtonDemoBot](https://t.me/BackButtonDemoBot)
31 |
32 | [Codesandbox](https://codesandbox.io/s/back-button-demo-lpc0rv)
33 |
--------------------------------------------------------------------------------
/src/react/BottomBar/BottomBar.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode, useEffect } from "react";
2 | import { WebApp } from "../../sdk";
3 |
4 | const defaultBottomBarColor =
5 | WebApp.themeParams.bottom_bar_bg_color ??
6 | WebApp.themeParams.secondary_bg_color;
7 |
8 | export const BottomBar = ({
9 | bgColor = defaultBottomBarColor,
10 | children = null,
11 | }: {
12 | bgColor?: string;
13 | children?: ReactNode;
14 | }) => {
15 | useEffect(() => {
16 | WebApp.setBottomBarColor(bgColor);
17 | }, [bgColor]);
18 |
19 | useEffect(() => {
20 | return () => {
21 | WebApp.setBottomBarColor(defaultBottomBarColor);
22 | };
23 | }, []);
24 |
25 | return <>{children}>;
26 | };
27 |
--------------------------------------------------------------------------------
/src/react/BottomBar/Readme.md:
--------------------------------------------------------------------------------
1 | # BottomBar
2 | React component for [Telegram Web Apps (TWA)](https://core.telegram.org/bots/webapps) bottom bar. Bottom bar is an area that wraps [Main](../MainButton/Readme.md) and [Secondary](../SecondaryButton/Readme.md) buttons.
3 |
4 | ## Installation
5 | ```bash
6 | npm i @twa-dev/sdk
7 | ```
8 |
9 | ## Motivation
10 | TWA SDK contains an interface that controls [bottom bar](https://core.telegram.org/bots/webapps#september-6-2024). It's written in imperative way:
11 |
12 | ```js
13 | const bottomBarColor = window.Telegram.WebApp.bottomBarColor;
14 | window.Telegram.WebApp.setBottomBarColor('#ff0000');
15 | ```
16 |
17 | It's not the best way to write code, especially if you use libraries like React.
18 |
19 | This package exports React component that wraps TWA bottom bar SDK:
20 |
21 | ```jsx
22 | import { BottomBar, MainButton, SecondaryButton } from '@twa-dev/sdk/react';
23 |
24 |
25 | alert('continue')} />
26 | alert('cancelled')} />
27 |
28 | ```
29 |
30 | ## Demo
31 | [@BottomButtonBot](https://t.me/BottomButtonBot)
32 |
33 | [Codesandbox](https://codesandbox.io/p/sandbox/bottom-button-demo-s8wdgp)
34 |
35 | ## Props
36 | Naming is pretty straight forward and corresponds SDK props and methods:
37 | - `children`
38 | - `bgColor`
--------------------------------------------------------------------------------
/src/react/MainButton/MainButton.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react";
2 | import { BottomButtonProps, useBottomButton } from "../bottomButton";
3 |
4 | export const MainButton: FC = ({
5 | disabled,
6 | color,
7 | textColor,
8 | text,
9 | onClick,
10 | progress,
11 | hasShineEffect,
12 | }) => {
13 | useBottomButton({
14 | type: "main",
15 | disabled,
16 | progress,
17 | textColor,
18 | text,
19 | onClick,
20 | color,
21 | hasShineEffect,
22 | });
23 |
24 | return null;
25 | };
26 |
--------------------------------------------------------------------------------
/src/react/MainButton/Readme.md:
--------------------------------------------------------------------------------
1 | # MainButton
2 | React component for [Telegram Web Apps (TWA)](https://core.telegram.org/bots/webapps) MainButton.
3 |
4 | ## Installation
5 | ```bash
6 | npm i @twa-dev/sdk
7 | ```
8 |
9 | ## Motivation
10 | TWA SDK contains an interface that controls [MainButton](https://core.telegram.org/bots/webapps#mainbutton). It's written in imperative way:
11 |
12 | ```js
13 | const MainButton = window.Telegram.WebApp.MainButton;
14 |
15 | MainButton.setText('Submit');
16 | MainButton.show();
17 | MainButton.onClick(() => alert('submitted'));
18 | ```
19 |
20 | It's not the best way to write code, especially if you use libraries like React.
21 |
22 | This package exports React component that wraps TWA MainButton SDK:
23 |
24 | ```jsx
25 | import { MainButton } from '@twa-dev/sdk/react';
26 |
27 | alert('submitted')} />
28 | ```
29 |
30 | ## Demo
31 | [@BottomButtonBot](https://t.me/BottomButtonBot)
32 |
33 | [Codesandbox](https://codesandbox.io/p/sandbox/bottom-button-demo-s8wdgp)
34 |
35 | ## Props
36 | Naming is pretty straight forward and corresponds SDK props and methods:
37 | - `text`
38 | - `color`
39 | - `textColor`
40 | - `disabled`
41 | - `progress`
42 | - `onClick`
43 | - `hasShineEffect`
44 |
--------------------------------------------------------------------------------
/src/react/SecondaryButton/Readme.md:
--------------------------------------------------------------------------------
1 | # SecondaryButton
2 | React component for [Telegram Web Apps (TWA)](https://core.telegram.org/bots/webapps) SecondaryButton.
3 |
4 | ## Installation
5 | ```bash
6 | npm i @twa-dev/sdk
7 | ```
8 |
9 | ## Motivation
10 | TWA SDK contains an interface that controls [BottomButton](https://core.telegram.org/bots/webapps#bottombutton). It's written in imperative way:
11 |
12 | ```js
13 | const SecondaryButton = window.Telegram.WebApp.SecondaryButton;
14 |
15 | SecondaryButton.setParams({ text: 'Cancel', position: 'bottom' });
16 | SecondaryButton.show();
17 | SecondaryButton.onClick(() => alert('cancelled'));
18 | ```
19 |
20 | It's not the best way to write code, especially if you use libraries like React.
21 |
22 | This package exports React component that wraps TWA SecondaryButton SDK:
23 |
24 | ```jsx
25 | import { MainButton, SecondaryButton } from '@twa-dev/sdk/react';
26 |
27 | alert('continue')} />
28 | alert('cancelled')} />
29 | ```
30 |
31 | ## Demo
32 | [@BottomButtonBot](https://t.me/BottomButtonBot)
33 |
34 | [Codesandbox](https://codesandbox.io/p/sandbox/bottom-button-demo-s8wdgp)
35 |
36 | ## Props
37 | Naming is pretty straight forward and corresponds SDK props and methods:
38 | - `text`
39 | - `color`
40 | - `textColor`
41 | - `disabled`
42 | - `progress`
43 | - `onClick`
44 | - `hasShineEffect`
45 | - `position`
46 |
--------------------------------------------------------------------------------
/src/react/SecondaryButton/SecondaryButton.tsx:
--------------------------------------------------------------------------------
1 | import { FC, useEffect } from "react";
2 | import { BottomButtonProps, useBottomButton } from "../bottomButton";
3 | import { SecondaryButton as SecondaryButtonType } from "@twa-dev/types";
4 | import { WebApp } from "../../sdk";
5 |
6 | const secondaryButton = WebApp.SecondaryButton;
7 |
8 | export const SecondaryButton: FC<
9 | BottomButtonProps & { position?: SecondaryButtonType["position"] }
10 | > = ({
11 | disabled,
12 | color,
13 | textColor,
14 | text,
15 | onClick,
16 | progress,
17 | hasShineEffect,
18 | position = "bottom",
19 | }) => {
20 | useBottomButton({
21 | type: "secondary",
22 | disabled,
23 | progress,
24 | textColor,
25 | text,
26 | onClick,
27 | color,
28 | hasShineEffect,
29 | });
30 |
31 | useEffect(() => {
32 | secondaryButton.setParams({
33 | position,
34 | });
35 | }, [position]);
36 |
37 | return null;
38 | };
39 |
--------------------------------------------------------------------------------
/src/react/bottomButton.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { WebApp } from "../sdk";
3 |
4 | export type BottomButtonProps = {
5 | disabled?: boolean;
6 | progress?: boolean;
7 | color?: string;
8 | textColor?: string;
9 | onClick?: VoidFunction;
10 | text: string;
11 | hasShineEffect?: boolean;
12 | };
13 |
14 | const { bottom_bar_bg_color, button_color, button_text_color } =
15 | WebApp.themeParams;
16 |
17 | type ButtonTypes = "main" | "secondary";
18 |
19 | const defaultButtonColors: Record<
20 | ButtonTypes,
21 | Parameters[0]
22 | > = {
23 | main: {
24 | color: button_color,
25 | text_color: button_text_color,
26 | },
27 | secondary: {
28 | color: bottom_bar_bg_color,
29 | text_color: button_color,
30 | },
31 | };
32 |
33 | const isButtonShown: Record = {
34 | main: false,
35 | secondary: false,
36 | };
37 |
38 | export const useBottomButton = ({
39 | type,
40 | progress = false,
41 | disabled = false,
42 | color,
43 | textColor,
44 | text,
45 | onClick,
46 | hasShineEffect = false,
47 | }: {
48 | type: ButtonTypes;
49 | } & BottomButtonProps) => {
50 | const button = type === "main" ? WebApp.MainButton : WebApp.SecondaryButton;
51 |
52 | useEffect(() => {
53 | button.show();
54 | isButtonShown[type] = true;
55 | return () => {
56 | isButtonShown[type] = false;
57 | setTimeout(() => {
58 | if (!isButtonShown[type]) {
59 | button.hide();
60 | }
61 | }, 10);
62 | };
63 | }, [type]);
64 |
65 | useEffect(() => {
66 | if (progress) {
67 | button.showProgress();
68 | button.disable();
69 | } else {
70 | button.hideProgress();
71 | }
72 |
73 | if (disabled || progress) {
74 | button.disable();
75 | } else {
76 | button.enable();
77 | }
78 |
79 | return () => {
80 | button.hideProgress();
81 | button.enable();
82 | };
83 | }, [disabled, progress]);
84 |
85 | useEffect(() => {
86 | button.setParams({
87 | color: color ?? defaultButtonColors[type].color,
88 | text_color: textColor ?? defaultButtonColors[type].text_color,
89 | has_shine_effect: hasShineEffect,
90 | });
91 | }, [color, textColor, hasShineEffect]);
92 |
93 | useEffect(() => {
94 | button.setText(text);
95 | }, [text]);
96 |
97 | useEffect(() => {
98 | if (onClick) {
99 | button.onClick(onClick);
100 | return () => {
101 | button.offClick(onClick);
102 | };
103 | }
104 | }, [onClick]);
105 | };
106 |
--------------------------------------------------------------------------------
/src/react/index.ts:
--------------------------------------------------------------------------------
1 | export { MainButton } from "./MainButton/MainButton";
2 | export { SecondaryButton } from "./SecondaryButton/SecondaryButton";
3 | export { BottomBar } from "./BottomBar/BottomBar";
4 | export { BackButton } from "./BackButton/BackButton";
5 |
--------------------------------------------------------------------------------
/src/sdk.ts:
--------------------------------------------------------------------------------
1 | import "./telegram-web-apps";
2 | import { Telegram, WebApp as WebAppTypes } from "@twa-dev/types";
3 |
4 | const telegramWindow = window as unknown as Window & { Telegram: Telegram };
5 |
6 | export const WebApp: WebAppTypes = telegramWindow.Telegram.WebApp;
7 |
--------------------------------------------------------------------------------
/src/telegram-web-apps.js:
--------------------------------------------------------------------------------
1 | // WebView
2 | (function () {
3 | var eventHandlers = {};
4 |
5 | var locationHash = '';
6 | try {
7 | locationHash = location.hash.toString();
8 | } catch (e) {}
9 |
10 | var initParams = urlParseHashParams(locationHash);
11 | var storedParams = sessionStorageGet('initParams');
12 | if (storedParams) {
13 | for (var key in storedParams) {
14 | if (typeof initParams[key] === 'undefined') {
15 | initParams[key] = storedParams[key];
16 | }
17 | }
18 | }
19 | sessionStorageSet('initParams', initParams);
20 |
21 | var isIframe = false, iFrameStyle;
22 | try {
23 | isIframe = (window.parent != null && window != window.parent);
24 | if (isIframe) {
25 | window.addEventListener('message', function (event) {
26 | if (event.source !== window.parent) return;
27 | try {
28 | var dataParsed = JSON.parse(event.data);
29 | } catch (e) {
30 | return;
31 | }
32 | if (!dataParsed || !dataParsed.eventType) {
33 | return;
34 | }
35 | if (dataParsed.eventType == 'set_custom_style') {
36 | if (event.origin === 'https://web.telegram.org') {
37 | iFrameStyle.innerHTML = dataParsed.eventData;
38 | }
39 | } else if (dataParsed.eventType == 'reload_iframe') {
40 | try {
41 | window.parent.postMessage(JSON.stringify({eventType: 'iframe_will_reload'}), '*');
42 | } catch (e) {}
43 | location.reload();
44 | } else {
45 | receiveEvent(dataParsed.eventType, dataParsed.eventData);
46 | }
47 | });
48 | iFrameStyle = document.createElement('style');
49 | document.head.appendChild(iFrameStyle);
50 | try {
51 | window.parent.postMessage(JSON.stringify({eventType: 'iframe_ready', eventData: {reload_supported: true}}), '*');
52 | } catch (e) {}
53 | }
54 | } catch (e) {}
55 |
56 | function urlSafeDecode(urlencoded) {
57 | try {
58 | urlencoded = urlencoded.replace(/\+/g, '%20');
59 | return decodeURIComponent(urlencoded);
60 | } catch (e) {
61 | return urlencoded;
62 | }
63 | }
64 |
65 | function urlParseHashParams(locationHash) {
66 | locationHash = locationHash.replace(/^#/, '');
67 | var params = {};
68 | if (!locationHash.length) {
69 | return params;
70 | }
71 | if (locationHash.indexOf('=') < 0 && locationHash.indexOf('?') < 0) {
72 | params._path = urlSafeDecode(locationHash);
73 | return params;
74 | }
75 | var qIndex = locationHash.indexOf('?');
76 | if (qIndex >= 0) {
77 | var pathParam = locationHash.substr(0, qIndex);
78 | params._path = urlSafeDecode(pathParam);
79 | locationHash = locationHash.substr(qIndex + 1);
80 | }
81 | var query_params = urlParseQueryString(locationHash);
82 | for (var k in query_params) {
83 | params[k] = query_params[k];
84 | }
85 | return params;
86 | }
87 |
88 | function urlParseQueryString(queryString) {
89 | var params = {};
90 | if (!queryString.length) {
91 | return params;
92 | }
93 | var queryStringParams = queryString.split('&');
94 | var i, param, paramName, paramValue;
95 | for (i = 0; i < queryStringParams.length; i++) {
96 | param = queryStringParams[i].split('=');
97 | paramName = urlSafeDecode(param[0]);
98 | paramValue = param[1] == null ? null : urlSafeDecode(param[1]);
99 | params[paramName] = paramValue;
100 | }
101 | return params;
102 | }
103 |
104 | // Telegram apps will implement this logic to add service params (e.g. tgShareScoreUrl) to game URL
105 | function urlAppendHashParams(url, addHash) {
106 | // url looks like 'https://game.com/path?query=1#hash'
107 | // addHash looks like 'tgShareScoreUrl=' + encodeURIComponent('tgb://share_game_score?hash=very_long_hash123')
108 |
109 | var ind = url.indexOf('#');
110 | if (ind < 0) {
111 | // https://game.com/path -> https://game.com/path#tgShareScoreUrl=etc
112 | return url + '#' + addHash;
113 | }
114 | var curHash = url.substr(ind + 1);
115 | if (curHash.indexOf('=') >= 0 || curHash.indexOf('?') >= 0) {
116 | // https://game.com/#hash=1 -> https://game.com/#hash=1&tgShareScoreUrl=etc
117 | // https://game.com/#path?query -> https://game.com/#path?query&tgShareScoreUrl=etc
118 | return url + '&' + addHash;
119 | }
120 | // https://game.com/#hash -> https://game.com/#hash?tgShareScoreUrl=etc
121 | if (curHash.length > 0) {
122 | return url + '?' + addHash;
123 | }
124 | // https://game.com/# -> https://game.com/#tgShareScoreUrl=etc
125 | return url + addHash;
126 | }
127 |
128 | function postEvent(eventType, callback, eventData) {
129 | if (!callback) {
130 | callback = function () {};
131 | }
132 | if (eventData === undefined) {
133 | eventData = '';
134 | }
135 | console.log('[Telegram.WebView] > postEvent', eventType, eventData);
136 |
137 | if (window.TelegramWebviewProxy !== undefined) {
138 | TelegramWebviewProxy.postEvent(eventType, JSON.stringify(eventData));
139 | callback();
140 | }
141 | else if (window.external && 'notify' in window.external) {
142 | window.external.notify(JSON.stringify({eventType: eventType, eventData: eventData}));
143 | callback();
144 | }
145 | else if (isIframe) {
146 | try {
147 | var trustedTarget = 'https://web.telegram.org';
148 | // For now we don't restrict target, for testing purposes
149 | trustedTarget = '*';
150 | window.parent.postMessage(JSON.stringify({eventType: eventType, eventData: eventData}), trustedTarget);
151 | callback();
152 | } catch (e) {
153 | callback(e);
154 | }
155 | }
156 | else {
157 | callback({notAvailable: true});
158 | }
159 | };
160 |
161 | function receiveEvent(eventType, eventData) {
162 | console.log('[Telegram.WebView] < receiveEvent', eventType, eventData);
163 | callEventCallbacks(eventType, function(callback) {
164 | callback(eventType, eventData);
165 | });
166 | }
167 |
168 | function callEventCallbacks(eventType, func) {
169 | var curEventHandlers = eventHandlers[eventType];
170 | if (curEventHandlers === undefined ||
171 | !curEventHandlers.length) {
172 | return;
173 | }
174 | for (var i = 0; i < curEventHandlers.length; i++) {
175 | try {
176 | func(curEventHandlers[i]);
177 | } catch (e) {}
178 | }
179 | }
180 |
181 | function onEvent(eventType, callback) {
182 | if (eventHandlers[eventType] === undefined) {
183 | eventHandlers[eventType] = [];
184 | }
185 | var index = eventHandlers[eventType].indexOf(callback);
186 | if (index === -1) {
187 | eventHandlers[eventType].push(callback);
188 | }
189 | };
190 |
191 | function offEvent(eventType, callback) {
192 | if (eventHandlers[eventType] === undefined) {
193 | return;
194 | }
195 | var index = eventHandlers[eventType].indexOf(callback);
196 | if (index === -1) {
197 | return;
198 | }
199 | eventHandlers[eventType].splice(index, 1);
200 | };
201 |
202 | function openProtoUrl(url) {
203 | if (!url.match(/^(web\+)?tgb?:\/\/./)) {
204 | return false;
205 | }
206 | var useIframe = navigator.userAgent.match(/iOS|iPhone OS|iPhone|iPod|iPad/i) ? true : false;
207 | if (useIframe) {
208 | var iframeContEl = document.getElementById('tgme_frame_cont') || document.body;
209 | var iframeEl = document.createElement('iframe');
210 | iframeContEl.appendChild(iframeEl);
211 | var pageHidden = false;
212 | var enableHidden = function () {
213 | pageHidden = true;
214 | };
215 | window.addEventListener('pagehide', enableHidden, false);
216 | window.addEventListener('blur', enableHidden, false);
217 | if (iframeEl !== null) {
218 | iframeEl.src = url;
219 | }
220 | setTimeout(function() {
221 | if (!pageHidden) {
222 | window.location = url;
223 | }
224 | window.removeEventListener('pagehide', enableHidden, false);
225 | window.removeEventListener('blur', enableHidden, false);
226 | }, 2000);
227 | }
228 | else {
229 | window.location = url;
230 | }
231 | return true;
232 | }
233 |
234 | function sessionStorageSet(key, value) {
235 | try {
236 | window.sessionStorage.setItem('__telegram__' + key, JSON.stringify(value));
237 | return true;
238 | } catch(e) {}
239 | return false;
240 | }
241 | function sessionStorageGet(key) {
242 | try {
243 | return JSON.parse(window.sessionStorage.getItem('__telegram__' + key));
244 | } catch(e) {}
245 | return null;
246 | }
247 |
248 | if (!window.Telegram) {
249 | window.Telegram = {};
250 | }
251 | window.Telegram.WebView = {
252 | initParams: initParams,
253 | isIframe: isIframe,
254 | onEvent: onEvent,
255 | offEvent: offEvent,
256 | postEvent: postEvent,
257 | receiveEvent: receiveEvent,
258 | callEventCallbacks: callEventCallbacks
259 | };
260 |
261 | window.Telegram.Utils = {
262 | urlSafeDecode: urlSafeDecode,
263 | urlParseQueryString: urlParseQueryString,
264 | urlParseHashParams: urlParseHashParams,
265 | urlAppendHashParams: urlAppendHashParams,
266 | sessionStorageSet: sessionStorageSet,
267 | sessionStorageGet: sessionStorageGet
268 | };
269 |
270 | // For Windows Phone app
271 | window.TelegramGameProxy_receiveEvent = receiveEvent;
272 |
273 | // App backward compatibility
274 | window.TelegramGameProxy = {
275 | receiveEvent: receiveEvent
276 | };
277 | })();
278 |
279 | // WebApp
280 | (function () {
281 | var Utils = window.Telegram.Utils;
282 | var WebView = window.Telegram.WebView;
283 | var initParams = WebView.initParams;
284 | var isIframe = WebView.isIframe;
285 |
286 | var WebApp = {};
287 | var webAppInitData = '', webAppInitDataUnsafe = {};
288 | var themeParams = {}, colorScheme = 'light';
289 | var webAppVersion = '6.0';
290 | var webAppPlatform = 'unknown';
291 | var webAppIsActive = true;
292 | var webAppIsFullscreen = false;
293 | var webAppIsOrientationLocked = false;
294 | var webAppBackgroundColor = 'bg_color';
295 | var webAppHeaderColorKey = 'bg_color';
296 | var webAppHeaderColor = null;
297 |
298 | if (initParams.tgWebAppData && initParams.tgWebAppData.length) {
299 | webAppInitData = initParams.tgWebAppData;
300 | webAppInitDataUnsafe = Utils.urlParseQueryString(webAppInitData);
301 | for (var key in webAppInitDataUnsafe) {
302 | var val = webAppInitDataUnsafe[key];
303 | try {
304 | if (val.substr(0, 1) == '{' && val.substr(-1) == '}' ||
305 | val.substr(0, 1) == '[' && val.substr(-1) == ']') {
306 | webAppInitDataUnsafe[key] = JSON.parse(val);
307 | }
308 | } catch (e) {}
309 | }
310 | }
311 | var stored_theme_params = Utils.sessionStorageGet('themeParams');
312 | if (initParams.tgWebAppThemeParams && initParams.tgWebAppThemeParams.length) {
313 | var themeParamsRaw = initParams.tgWebAppThemeParams;
314 | try {
315 | var theme_params = JSON.parse(themeParamsRaw);
316 | if (theme_params) {
317 | setThemeParams(theme_params);
318 | }
319 | } catch (e) {}
320 | }
321 | if (stored_theme_params) {
322 | setThemeParams(stored_theme_params);
323 | }
324 | var stored_def_colors = Utils.sessionStorageGet('defaultColors');
325 | if (initParams.tgWebAppDefaultColors && initParams.tgWebAppDefaultColors.length) {
326 | var defColorsRaw = initParams.tgWebAppDefaultColors;
327 | try {
328 | var def_colors = JSON.parse(defColorsRaw);
329 | if (def_colors) {
330 | setDefaultColors(def_colors);
331 | }
332 | } catch (e) {}
333 | }
334 | if (stored_def_colors) {
335 | setDefaultColors(stored_def_colors);
336 | }
337 | if (initParams.tgWebAppVersion) {
338 | webAppVersion = initParams.tgWebAppVersion;
339 | }
340 | if (initParams.tgWebAppPlatform) {
341 | webAppPlatform = initParams.tgWebAppPlatform;
342 | }
343 |
344 | var stored_fullscreen = Utils.sessionStorageGet('isFullscreen');
345 | if (initParams.tgWebAppFullscreen) {
346 | setFullscreen(true);
347 | }
348 | if (stored_fullscreen) {
349 | setFullscreen(stored_fullscreen == 'yes');
350 | }
351 |
352 | var stored_orientation_lock = Utils.sessionStorageGet('isOrientationLocked');
353 | if (stored_orientation_lock) {
354 | setOrientationLock(stored_orientation_lock == 'yes');
355 | }
356 |
357 | function onThemeChanged(eventType, eventData) {
358 | if (eventData.theme_params) {
359 | setThemeParams(eventData.theme_params);
360 | window.Telegram.WebApp.MainButton.setParams({});
361 | window.Telegram.WebApp.SecondaryButton.setParams({});
362 | updateHeaderColor();
363 | updateBackgroundColor();
364 | updateBottomBarColor();
365 | receiveWebViewEvent('themeChanged');
366 | }
367 | }
368 |
369 | var lastWindowHeight = window.innerHeight;
370 | function onViewportChanged(eventType, eventData) {
371 | if (eventData.height) {
372 | window.removeEventListener('resize', onWindowResize);
373 | setViewportHeight(eventData);
374 | }
375 | }
376 |
377 | function onWindowResize(e) {
378 | if (lastWindowHeight != window.innerHeight) {
379 | lastWindowHeight = window.innerHeight;
380 | receiveWebViewEvent('viewportChanged', {
381 | isStateStable: true
382 | });
383 | }
384 | }
385 |
386 | function onSafeAreaChanged(eventType, eventData) {
387 | if (eventData) {
388 | setSafeAreaInset(eventData);
389 | }
390 | }
391 | function onContentSafeAreaChanged(eventType, eventData) {
392 | if (eventData) {
393 | setContentSafeAreaInset(eventData);
394 | }
395 | }
396 |
397 | function onVisibilityChanged(eventType, eventData) {
398 | if (eventData.is_visible) {
399 | webAppIsActive = true;
400 | receiveWebViewEvent('activated');
401 | } else {
402 | webAppIsActive = false;
403 | receiveWebViewEvent('deactivated');
404 | }
405 | }
406 |
407 | function linkHandler(e) {
408 | if (e.metaKey || e.ctrlKey) return;
409 | var el = e.target;
410 | while (el.tagName != 'A' && el.parentNode) {
411 | el = el.parentNode;
412 | }
413 | if (el.tagName == 'A' &&
414 | el.target != '_blank' &&
415 | (el.protocol == 'http:' || el.protocol == 'https:') &&
416 | el.hostname == 't.me') {
417 | WebApp.openTgLink(el.href);
418 | e.preventDefault();
419 | }
420 | }
421 |
422 | function strTrim(str) {
423 | return str.toString().replace(/^\s+|\s+$/g, '');
424 | }
425 |
426 | function receiveWebViewEvent(eventType) {
427 | var args = Array.prototype.slice.call(arguments);
428 | eventType = args.shift();
429 | WebView.callEventCallbacks('webview:' + eventType, function(callback) {
430 | callback.apply(WebApp, args);
431 | });
432 | }
433 |
434 | function onWebViewEvent(eventType, callback) {
435 | WebView.onEvent('webview:' + eventType, callback);
436 | };
437 |
438 | function offWebViewEvent(eventType, callback) {
439 | WebView.offEvent('webview:' + eventType, callback);
440 | };
441 |
442 | function setCssProperty(name, value) {
443 | var root = document.documentElement;
444 | if (root && root.style && root.style.setProperty) {
445 | root.style.setProperty('--tg-' + name, value);
446 | }
447 | }
448 |
449 | function setFullscreen(is_fullscreen) {
450 | webAppIsFullscreen = !!is_fullscreen;
451 | Utils.sessionStorageSet('isFullscreen', webAppIsFullscreen ? 'yes' : 'no');
452 | }
453 |
454 | function setOrientationLock(is_locked) {
455 | webAppIsOrientationLocked = !!is_locked;
456 | Utils.sessionStorageSet('isOrientationLocked', webAppIsOrientationLocked ? 'yes' : 'no');
457 | }
458 |
459 | function setThemeParams(theme_params) {
460 | // temp iOS fix
461 | if (theme_params.bg_color == '#1c1c1d' &&
462 | theme_params.bg_color == theme_params.secondary_bg_color) {
463 | theme_params.secondary_bg_color = '#2c2c2e';
464 | }
465 | var color;
466 | for (var key in theme_params) {
467 | if (color = parseColorToHex(theme_params[key])) {
468 | themeParams[key] = color;
469 | if (key == 'bg_color') {
470 | colorScheme = isColorDark(color) ? 'dark' : 'light'
471 | setCssProperty('color-scheme', colorScheme);
472 | }
473 | key = 'theme-' + key.split('_').join('-');
474 | setCssProperty(key, color);
475 | }
476 | }
477 | Utils.sessionStorageSet('themeParams', themeParams);
478 | }
479 |
480 | function setDefaultColors(def_colors) {
481 | if (colorScheme == 'dark') {
482 | if (def_colors.bg_dark_color) {
483 | webAppBackgroundColor = def_colors.bg_dark_color;
484 | }
485 | if (def_colors.header_dark_color) {
486 | webAppHeaderColorKey = null;
487 | webAppHeaderColor = def_colors.header_dark_color;
488 | }
489 | } else {
490 | if (def_colors.bg_color) {
491 | webAppBackgroundColor = def_colors.bg_color;
492 | }
493 | if (def_colors.header_color) {
494 | webAppHeaderColorKey = null;
495 | webAppHeaderColor = def_colors.header_color;
496 | }
497 | }
498 | Utils.sessionStorageSet('defaultColors', def_colors);
499 | }
500 |
501 | var webAppCallbacks = {};
502 | function generateCallbackId(len) {
503 | var tries = 100;
504 | while (--tries) {
505 | var id = '', chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', chars_len = chars.length;
506 | for (var i = 0; i < len; i++) {
507 | id += chars[Math.floor(Math.random() * chars_len)];
508 | }
509 | if (!webAppCallbacks[id]) {
510 | webAppCallbacks[id] = {};
511 | return id;
512 | }
513 | }
514 | throw Error('WebAppCallbackIdGenerateFailed');
515 | }
516 |
517 | var viewportHeight = false, viewportStableHeight = false, isExpanded = true;
518 | function setViewportHeight(data) {
519 | if (typeof data !== 'undefined') {
520 | isExpanded = !!data.is_expanded;
521 | viewportHeight = data.height;
522 | if (data.is_state_stable) {
523 | viewportStableHeight = data.height;
524 | }
525 | receiveWebViewEvent('viewportChanged', {
526 | isStateStable: !!data.is_state_stable
527 | });
528 | }
529 | var height, stable_height;
530 | if (viewportHeight !== false) {
531 | height = (viewportHeight - bottomBarHeight) + 'px';
532 | } else {
533 | height = bottomBarHeight ? 'calc(100vh - ' + bottomBarHeight + 'px)' : '100vh';
534 | }
535 | if (viewportStableHeight !== false) {
536 | stable_height = (viewportStableHeight - bottomBarHeight) + 'px';
537 | } else {
538 | stable_height = bottomBarHeight ? 'calc(100vh - ' + bottomBarHeight + 'px)' : '100vh';
539 | }
540 | setCssProperty('viewport-height', height);
541 | setCssProperty('viewport-stable-height', stable_height);
542 | }
543 |
544 | var safeAreaInset = {top: 0, bottom: 0, left: 0, right: 0};
545 | function setSafeAreaInset(data) {
546 | if (typeof data !== 'undefined') {
547 | if (typeof data.top !== 'undefined') {
548 | safeAreaInset.top = data.top;
549 | }
550 | if (typeof data.bottom !== 'undefined') {
551 | safeAreaInset.bottom = data.bottom;
552 | }
553 | if (typeof data.left !== 'undefined') {
554 | safeAreaInset.left = data.left;
555 | }
556 | if (typeof data.right !== 'undefined') {
557 | safeAreaInset.right = data.right;
558 | }
559 | receiveWebViewEvent('safeAreaChanged');
560 | }
561 | setCssProperty('safe-area-inset-top', safeAreaInset.top + 'px');
562 | setCssProperty('safe-area-inset-bottom', safeAreaInset.bottom + 'px');
563 | setCssProperty('safe-area-inset-left', safeAreaInset.left + 'px');
564 | setCssProperty('safe-area-inset-right', safeAreaInset.right + 'px');
565 | }
566 |
567 | var contentSafeAreaInset = {top: 0, bottom: 0, left: 0, right: 0};
568 | function setContentSafeAreaInset(data) {
569 | if (typeof data !== 'undefined') {
570 | if (typeof data.top !== 'undefined') {
571 | contentSafeAreaInset.top = data.top;
572 | }
573 | if (typeof data.bottom !== 'undefined') {
574 | contentSafeAreaInset.bottom = data.bottom;
575 | }
576 | if (typeof data.left !== 'undefined') {
577 | contentSafeAreaInset.left = data.left;
578 | }
579 | if (typeof data.right !== 'undefined') {
580 | contentSafeAreaInset.right = data.right;
581 | }
582 | receiveWebViewEvent('contentSafeAreaChanged');
583 | }
584 | setCssProperty('content-safe-area-inset-top', contentSafeAreaInset.top + 'px');
585 | setCssProperty('content-safe-area-inset-bottom', contentSafeAreaInset.bottom + 'px');
586 | setCssProperty('content-safe-area-inset-left', contentSafeAreaInset.left + 'px');
587 | setCssProperty('content-safe-area-inset-right', contentSafeAreaInset.right + 'px');
588 | }
589 |
590 | var isClosingConfirmationEnabled = false;
591 | function setClosingConfirmation(need_confirmation) {
592 | if (!versionAtLeast('6.2')) {
593 | console.warn('[Telegram.WebApp] Closing confirmation is not supported in version ' + webAppVersion);
594 | return;
595 | }
596 | isClosingConfirmationEnabled = !!need_confirmation;
597 | WebView.postEvent('web_app_setup_closing_behavior', false, {need_confirmation: isClosingConfirmationEnabled});
598 | }
599 |
600 | var isVerticalSwipesEnabled = true;
601 | function toggleVerticalSwipes(enable_swipes) {
602 | if (!versionAtLeast('7.7')) {
603 | console.warn('[Telegram.WebApp] Changing swipes behavior is not supported in version ' + webAppVersion);
604 | return;
605 | }
606 | isVerticalSwipesEnabled = !!enable_swipes;
607 | WebView.postEvent('web_app_setup_swipe_behavior', false, {allow_vertical_swipe: isVerticalSwipesEnabled});
608 | }
609 |
610 | function onFullscreenChanged(eventType, eventData) {
611 | setFullscreen(eventData.is_fullscreen);
612 | receiveWebViewEvent('fullscreenChanged');
613 | }
614 | function onFullscreenFailed(eventType, eventData) {
615 | if (eventData.error == 'ALREADY_FULLSCREEN' && !webAppIsFullscreen) {
616 | setFullscreen(true);
617 | }
618 | receiveWebViewEvent('fullscreenFailed', {
619 | error: eventData.error
620 | });
621 | }
622 |
623 | function toggleOrientationLock(locked) {
624 | if (!versionAtLeast('8.0')) {
625 | console.warn('[Telegram.WebApp] Orientation locking is not supported in version ' + webAppVersion);
626 | return;
627 | }
628 | setOrientationLock(locked);
629 | WebView.postEvent('web_app_toggle_orientation_lock', false, {locked: webAppIsOrientationLocked});
630 | }
631 |
632 | var homeScreenCallbacks = [];
633 | function onHomeScreenAdded(eventType, eventData) {
634 | receiveWebViewEvent('homeScreenAdded');
635 | }
636 | function onHomeScreenChecked(eventType, eventData) {
637 | var status = eventData.status || 'unknown';
638 | if (homeScreenCallbacks.length > 0) {
639 | for (var i = 0; i < homeScreenCallbacks.length; i++) {
640 | var callback = homeScreenCallbacks[i];
641 | callback(status);
642 | }
643 | homeScreenCallbacks = [];
644 | }
645 | receiveWebViewEvent('homeScreenChecked', {
646 | status: status
647 | });
648 | }
649 |
650 | var WebAppShareMessageOpened = false;
651 | function onPreparedMessageSent(eventType, eventData) {
652 | if (WebAppShareMessageOpened) {
653 | var requestData = WebAppShareMessageOpened;
654 | WebAppShareMessageOpened = false;
655 | if (requestData.callback) {
656 | requestData.callback(true);
657 | }
658 | receiveWebViewEvent('shareMessageSent');
659 | }
660 | }
661 | function onPreparedMessageFailed(eventType, eventData) {
662 | if (WebAppShareMessageOpened) {
663 | var requestData = WebAppShareMessageOpened;
664 | WebAppShareMessageOpened = false;
665 | if (requestData.callback) {
666 | requestData.callback(false);
667 | }
668 | receiveWebViewEvent('shareMessageFailed', {
669 | error: eventData.error
670 | });
671 | }
672 | }
673 |
674 | var WebAppEmojiStatusRequested = false;
675 | function onEmojiStatusSet(eventType, eventData) {
676 | if (WebAppEmojiStatusRequested) {
677 | var requestData = WebAppEmojiStatusRequested;
678 | WebAppEmojiStatusRequested = false;
679 | if (requestData.callback) {
680 | requestData.callback(true);
681 | }
682 | receiveWebViewEvent('emojiStatusSet');
683 | }
684 | }
685 | function onEmojiStatusFailed(eventType, eventData) {
686 | if (WebAppEmojiStatusRequested) {
687 | var requestData = WebAppEmojiStatusRequested;
688 | WebAppEmojiStatusRequested = false;
689 | if (requestData.callback) {
690 | requestData.callback(false);
691 | }
692 | receiveWebViewEvent('emojiStatusFailed', {
693 | error: eventData.error
694 | });
695 | }
696 | }
697 | var WebAppEmojiStatusAccessRequested = false;
698 | function onEmojiStatusAccessRequested(eventType, eventData) {
699 | if (WebAppEmojiStatusAccessRequested) {
700 | var requestData = WebAppEmojiStatusAccessRequested;
701 | WebAppEmojiStatusAccessRequested = false;
702 | if (requestData.callback) {
703 | requestData.callback(eventData.status == 'allowed');
704 | }
705 | receiveWebViewEvent('emojiStatusAccessRequested', {
706 | status: eventData.status
707 | });
708 | }
709 | }
710 |
711 | var webAppPopupOpened = false;
712 | function onPopupClosed(eventType, eventData) {
713 | if (webAppPopupOpened) {
714 | var popupData = webAppPopupOpened;
715 | webAppPopupOpened = false;
716 | var button_id = null;
717 | if (typeof eventData.button_id !== 'undefined') {
718 | button_id = eventData.button_id;
719 | }
720 | if (popupData.callback) {
721 | popupData.callback(button_id);
722 | }
723 | receiveWebViewEvent('popupClosed', {
724 | button_id: button_id
725 | });
726 | }
727 | }
728 |
729 |
730 | function getHeaderColor() {
731 | if (webAppHeaderColorKey == 'secondary_bg_color') {
732 | return themeParams.secondary_bg_color;
733 | } else if (webAppHeaderColorKey == 'bg_color') {
734 | return themeParams.bg_color;
735 | }
736 | return webAppHeaderColor;
737 | }
738 | function setHeaderColor(color) {
739 | if (!versionAtLeast('6.1')) {
740 | console.warn('[Telegram.WebApp] Header color is not supported in version ' + webAppVersion);
741 | return;
742 | }
743 | if (!versionAtLeast('6.9')) {
744 | if (themeParams.bg_color &&
745 | themeParams.bg_color == color) {
746 | color = 'bg_color';
747 | } else if (themeParams.secondary_bg_color &&
748 | themeParams.secondary_bg_color == color) {
749 | color = 'secondary_bg_color';
750 | }
751 | }
752 | var head_color = null, color_key = null;
753 | if (color == 'bg_color' || color == 'secondary_bg_color') {
754 | color_key = color;
755 | } else if (versionAtLeast('6.9')) {
756 | head_color = parseColorToHex(color);
757 | if (!head_color) {
758 | console.error('[Telegram.WebApp] Header color format is invalid', color);
759 | throw Error('WebAppHeaderColorInvalid');
760 | }
761 | }
762 | if (!versionAtLeast('6.9') &&
763 | color_key != 'bg_color' &&
764 | color_key != 'secondary_bg_color') {
765 | console.error('[Telegram.WebApp] Header color key should be one of Telegram.WebApp.themeParams.bg_color, Telegram.WebApp.themeParams.secondary_bg_color, \'bg_color\', \'secondary_bg_color\'', color);
766 | throw Error('WebAppHeaderColorKeyInvalid');
767 | }
768 | webAppHeaderColorKey = color_key;
769 | webAppHeaderColor = head_color;
770 | updateHeaderColor();
771 | }
772 | var appHeaderColorKey = null, appHeaderColor = null;
773 | function updateHeaderColor() {
774 | if (appHeaderColorKey != webAppHeaderColorKey ||
775 | appHeaderColor != webAppHeaderColor) {
776 | appHeaderColorKey = webAppHeaderColorKey;
777 | appHeaderColor = webAppHeaderColor;
778 | if (appHeaderColor) {
779 | WebView.postEvent('web_app_set_header_color', false, {color: webAppHeaderColor});
780 | } else {
781 | WebView.postEvent('web_app_set_header_color', false, {color_key: webAppHeaderColorKey});
782 | }
783 | }
784 | }
785 |
786 | function getBackgroundColor() {
787 | if (webAppBackgroundColor == 'secondary_bg_color') {
788 | return themeParams.secondary_bg_color;
789 | } else if (webAppBackgroundColor == 'bg_color') {
790 | return themeParams.bg_color;
791 | }
792 | return webAppBackgroundColor;
793 | }
794 | function setBackgroundColor(color) {
795 | if (!versionAtLeast('6.1')) {
796 | console.warn('[Telegram.WebApp] Background color is not supported in version ' + webAppVersion);
797 | return;
798 | }
799 | var bg_color;
800 | if (color == 'bg_color' || color == 'secondary_bg_color') {
801 | bg_color = color;
802 | } else {
803 | bg_color = parseColorToHex(color);
804 | if (!bg_color) {
805 | console.error('[Telegram.WebApp] Background color format is invalid', color);
806 | throw Error('WebAppBackgroundColorInvalid');
807 | }
808 | }
809 | webAppBackgroundColor = bg_color;
810 | updateBackgroundColor();
811 | }
812 | var appBackgroundColor = null;
813 | function updateBackgroundColor() {
814 | var color = getBackgroundColor();
815 | if (appBackgroundColor != color) {
816 | appBackgroundColor = color;
817 | WebView.postEvent('web_app_set_background_color', false, {color: color});
818 | }
819 | }
820 |
821 | var bottomBarColor = 'bottom_bar_bg_color';
822 | function getBottomBarColor() {
823 | if (bottomBarColor == 'bottom_bar_bg_color') {
824 | return themeParams.bottom_bar_bg_color || themeParams.secondary_bg_color || '#ffffff';
825 | } else if (bottomBarColor == 'secondary_bg_color') {
826 | return themeParams.secondary_bg_color;
827 | } else if (bottomBarColor == 'bg_color') {
828 | return themeParams.bg_color;
829 | }
830 | return bottomBarColor;
831 | }
832 | function setBottomBarColor(color) {
833 | if (!versionAtLeast('7.10')) {
834 | console.warn('[Telegram.WebApp] Bottom bar color is not supported in version ' + webAppVersion);
835 | return;
836 | }
837 | var bg_color;
838 | if (color == 'bg_color' || color == 'secondary_bg_color' || color == 'bottom_bar_bg_color') {
839 | bg_color = color;
840 | } else {
841 | bg_color = parseColorToHex(color);
842 | if (!bg_color) {
843 | console.error('[Telegram.WebApp] Bottom bar color format is invalid', color);
844 | throw Error('WebAppBottomBarColorInvalid');
845 | }
846 | }
847 | bottomBarColor = bg_color;
848 | updateBottomBarColor();
849 | window.Telegram.WebApp.SecondaryButton.setParams({});
850 | }
851 | var appBottomBarColor = null;
852 | function updateBottomBarColor() {
853 | var color = getBottomBarColor();
854 | if (appBottomBarColor != color) {
855 | appBottomBarColor = color;
856 | WebView.postEvent('web_app_set_bottom_bar_color', false, {color: color});
857 | }
858 | if (initParams.tgWebAppDebug) {
859 | updateDebugBottomBar();
860 | }
861 | }
862 |
863 |
864 | function parseColorToHex(color) {
865 | color += '';
866 | var match;
867 | if (match = /^\s*#([0-9a-f]{6})\s*$/i.exec(color)) {
868 | return '#' + match[1].toLowerCase();
869 | }
870 | else if (match = /^\s*#([0-9a-f])([0-9a-f])([0-9a-f])\s*$/i.exec(color)) {
871 | return ('#' + match[1] + match[1] + match[2] + match[2] + match[3] + match[3]).toLowerCase();
872 | }
873 | else if (match = /^\s*rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)\s*$/.exec(color)) {
874 | var r = parseInt(match[1]), g = parseInt(match[2]), b = parseInt(match[3]);
875 | r = (r < 16 ? '0' : '') + r.toString(16);
876 | g = (g < 16 ? '0' : '') + g.toString(16);
877 | b = (b < 16 ? '0' : '') + b.toString(16);
878 | return '#' + r + g + b;
879 | }
880 | return false;
881 | }
882 |
883 | function isColorDark(rgb) {
884 | rgb = rgb.replace(/[\s#]/g, '');
885 | if (rgb.length == 3) {
886 | rgb = rgb[0] + rgb[0] + rgb[1] + rgb[1] + rgb[2] + rgb[2];
887 | }
888 | var r = parseInt(rgb.substr(0, 2), 16);
889 | var g = parseInt(rgb.substr(2, 2), 16);
890 | var b = parseInt(rgb.substr(4, 2), 16);
891 | var hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
892 | return hsp < 120;
893 | }
894 |
895 | function versionCompare(v1, v2) {
896 | if (typeof v1 !== 'string') v1 = '';
897 | if (typeof v2 !== 'string') v2 = '';
898 | v1 = v1.replace(/^\s+|\s+$/g, '').split('.');
899 | v2 = v2.replace(/^\s+|\s+$/g, '').split('.');
900 | var a = Math.max(v1.length, v2.length), i, p1, p2;
901 | for (i = 0; i < a; i++) {
902 | p1 = parseInt(v1[i]) || 0;
903 | p2 = parseInt(v2[i]) || 0;
904 | if (p1 == p2) continue;
905 | if (p1 > p2) return 1;
906 | return -1;
907 | }
908 | return 0;
909 | }
910 |
911 | function versionAtLeast(ver) {
912 | return versionCompare(webAppVersion, ver) >= 0;
913 | }
914 |
915 | function byteLength(str) {
916 | if (window.Blob) {
917 | try { return new Blob([str]).size; } catch (e) {}
918 | }
919 | var s = str.length;
920 | for (var i=str.length-1; i>=0; i--) {
921 | var code = str.charCodeAt(i);
922 | if (code > 0x7f && code <= 0x7ff) s++;
923 | else if (code > 0x7ff && code <= 0xffff) s+=2;
924 | if (code >= 0xdc00 && code <= 0xdfff) i--;
925 | }
926 | return s;
927 | }
928 |
929 | var BackButton = (function() {
930 | var isVisible = false;
931 |
932 | var backButton = {};
933 | Object.defineProperty(backButton, 'isVisible', {
934 | set: function(val){ setParams({is_visible: val}); },
935 | get: function(){ return isVisible; },
936 | enumerable: true
937 | });
938 |
939 | var curButtonState = null;
940 |
941 | WebView.onEvent('back_button_pressed', onBackButtonPressed);
942 |
943 | function onBackButtonPressed() {
944 | receiveWebViewEvent('backButtonClicked');
945 | }
946 |
947 | function buttonParams() {
948 | return {is_visible: isVisible};
949 | }
950 |
951 | function buttonState(btn_params) {
952 | if (typeof btn_params === 'undefined') {
953 | btn_params = buttonParams();
954 | }
955 | return JSON.stringify(btn_params);
956 | }
957 |
958 | function buttonCheckVersion() {
959 | if (!versionAtLeast('6.1')) {
960 | console.warn('[Telegram.WebApp] BackButton is not supported in version ' + webAppVersion);
961 | return false;
962 | }
963 | return true;
964 | }
965 |
966 | function updateButton() {
967 | var btn_params = buttonParams();
968 | var btn_state = buttonState(btn_params);
969 | if (curButtonState === btn_state) {
970 | return;
971 | }
972 | curButtonState = btn_state;
973 | WebView.postEvent('web_app_setup_back_button', false, btn_params);
974 | }
975 |
976 | function setParams(params) {
977 | if (!buttonCheckVersion()) {
978 | return backButton;
979 | }
980 | if (typeof params.is_visible !== 'undefined') {
981 | isVisible = !!params.is_visible;
982 | }
983 | updateButton();
984 | return backButton;
985 | }
986 |
987 | backButton.onClick = function(callback) {
988 | if (buttonCheckVersion()) {
989 | onWebViewEvent('backButtonClicked', callback);
990 | }
991 | return backButton;
992 | };
993 | backButton.offClick = function(callback) {
994 | if (buttonCheckVersion()) {
995 | offWebViewEvent('backButtonClicked', callback);
996 | }
997 | return backButton;
998 | };
999 | backButton.show = function() {
1000 | return setParams({is_visible: true});
1001 | };
1002 | backButton.hide = function() {
1003 | return setParams({is_visible: false});
1004 | };
1005 | return backButton;
1006 | })();
1007 |
1008 | var debugBottomBar = null, debugBottomBarBtns = {}, bottomBarHeight = 0;
1009 | if (initParams.tgWebAppDebug) {
1010 | debugBottomBar = document.createElement('tg-bottom-bar');
1011 | var debugBottomBarStyle = {
1012 | display: 'flex',
1013 | gap: '7px',
1014 | font: '600 14px/18px sans-serif',
1015 | width: '100%',
1016 | background: getBottomBarColor(),
1017 | position: 'fixed',
1018 | left: '0',
1019 | right: '0',
1020 | bottom: '0',
1021 | margin: '0',
1022 | padding: '7px',
1023 | textAlign: 'center',
1024 | boxSizing: 'border-box',
1025 | zIndex: '10000'
1026 | };
1027 | for (var k in debugBottomBarStyle) {
1028 | debugBottomBar.style[k] = debugBottomBarStyle[k];
1029 | }
1030 | document.addEventListener('DOMContentLoaded', function onDomLoaded(event) {
1031 | document.removeEventListener('DOMContentLoaded', onDomLoaded);
1032 | document.body.appendChild(debugBottomBar);
1033 | });
1034 | var animStyle = document.createElement('style');
1035 | animStyle.innerHTML = 'tg-bottom-button.shine { position: relative; overflow: hidden; } tg-bottom-button.shine:before { content:""; position: absolute; top: 0; width: 100%; height: 100%; background: linear-gradient(120deg, transparent, rgba(255, 255, 255, .2), transparent); animation: tg-bottom-button-shine 5s ease-in-out infinite; } @-webkit-keyframes tg-bottom-button-shine { 0% {left: -100%;} 12%,100% {left: 100%}} @keyframes tg-bottom-button-shine { 0% {left: -100%;} 12%,100% {left: 100%}}';
1036 | debugBottomBar.appendChild(animStyle);
1037 | }
1038 | function updateDebugBottomBar() {
1039 | var mainBtn = debugBottomBarBtns.main._bottomButton;
1040 | var secondaryBtn = debugBottomBarBtns.secondary._bottomButton;
1041 | if (mainBtn.isVisible || secondaryBtn.isVisible) {
1042 | debugBottomBar.style.display = 'flex';
1043 | bottomBarHeight = 58;
1044 | if (mainBtn.isVisible && secondaryBtn.isVisible) {
1045 | if (secondaryBtn.position == 'top') {
1046 | debugBottomBar.style.flexDirection = 'column-reverse';
1047 | bottomBarHeight += 51;
1048 | } else if (secondaryBtn.position == 'bottom') {
1049 | debugBottomBar.style.flexDirection = 'column';
1050 | bottomBarHeight += 51;
1051 | } else if (secondaryBtn.position == 'left') {
1052 | debugBottomBar.style.flexDirection = 'row-reverse';
1053 | } else if (secondaryBtn.position == 'right') {
1054 | debugBottomBar.style.flexDirection = 'row';
1055 | }
1056 | }
1057 | } else {
1058 | debugBottomBar.style.display = 'none';
1059 | bottomBarHeight = 0;
1060 | }
1061 | debugBottomBar.style.background = getBottomBarColor();
1062 | if (document.documentElement) {
1063 | document.documentElement.style.boxSizing = 'border-box';
1064 | document.documentElement.style.paddingBottom = bottomBarHeight + 'px';
1065 | }
1066 | setViewportHeight();
1067 | }
1068 |
1069 |
1070 | var BottomButtonConstructor = function(type) {
1071 | var isMainButton = (type == 'main');
1072 | if (isMainButton) {
1073 | var setupFnName = 'web_app_setup_main_button';
1074 | var tgEventName = 'main_button_pressed';
1075 | var webViewEventName = 'mainButtonClicked';
1076 | var buttonTextDefault = 'Continue';
1077 | var buttonColorDefault = function(){ return themeParams.button_color || '#2481cc'; };
1078 | var buttonTextColorDefault = function(){ return themeParams.button_text_color || '#ffffff'; };
1079 | } else {
1080 | var setupFnName = 'web_app_setup_secondary_button';
1081 | var tgEventName = 'secondary_button_pressed';
1082 | var webViewEventName = 'secondaryButtonClicked';
1083 | var buttonTextDefault = 'Cancel';
1084 | var buttonColorDefault = function(){ return getBottomBarColor(); };
1085 | var buttonTextColorDefault = function(){ return themeParams.button_color || '#2481cc'; };
1086 | }
1087 |
1088 | var isVisible = false;
1089 | var isActive = true;
1090 | var hasShineEffect = false;
1091 | var isProgressVisible = false;
1092 | var buttonType = type;
1093 | var buttonText = buttonTextDefault;
1094 | var buttonColor = false;
1095 | var buttonTextColor = false;
1096 | var buttonPosition = 'left';
1097 |
1098 | var bottomButton = {};
1099 | Object.defineProperty(bottomButton, 'type', {
1100 | get: function(){ return buttonType; },
1101 | enumerable: true
1102 | });
1103 | Object.defineProperty(bottomButton, 'text', {
1104 | set: function(val){ bottomButton.setParams({text: val}); },
1105 | get: function(){ return buttonText; },
1106 | enumerable: true
1107 | });
1108 | Object.defineProperty(bottomButton, 'color', {
1109 | set: function(val){ bottomButton.setParams({color: val}); },
1110 | get: function(){ return buttonColor || buttonColorDefault(); },
1111 | enumerable: true
1112 | });
1113 | Object.defineProperty(bottomButton, 'textColor', {
1114 | set: function(val){ bottomButton.setParams({text_color: val}); },
1115 | get: function(){ return buttonTextColor || buttonTextColorDefault(); },
1116 | enumerable: true
1117 | });
1118 | Object.defineProperty(bottomButton, 'isVisible', {
1119 | set: function(val){ bottomButton.setParams({is_visible: val}); },
1120 | get: function(){ return isVisible; },
1121 | enumerable: true
1122 | });
1123 | Object.defineProperty(bottomButton, 'isProgressVisible', {
1124 | get: function(){ return isProgressVisible; },
1125 | enumerable: true
1126 | });
1127 | Object.defineProperty(bottomButton, 'isActive', {
1128 | set: function(val){ bottomButton.setParams({is_active: val}); },
1129 | get: function(){ return isActive; },
1130 | enumerable: true
1131 | });
1132 | Object.defineProperty(bottomButton, 'hasShineEffect', {
1133 | set: function(val){ bottomButton.setParams({has_shine_effect: val}); },
1134 | get: function(){ return hasShineEffect; },
1135 | enumerable: true
1136 | });
1137 | if (!isMainButton) {
1138 | Object.defineProperty(bottomButton, 'position', {
1139 | set: function(val){ bottomButton.setParams({position: val}); },
1140 | get: function(){ return buttonPosition; },
1141 | enumerable: true
1142 | });
1143 | }
1144 |
1145 | var curButtonState = null;
1146 |
1147 | WebView.onEvent(tgEventName, onBottomButtonPressed);
1148 |
1149 | var debugBtn = null;
1150 | if (initParams.tgWebAppDebug) {
1151 | debugBtn = document.createElement('tg-bottom-button');
1152 | var debugBtnStyle = {
1153 | display: 'none',
1154 | width: '100%',
1155 | height: '44px',
1156 | borderRadius: '0',
1157 | background: 'no-repeat right center',
1158 | padding: '13px 15px',
1159 | textAlign: 'center',
1160 | boxSizing: 'border-box'
1161 | };
1162 | for (var k in debugBtnStyle) {
1163 | debugBtn.style[k] = debugBtnStyle[k];
1164 | }
1165 | debugBottomBar.appendChild(debugBtn);
1166 | debugBtn.addEventListener('click', onBottomButtonPressed, false);
1167 | debugBtn._bottomButton = bottomButton;
1168 | debugBottomBarBtns[type] = debugBtn;
1169 | }
1170 |
1171 | function onBottomButtonPressed() {
1172 | if (isActive) {
1173 | receiveWebViewEvent(webViewEventName);
1174 | }
1175 | }
1176 |
1177 | function buttonParams() {
1178 | var color = bottomButton.color;
1179 | var text_color = bottomButton.textColor;
1180 | if (isVisible) {
1181 | var params = {
1182 | is_visible: true,
1183 | is_active: isActive,
1184 | is_progress_visible: isProgressVisible,
1185 | text: buttonText,
1186 | color: color,
1187 | text_color: text_color,
1188 | has_shine_effect: hasShineEffect && isActive && !isProgressVisible
1189 | };
1190 | if (!isMainButton) {
1191 | params.position = buttonPosition;
1192 | }
1193 | } else {
1194 | var params = {
1195 | is_visible: false
1196 | };
1197 | }
1198 | return params;
1199 | }
1200 |
1201 | function buttonState(btn_params) {
1202 | if (typeof btn_params === 'undefined') {
1203 | btn_params = buttonParams();
1204 | }
1205 | return JSON.stringify(btn_params);
1206 | }
1207 |
1208 | function updateButton() {
1209 | var btn_params = buttonParams();
1210 | var btn_state = buttonState(btn_params);
1211 | if (curButtonState === btn_state) {
1212 | return;
1213 | }
1214 | curButtonState = btn_state;
1215 | WebView.postEvent(setupFnName, false, btn_params);
1216 | if (initParams.tgWebAppDebug) {
1217 | updateDebugButton(btn_params);
1218 | }
1219 | }
1220 |
1221 | function updateDebugButton(btn_params) {
1222 | if (btn_params.is_visible) {
1223 | debugBtn.style.display = 'block';
1224 |
1225 | debugBtn.style.opacity = btn_params.is_active ? '1' : '0.8';
1226 | debugBtn.style.cursor = btn_params.is_active ? 'pointer' : 'auto';
1227 | debugBtn.disabled = !btn_params.is_active;
1228 | debugBtn.innerText = btn_params.text;
1229 | debugBtn.className = btn_params.has_shine_effect ? 'shine' : '';
1230 | debugBtn.style.backgroundImage = btn_params.is_progress_visible ? "url('data:image/svg+xml," + encodeURIComponent('') + "')" : 'none';
1231 | debugBtn.style.backgroundColor = btn_params.color;
1232 | debugBtn.style.color = btn_params.text_color;
1233 | } else {
1234 | debugBtn.style.display = 'none';
1235 | }
1236 | updateDebugBottomBar();
1237 | }
1238 |
1239 | function setParams(params) {
1240 | if (typeof params.text !== 'undefined') {
1241 | var text = strTrim(params.text);
1242 | if (!text.length) {
1243 | console.error('[Telegram.WebApp] Bottom button text is required', params.text);
1244 | throw Error('WebAppBottomButtonParamInvalid');
1245 | }
1246 | if (text.length > 64) {
1247 | console.error('[Telegram.WebApp] Bottom button text is too long', text);
1248 | throw Error('WebAppBottomButtonParamInvalid');
1249 | }
1250 | buttonText = text;
1251 | }
1252 | if (typeof params.color !== 'undefined') {
1253 | if (params.color === false ||
1254 | params.color === null) {
1255 | buttonColor = false;
1256 | } else {
1257 | var color = parseColorToHex(params.color);
1258 | if (!color) {
1259 | console.error('[Telegram.WebApp] Bottom button color format is invalid', params.color);
1260 | throw Error('WebAppBottomButtonParamInvalid');
1261 | }
1262 | buttonColor = color;
1263 | }
1264 | }
1265 | if (typeof params.text_color !== 'undefined') {
1266 | if (params.text_color === false ||
1267 | params.text_color === null) {
1268 | buttonTextColor = false;
1269 | } else {
1270 | var text_color = parseColorToHex(params.text_color);
1271 | if (!text_color) {
1272 | console.error('[Telegram.WebApp] Bottom button text color format is invalid', params.text_color);
1273 | throw Error('WebAppBottomButtonParamInvalid');
1274 | }
1275 | buttonTextColor = text_color;
1276 | }
1277 | }
1278 | if (typeof params.is_visible !== 'undefined') {
1279 | if (params.is_visible &&
1280 | !bottomButton.text.length) {
1281 | console.error('[Telegram.WebApp] Bottom button text is required');
1282 | throw Error('WebAppBottomButtonParamInvalid');
1283 | }
1284 | isVisible = !!params.is_visible;
1285 | }
1286 | if (typeof params.has_shine_effect !== 'undefined') {
1287 | hasShineEffect = !!params.has_shine_effect;
1288 | }
1289 | if (!isMainButton && typeof params.position !== 'undefined') {
1290 | if (params.position != 'left' && params.position != 'right' &&
1291 | params.position != 'top' && params.position != 'bottom') {
1292 | console.error('[Telegram.WebApp] Bottom button posiition is invalid', params.position);
1293 | throw Error('WebAppBottomButtonParamInvalid');
1294 | }
1295 | buttonPosition = params.position;
1296 | }
1297 | if (typeof params.is_active !== 'undefined') {
1298 | isActive = !!params.is_active;
1299 | }
1300 | updateButton();
1301 | return bottomButton;
1302 | }
1303 |
1304 | bottomButton.setText = function(text) {
1305 | return bottomButton.setParams({text: text});
1306 | };
1307 | bottomButton.onClick = function(callback) {
1308 | onWebViewEvent(webViewEventName, callback);
1309 | return bottomButton;
1310 | };
1311 | bottomButton.offClick = function(callback) {
1312 | offWebViewEvent(webViewEventName, callback);
1313 | return bottomButton;
1314 | };
1315 | bottomButton.show = function() {
1316 | return bottomButton.setParams({is_visible: true});
1317 | };
1318 | bottomButton.hide = function() {
1319 | return bottomButton.setParams({is_visible: false});
1320 | };
1321 | bottomButton.enable = function() {
1322 | return bottomButton.setParams({is_active: true});
1323 | };
1324 | bottomButton.disable = function() {
1325 | return bottomButton.setParams({is_active: false});
1326 | };
1327 | bottomButton.showProgress = function(leaveActive) {
1328 | isActive = !!leaveActive;
1329 | isProgressVisible = true;
1330 | updateButton();
1331 | return bottomButton;
1332 | };
1333 | bottomButton.hideProgress = function() {
1334 | if (!bottomButton.isActive) {
1335 | isActive = true;
1336 | }
1337 | isProgressVisible = false;
1338 | updateButton();
1339 | return bottomButton;
1340 | }
1341 | bottomButton.setParams = setParams;
1342 | return bottomButton;
1343 | };
1344 | var MainButton = BottomButtonConstructor('main');
1345 | var SecondaryButton = BottomButtonConstructor('secondary');
1346 |
1347 | var SettingsButton = (function() {
1348 | var isVisible = false;
1349 |
1350 | var settingsButton = {};
1351 | Object.defineProperty(settingsButton, 'isVisible', {
1352 | set: function(val){ setParams({is_visible: val}); },
1353 | get: function(){ return isVisible; },
1354 | enumerable: true
1355 | });
1356 |
1357 | var curButtonState = null;
1358 |
1359 | WebView.onEvent('settings_button_pressed', onSettingsButtonPressed);
1360 |
1361 | function onSettingsButtonPressed() {
1362 | receiveWebViewEvent('settingsButtonClicked');
1363 | }
1364 |
1365 | function buttonParams() {
1366 | return {is_visible: isVisible};
1367 | }
1368 |
1369 | function buttonState(btn_params) {
1370 | if (typeof btn_params === 'undefined') {
1371 | btn_params = buttonParams();
1372 | }
1373 | return JSON.stringify(btn_params);
1374 | }
1375 |
1376 | function buttonCheckVersion() {
1377 | if (!versionAtLeast('6.10')) {
1378 | console.warn('[Telegram.WebApp] SettingsButton is not supported in version ' + webAppVersion);
1379 | return false;
1380 | }
1381 | return true;
1382 | }
1383 |
1384 | function updateButton() {
1385 | var btn_params = buttonParams();
1386 | var btn_state = buttonState(btn_params);
1387 | if (curButtonState === btn_state) {
1388 | return;
1389 | }
1390 | curButtonState = btn_state;
1391 | WebView.postEvent('web_app_setup_settings_button', false, btn_params);
1392 | }
1393 |
1394 | function setParams(params) {
1395 | if (!buttonCheckVersion()) {
1396 | return settingsButton;
1397 | }
1398 | if (typeof params.is_visible !== 'undefined') {
1399 | isVisible = !!params.is_visible;
1400 | }
1401 | updateButton();
1402 | return settingsButton;
1403 | }
1404 |
1405 | settingsButton.onClick = function(callback) {
1406 | if (buttonCheckVersion()) {
1407 | onWebViewEvent('settingsButtonClicked', callback);
1408 | }
1409 | return settingsButton;
1410 | };
1411 | settingsButton.offClick = function(callback) {
1412 | if (buttonCheckVersion()) {
1413 | offWebViewEvent('settingsButtonClicked', callback);
1414 | }
1415 | return settingsButton;
1416 | };
1417 | settingsButton.show = function() {
1418 | return setParams({is_visible: true});
1419 | };
1420 | settingsButton.hide = function() {
1421 | return setParams({is_visible: false});
1422 | };
1423 | return settingsButton;
1424 | })();
1425 |
1426 | var HapticFeedback = (function() {
1427 | var hapticFeedback = {};
1428 |
1429 | function triggerFeedback(params) {
1430 | if (!versionAtLeast('6.1')) {
1431 | console.warn('[Telegram.WebApp] HapticFeedback is not supported in version ' + webAppVersion);
1432 | return hapticFeedback;
1433 | }
1434 | if (params.type == 'impact') {
1435 | if (params.impact_style != 'light' &&
1436 | params.impact_style != 'medium' &&
1437 | params.impact_style != 'heavy' &&
1438 | params.impact_style != 'rigid' &&
1439 | params.impact_style != 'soft') {
1440 | console.error('[Telegram.WebApp] Haptic impact style is invalid', params.impact_style);
1441 | throw Error('WebAppHapticImpactStyleInvalid');
1442 | }
1443 | } else if (params.type == 'notification') {
1444 | if (params.notification_type != 'error' &&
1445 | params.notification_type != 'success' &&
1446 | params.notification_type != 'warning') {
1447 | console.error('[Telegram.WebApp] Haptic notification type is invalid', params.notification_type);
1448 | throw Error('WebAppHapticNotificationTypeInvalid');
1449 | }
1450 | } else if (params.type == 'selection_change') {
1451 | // no params needed
1452 | } else {
1453 | console.error('[Telegram.WebApp] Haptic feedback type is invalid', params.type);
1454 | throw Error('WebAppHapticFeedbackTypeInvalid');
1455 | }
1456 | WebView.postEvent('web_app_trigger_haptic_feedback', false, params);
1457 | return hapticFeedback;
1458 | }
1459 |
1460 | hapticFeedback.impactOccurred = function(style) {
1461 | return triggerFeedback({type: 'impact', impact_style: style});
1462 | };
1463 | hapticFeedback.notificationOccurred = function(type) {
1464 | return triggerFeedback({type: 'notification', notification_type: type});
1465 | };
1466 | hapticFeedback.selectionChanged = function() {
1467 | return triggerFeedback({type: 'selection_change'});
1468 | };
1469 | return hapticFeedback;
1470 | })();
1471 |
1472 | var CloudStorage = (function() {
1473 | var cloudStorage = {};
1474 |
1475 | function invokeStorageMethod(method, params, callback) {
1476 | if (!versionAtLeast('6.9')) {
1477 | console.error('[Telegram.WebApp] CloudStorage is not supported in version ' + webAppVersion);
1478 | throw Error('WebAppMethodUnsupported');
1479 | }
1480 | invokeCustomMethod(method, params, callback);
1481 | return cloudStorage;
1482 | }
1483 |
1484 | cloudStorage.setItem = function(key, value, callback) {
1485 | return invokeStorageMethod('saveStorageValue', {key: key, value: value}, callback);
1486 | };
1487 | cloudStorage.getItem = function(key, callback) {
1488 | return cloudStorage.getItems([key], callback ? function(err, res) {
1489 | if (err) callback(err);
1490 | else callback(null, res[key]);
1491 | } : null);
1492 | };
1493 | cloudStorage.getItems = function(keys, callback) {
1494 | return invokeStorageMethod('getStorageValues', {keys: keys}, callback);
1495 | };
1496 | cloudStorage.removeItem = function(key, callback) {
1497 | return cloudStorage.removeItems([key], callback);
1498 | };
1499 | cloudStorage.removeItems = function(keys, callback) {
1500 | return invokeStorageMethod('deleteStorageValues', {keys: keys}, callback);
1501 | };
1502 | cloudStorage.getKeys = function(callback) {
1503 | return invokeStorageMethod('getStorageKeys', {}, callback);
1504 | };
1505 | return cloudStorage;
1506 | })();
1507 |
1508 | var BiometricManager = (function() {
1509 | var isInited = false;
1510 | var isBiometricAvailable = false;
1511 | var biometricType = 'unknown';
1512 | var isAccessRequested = false;
1513 | var isAccessGranted = false;
1514 | var isBiometricTokenSaved = false;
1515 | var deviceId = '';
1516 |
1517 | var biometricManager = {};
1518 | Object.defineProperty(biometricManager, 'isInited', {
1519 | get: function(){ return isInited; },
1520 | enumerable: true
1521 | });
1522 | Object.defineProperty(biometricManager, 'isBiometricAvailable', {
1523 | get: function(){ return isInited && isBiometricAvailable; },
1524 | enumerable: true
1525 | });
1526 | Object.defineProperty(biometricManager, 'biometricType', {
1527 | get: function(){ return biometricType || 'unknown'; },
1528 | enumerable: true
1529 | });
1530 | Object.defineProperty(biometricManager, 'isAccessRequested', {
1531 | get: function(){ return isAccessRequested; },
1532 | enumerable: true
1533 | });
1534 | Object.defineProperty(biometricManager, 'isAccessGranted', {
1535 | get: function(){ return isAccessRequested && isAccessGranted; },
1536 | enumerable: true
1537 | });
1538 | Object.defineProperty(biometricManager, 'isBiometricTokenSaved', {
1539 | get: function(){ return isBiometricTokenSaved; },
1540 | enumerable: true
1541 | });
1542 | Object.defineProperty(biometricManager, 'deviceId', {
1543 | get: function(){ return deviceId || ''; },
1544 | enumerable: true
1545 | });
1546 |
1547 | var initRequestState = {callbacks: []};
1548 | var accessRequestState = false;
1549 | var authRequestState = false;
1550 | var tokenRequestState = false;
1551 |
1552 | WebView.onEvent('biometry_info_received', onBiometryInfoReceived);
1553 | WebView.onEvent('biometry_auth_requested', onBiometryAuthRequested);
1554 | WebView.onEvent('biometry_token_updated', onBiometryTokenUpdated);
1555 |
1556 | function onBiometryInfoReceived(eventType, eventData) {
1557 | isInited = true;
1558 | if (eventData.available) {
1559 | isBiometricAvailable = true;
1560 | biometricType = eventData.type || 'unknown';
1561 | if (eventData.access_requested) {
1562 | isAccessRequested = true;
1563 | isAccessGranted = !!eventData.access_granted;
1564 | isBiometricTokenSaved = !!eventData.token_saved;
1565 | } else {
1566 | isAccessRequested = false;
1567 | isAccessGranted = false;
1568 | isBiometricTokenSaved = false;
1569 | }
1570 | } else {
1571 | isBiometricAvailable = false;
1572 | biometricType = 'unknown';
1573 | isAccessRequested = false;
1574 | isAccessGranted = false;
1575 | isBiometricTokenSaved = false;
1576 | }
1577 | deviceId = eventData.device_id || '';
1578 |
1579 | if (initRequestState.callbacks.length > 0) {
1580 | for (var i = 0; i < initRequestState.callbacks.length; i++) {
1581 | var callback = initRequestState.callbacks[i];
1582 | callback();
1583 | }
1584 | initRequestState.callbacks = [];
1585 | }
1586 | if (accessRequestState) {
1587 | var state = accessRequestState;
1588 | accessRequestState = false;
1589 | if (state.callback) {
1590 | state.callback(isAccessGranted);
1591 | }
1592 | }
1593 | receiveWebViewEvent('biometricManagerUpdated');
1594 | }
1595 | function onBiometryAuthRequested(eventType, eventData) {
1596 | var isAuthenticated = (eventData.status == 'authorized'),
1597 | biometricToken = eventData.token || '';
1598 | if (authRequestState) {
1599 | var state = authRequestState;
1600 | authRequestState = false;
1601 | if (state.callback) {
1602 | state.callback(isAuthenticated, isAuthenticated ? biometricToken : null);
1603 | }
1604 | }
1605 | receiveWebViewEvent('biometricAuthRequested', isAuthenticated ? {
1606 | isAuthenticated: true,
1607 | biometricToken: biometricToken
1608 | } : {
1609 | isAuthenticated: false
1610 | });
1611 | }
1612 | function onBiometryTokenUpdated(eventType, eventData) {
1613 | var applied = false;
1614 | if (isBiometricAvailable &&
1615 | isAccessRequested) {
1616 | if (eventData.status == 'updated') {
1617 | isBiometricTokenSaved = true;
1618 | applied = true;
1619 | }
1620 | else if (eventData.status == 'removed') {
1621 | isBiometricTokenSaved = false;
1622 | applied = true;
1623 | }
1624 | }
1625 | if (tokenRequestState) {
1626 | var state = tokenRequestState;
1627 | tokenRequestState = false;
1628 | if (state.callback) {
1629 | state.callback(applied);
1630 | }
1631 | }
1632 | receiveWebViewEvent('biometricTokenUpdated', {
1633 | isUpdated: applied
1634 | });
1635 | }
1636 |
1637 | function checkVersion() {
1638 | if (!versionAtLeast('7.2')) {
1639 | console.warn('[Telegram.WebApp] BiometricManager is not supported in version ' + webAppVersion);
1640 | return false;
1641 | }
1642 | return true;
1643 | }
1644 |
1645 | function checkInit() {
1646 | if (!isInited) {
1647 | console.error('[Telegram.WebApp] BiometricManager should be inited before using.');
1648 | throw Error('WebAppBiometricManagerNotInited');
1649 | }
1650 | return true;
1651 | }
1652 |
1653 | biometricManager.init = function(callback) {
1654 | if (!checkVersion()) {
1655 | return biometricManager;
1656 | }
1657 | if (isInited) {
1658 | return biometricManager;
1659 | }
1660 | if (callback) {
1661 | initRequestState.callbacks.push(callback);
1662 | }
1663 | WebView.postEvent('web_app_biometry_get_info', false);
1664 | return biometricManager;
1665 | };
1666 | biometricManager.requestAccess = function(params, callback) {
1667 | if (!checkVersion()) {
1668 | return biometricManager;
1669 | }
1670 | checkInit();
1671 | if (!isBiometricAvailable) {
1672 | console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1673 | throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1674 | }
1675 | if (accessRequestState) {
1676 | console.error('[Telegram.WebApp] Access is already requested');
1677 | throw Error('WebAppBiometricManagerAccessRequested');
1678 | }
1679 | var popup_params = {};
1680 | if (typeof params.reason !== 'undefined') {
1681 | var reason = strTrim(params.reason);
1682 | if (reason.length > 128) {
1683 | console.error('[Telegram.WebApp] Biometric reason is too long', reason);
1684 | throw Error('WebAppBiometricRequestAccessParamInvalid');
1685 | }
1686 | if (reason.length > 0) {
1687 | popup_params.reason = reason;
1688 | }
1689 | }
1690 |
1691 | accessRequestState = {
1692 | callback: callback
1693 | };
1694 | WebView.postEvent('web_app_biometry_request_access', false, popup_params);
1695 | return biometricManager;
1696 | };
1697 | biometricManager.authenticate = function(params, callback) {
1698 | if (!checkVersion()) {
1699 | return biometricManager;
1700 | }
1701 | checkInit();
1702 | if (!isBiometricAvailable) {
1703 | console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1704 | throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1705 | }
1706 | if (!isAccessGranted) {
1707 | console.error('[Telegram.WebApp] Biometric access was not granted by the user.');
1708 | throw Error('WebAppBiometricManagerBiometricAccessNotGranted');
1709 | }
1710 | if (authRequestState) {
1711 | console.error('[Telegram.WebApp] Authentication request is already in progress.');
1712 | throw Error('WebAppBiometricManagerAuthenticationRequested');
1713 | }
1714 | var popup_params = {};
1715 | if (typeof params.reason !== 'undefined') {
1716 | var reason = strTrim(params.reason);
1717 | if (reason.length > 128) {
1718 | console.error('[Telegram.WebApp] Biometric reason is too long', reason);
1719 | throw Error('WebAppBiometricRequestAccessParamInvalid');
1720 | }
1721 | if (reason.length > 0) {
1722 | popup_params.reason = reason;
1723 | }
1724 | }
1725 |
1726 | authRequestState = {
1727 | callback: callback
1728 | };
1729 | WebView.postEvent('web_app_biometry_request_auth', false, popup_params);
1730 | return biometricManager;
1731 | };
1732 | biometricManager.updateBiometricToken = function(token, callback) {
1733 | if (!checkVersion()) {
1734 | return biometricManager;
1735 | }
1736 | token = token || '';
1737 | if (token.length > 1024) {
1738 | console.error('[Telegram.WebApp] Token is too long', token);
1739 | throw Error('WebAppBiometricManagerTokenInvalid');
1740 | }
1741 | checkInit();
1742 | if (!isBiometricAvailable) {
1743 | console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1744 | throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1745 | }
1746 | if (!isAccessGranted) {
1747 | console.error('[Telegram.WebApp] Biometric access was not granted by the user.');
1748 | throw Error('WebAppBiometricManagerBiometricAccessNotGranted');
1749 | }
1750 | if (tokenRequestState) {
1751 | console.error('[Telegram.WebApp] Token request is already in progress.');
1752 | throw Error('WebAppBiometricManagerTokenUpdateRequested');
1753 | }
1754 | tokenRequestState = {
1755 | callback: callback
1756 | };
1757 | WebView.postEvent('web_app_biometry_update_token', false, {token: token});
1758 | return biometricManager;
1759 | };
1760 | biometricManager.openSettings = function() {
1761 | if (!checkVersion()) {
1762 | return biometricManager;
1763 | }
1764 | checkInit();
1765 | if (!isBiometricAvailable) {
1766 | console.error('[Telegram.WebApp] Biometrics is not available on this device.');
1767 | throw Error('WebAppBiometricManagerBiometricsNotAvailable');
1768 | }
1769 | if (!isAccessRequested) {
1770 | console.error('[Telegram.WebApp] Biometric access was not requested yet.');
1771 | throw Error('WebAppBiometricManagerBiometricsAccessNotRequested');
1772 | }
1773 | if (isAccessGranted) {
1774 | console.warn('[Telegram.WebApp] Biometric access was granted by the user, no need to go to settings.');
1775 | return biometricManager;
1776 | }
1777 | WebView.postEvent('web_app_biometry_open_settings', false);
1778 | return biometricManager;
1779 | };
1780 | return biometricManager;
1781 | })();
1782 |
1783 | var LocationManager = (function() {
1784 | var isInited = false;
1785 | var isLocationAvailable = false;
1786 | var isAccessRequested = false;
1787 | var isAccessGranted = false;
1788 |
1789 | var locationManager = {};
1790 | Object.defineProperty(locationManager, 'isInited', {
1791 | get: function(){ return isInited; },
1792 | enumerable: true
1793 | });
1794 | Object.defineProperty(locationManager, 'isLocationAvailable', {
1795 | get: function(){ return isInited && isLocationAvailable; },
1796 | enumerable: true
1797 | });
1798 | Object.defineProperty(locationManager, 'isAccessRequested', {
1799 | get: function(){ return isAccessRequested; },
1800 | enumerable: true
1801 | });
1802 | Object.defineProperty(locationManager, 'isAccessGranted', {
1803 | get: function(){ return isAccessRequested && isAccessGranted; },
1804 | enumerable: true
1805 | });
1806 |
1807 | var initRequestState = {callbacks: []};
1808 | var getRequestState = {callbacks: []};
1809 |
1810 | WebView.onEvent('location_checked', onLocationChecked);
1811 | WebView.onEvent('location_requested', onLocationRequested);
1812 |
1813 | function onLocationChecked(eventType, eventData) {
1814 | isInited = true;
1815 | if (eventData.available) {
1816 | isLocationAvailable = true;
1817 | if (eventData.access_requested) {
1818 | isAccessRequested = true;
1819 | isAccessGranted = !!eventData.access_granted;
1820 | } else {
1821 | isAccessRequested = false;
1822 | isAccessGranted = false;
1823 | }
1824 | } else {
1825 | isLocationAvailable = false;
1826 | isAccessRequested = false;
1827 | isAccessGranted = false;
1828 | }
1829 |
1830 | if (initRequestState.callbacks.length > 0) {
1831 | for (var i = 0; i < initRequestState.callbacks.length; i++) {
1832 | var callback = initRequestState.callbacks[i];
1833 | callback();
1834 | }
1835 | initRequestState.callbacks = [];
1836 | }
1837 | receiveWebViewEvent('locationManagerUpdated');
1838 | }
1839 | function onLocationRequested(eventType, eventData) {
1840 | if (!eventData.available) {
1841 | locationData = null;
1842 | } else {
1843 | var locationData = {
1844 | latitude: eventData.latitude,
1845 | longitude: eventData.longitude,
1846 | altitude: null,
1847 | course: null,
1848 | speed: null,
1849 | horizontal_accuracy: null,
1850 | vertical_accuracy: null,
1851 | course_accuracy: null,
1852 | speed_accuracy: null,
1853 | };
1854 | if (typeof eventData.altitude !== 'undefined' && eventData.altitude !== null) {
1855 | locationData.altitude = eventData.altitude;
1856 | }
1857 | if (typeof eventData.course !== 'undefined' && eventData.course !== null) {
1858 | locationData.course = eventData.course % 360;
1859 | }
1860 | if (typeof eventData.speed !== 'undefined' && eventData.speed !== null) {
1861 | locationData.speed = eventData.speed;
1862 | }
1863 | if (typeof eventData.horizontal_accuracy !== 'undefined' && eventData.horizontal_accuracy !== null) {
1864 | locationData.horizontal_accuracy = eventData.horizontal_accuracy;
1865 | }
1866 | if (typeof eventData.vertical_accuracy !== 'undefined' && eventData.vertical_accuracy !== null) {
1867 | locationData.vertical_accuracy = eventData.vertical_accuracy;
1868 | }
1869 | if (typeof eventData.course_accuracy !== 'undefined' && eventData.course_accuracy !== null) {
1870 | locationData.course_accuracy = eventData.course_accuracy;
1871 | }
1872 | if (typeof eventData.speed_accuracy !== 'undefined' && eventData.speed_accuracy !== null) {
1873 | locationData.speed_accuracy = eventData.speed_accuracy;
1874 | }
1875 | }
1876 | if (!eventData.available ||
1877 | !isLocationAvailable ||
1878 | !isAccessRequested ||
1879 | !isAccessGranted) {
1880 | initRequestState.callbacks.push(function() {
1881 | locationResponse(locationData);
1882 | });
1883 | WebView.postEvent('web_app_check_location', false);
1884 | } else {
1885 | locationResponse(locationData);
1886 | }
1887 | }
1888 | function locationResponse(response) {
1889 | if (getRequestState.callbacks.length > 0) {
1890 | for (var i = 0; i < getRequestState.callbacks.length; i++) {
1891 | var callback = getRequestState.callbacks[i];
1892 | callback(response);
1893 | }
1894 | getRequestState.callbacks = [];
1895 | }
1896 | if (response !== null) {
1897 | receiveWebViewEvent('locationRequested', {
1898 | locationData: response
1899 | });
1900 | }
1901 | }
1902 |
1903 | function checkVersion() {
1904 | if (!versionAtLeast('8.0')) {
1905 | console.warn('[Telegram.WebApp] LocationManager is not supported in version ' + webAppVersion);
1906 | return false;
1907 | }
1908 | return true;
1909 | }
1910 |
1911 | function checkInit() {
1912 | if (!isInited) {
1913 | console.error('[Telegram.WebApp] LocationManager should be inited before using.');
1914 | throw Error('WebAppLocationManagerNotInited');
1915 | }
1916 | return true;
1917 | }
1918 |
1919 | locationManager.init = function(callback) {
1920 | if (!checkVersion()) {
1921 | return locationManager;
1922 | }
1923 | if (isInited) {
1924 | return locationManager;
1925 | }
1926 | if (callback) {
1927 | initRequestState.callbacks.push(callback);
1928 | }
1929 | WebView.postEvent('web_app_check_location', false);
1930 | return locationManager;
1931 | };
1932 | locationManager.getLocation = function(callback) {
1933 | if (!checkVersion()) {
1934 | return locationManager;
1935 | }
1936 | checkInit();
1937 | if (!isLocationAvailable) {
1938 | console.error('[Telegram.WebApp] Location is not available on this device.');
1939 | throw Error('WebAppLocationManagerLocationNotAvailable');
1940 | }
1941 |
1942 | getRequestState.callbacks.push(callback);
1943 | WebView.postEvent('web_app_request_location');
1944 | return locationManager;
1945 | };
1946 | locationManager.openSettings = function() {
1947 | if (!checkVersion()) {
1948 | return locationManager;
1949 | }
1950 | checkInit();
1951 | if (!isLocationAvailable) {
1952 | console.error('[Telegram.WebApp] Location is not available on this device.');
1953 | throw Error('WebAppLocationManagerLocationNotAvailable');
1954 | }
1955 | if (!isAccessRequested) {
1956 | console.error('[Telegram.WebApp] Location access was not requested yet.');
1957 | throw Error('WebAppLocationManagerLocationAccessNotRequested');
1958 | }
1959 | if (isAccessGranted) {
1960 | console.warn('[Telegram.WebApp] Location access was granted by the user, no need to go to settings.');
1961 | return locationManager;
1962 | }
1963 | WebView.postEvent('web_app_open_location_settings', false);
1964 | return locationManager;
1965 | };
1966 | return locationManager;
1967 | })();
1968 |
1969 | var Accelerometer = (function() {
1970 | var isStarted = false;
1971 | var valueX = null, valueY = null, valueZ = null;
1972 | var startCallbacks = [], stopCallbacks = [];
1973 |
1974 | var accelerometer = {};
1975 | Object.defineProperty(accelerometer, 'isStarted', {
1976 | get: function(){ return isStarted; },
1977 | enumerable: true
1978 | });
1979 | Object.defineProperty(accelerometer, 'x', {
1980 | get: function(){ return valueX; },
1981 | enumerable: true
1982 | });
1983 | Object.defineProperty(accelerometer, 'y', {
1984 | get: function(){ return valueY; },
1985 | enumerable: true
1986 | });
1987 | Object.defineProperty(accelerometer, 'z', {
1988 | get: function(){ return valueZ; },
1989 | enumerable: true
1990 | });
1991 |
1992 | WebView.onEvent('accelerometer_started', onAccelerometerStarted);
1993 | WebView.onEvent('accelerometer_stopped', onAccelerometerStopped);
1994 | WebView.onEvent('accelerometer_changed', onAccelerometerChanged);
1995 | WebView.onEvent('accelerometer_failed', onAccelerometerFailed);
1996 |
1997 | function onAccelerometerStarted(eventType, eventData) {
1998 | isStarted = true;
1999 | if (startCallbacks.length > 0) {
2000 | for (var i = 0; i < startCallbacks.length; i++) {
2001 | var callback = startCallbacks[i];
2002 | callback(true);
2003 | }
2004 | startCallbacks = [];
2005 | }
2006 | receiveWebViewEvent('accelerometerStarted');
2007 | }
2008 | function onAccelerometerStopped(eventType, eventData) {
2009 | isStarted = false;
2010 | if (stopCallbacks.length > 0) {
2011 | for (var i = 0; i < stopCallbacks.length; i++) {
2012 | var callback = stopCallbacks[i];
2013 | callback(true);
2014 | }
2015 | stopCallbacks = [];
2016 | }
2017 | receiveWebViewEvent('accelerometerStopped');
2018 | }
2019 | function onAccelerometerChanged(eventType, eventData) {
2020 | valueX = eventData.x;
2021 | valueY = eventData.y;
2022 | valueZ = eventData.z;
2023 | receiveWebViewEvent('accelerometerChanged');
2024 | }
2025 | function onAccelerometerFailed(eventType, eventData) {
2026 | if (startCallbacks.length > 0) {
2027 | for (var i = 0; i < startCallbacks.length; i++) {
2028 | var callback = startCallbacks[i];
2029 | callback(false);
2030 | }
2031 | startCallbacks = [];
2032 | }
2033 | receiveWebViewEvent('accelerometerFailed', {
2034 | error: eventData.error
2035 | });
2036 | }
2037 |
2038 | function checkVersion() {
2039 | if (!versionAtLeast('8.0')) {
2040 | console.warn('[Telegram.WebApp] Accelerometer is not supported in version ' + webAppVersion);
2041 | return false;
2042 | }
2043 | return true;
2044 | }
2045 |
2046 | accelerometer.start = function(params, callback) {
2047 | params = params || {};
2048 | if (!checkVersion()) {
2049 | return accelerometer;
2050 | }
2051 | var req_params = {};
2052 | var refresh_rate = parseInt(params.refresh_rate || 1000);
2053 | if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2054 | console.warn('[Telegram.WebApp] Accelerometer refresh_rate is invalid', refresh_rate);
2055 | } else {
2056 | req_params.refresh_rate = refresh_rate;
2057 | }
2058 |
2059 | if (callback) {
2060 | startCallbacks.push(callback);
2061 | }
2062 | WebView.postEvent('web_app_start_accelerometer', false, req_params);
2063 | return accelerometer;
2064 | };
2065 | accelerometer.stop = function(callback) {
2066 | if (!checkVersion()) {
2067 | return accelerometer;
2068 | }
2069 | if (callback) {
2070 | stopCallbacks.push(callback);
2071 | }
2072 | WebView.postEvent('web_app_stop_accelerometer');
2073 | return accelerometer;
2074 | };
2075 | return accelerometer;
2076 | })();
2077 |
2078 | var DeviceOrientation = (function() {
2079 | var isStarted = false;
2080 | var valueAlpha = null, valueBeta = null, valueGamma = null, valueAbsolute = false;
2081 | var startCallbacks = [], stopCallbacks = [];
2082 |
2083 | var deviceOrientation = {};
2084 | Object.defineProperty(deviceOrientation, 'isStarted', {
2085 | get: function(){ return isStarted; },
2086 | enumerable: true
2087 | });
2088 | Object.defineProperty(deviceOrientation, 'absolute', {
2089 | get: function(){ return valueAbsolute; },
2090 | enumerable: true
2091 | });
2092 | Object.defineProperty(deviceOrientation, 'alpha', {
2093 | get: function(){ return valueAlpha; },
2094 | enumerable: true
2095 | });
2096 | Object.defineProperty(deviceOrientation, 'beta', {
2097 | get: function(){ return valueBeta; },
2098 | enumerable: true
2099 | });
2100 | Object.defineProperty(deviceOrientation, 'gamma', {
2101 | get: function(){ return valueGamma; },
2102 | enumerable: true
2103 | });
2104 |
2105 | WebView.onEvent('device_orientation_started', onDeviceOrientationStarted);
2106 | WebView.onEvent('device_orientation_stopped', onDeviceOrientationStopped);
2107 | WebView.onEvent('device_orientation_changed', onDeviceOrientationChanged);
2108 | WebView.onEvent('device_orientation_failed', onDeviceOrientationFailed);
2109 |
2110 | function onDeviceOrientationStarted(eventType, eventData) {
2111 | isStarted = true;
2112 | if (startCallbacks.length > 0) {
2113 | for (var i = 0; i < startCallbacks.length; i++) {
2114 | var callback = startCallbacks[i];
2115 | callback(true);
2116 | }
2117 | startCallbacks = [];
2118 | }
2119 | receiveWebViewEvent('deviceOrientationStarted');
2120 | }
2121 | function onDeviceOrientationStopped(eventType, eventData) {
2122 | isStarted = false;
2123 | if (stopCallbacks.length > 0) {
2124 | for (var i = 0; i < stopCallbacks.length; i++) {
2125 | var callback = stopCallbacks[i];
2126 | callback(true);
2127 | }
2128 | stopCallbacks = [];
2129 | }
2130 | receiveWebViewEvent('deviceOrientationStopped');
2131 | }
2132 | function onDeviceOrientationChanged(eventType, eventData) {
2133 | valueAbsolute = !!eventData.absolute;
2134 | valueAlpha = eventData.alpha;
2135 | valueBeta = eventData.beta;
2136 | valueGamma = eventData.gamma;
2137 | receiveWebViewEvent('deviceOrientationChanged');
2138 | }
2139 | function onDeviceOrientationFailed(eventType, eventData) {
2140 | if (startCallbacks.length > 0) {
2141 | for (var i = 0; i < startCallbacks.length; i++) {
2142 | var callback = startCallbacks[i];
2143 | callback(false);
2144 | }
2145 | startCallbacks = [];
2146 | }
2147 | receiveWebViewEvent('deviceOrientationFailed', {
2148 | error: eventData.error
2149 | });
2150 | }
2151 |
2152 | function checkVersion() {
2153 | if (!versionAtLeast('8.0')) {
2154 | console.warn('[Telegram.WebApp] DeviceOrientation is not supported in version ' + webAppVersion);
2155 | return false;
2156 | }
2157 | return true;
2158 | }
2159 |
2160 | deviceOrientation.start = function(params, callback) {
2161 | params = params || {};
2162 | if (!checkVersion()) {
2163 | return deviceOrientation;
2164 | }
2165 | var req_params = {};
2166 | var refresh_rate = parseInt(params.refresh_rate || 1000);
2167 | if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2168 | console.warn('[Telegram.WebApp] DeviceOrientation refresh_rate is invalid', refresh_rate);
2169 | } else {
2170 | req_params.refresh_rate = refresh_rate;
2171 | }
2172 | req_params.need_absolute = !!params.need_absolute;
2173 |
2174 | if (callback) {
2175 | startCallbacks.push(callback);
2176 | }
2177 | WebView.postEvent('web_app_start_device_orientation', false, req_params);
2178 | return deviceOrientation;
2179 | };
2180 | deviceOrientation.stop = function(callback) {
2181 | if (!checkVersion()) {
2182 | return deviceOrientation;
2183 | }
2184 | if (callback) {
2185 | stopCallbacks.push(callback);
2186 | }
2187 | WebView.postEvent('web_app_stop_device_orientation');
2188 | return deviceOrientation;
2189 | };
2190 | return deviceOrientation;
2191 | })();
2192 |
2193 | var Gyroscope = (function() {
2194 | var isStarted = false;
2195 | var valueX = null, valueY = null, valueZ = null;
2196 | var startCallbacks = [], stopCallbacks = [];
2197 |
2198 | var gyroscope = {};
2199 | Object.defineProperty(gyroscope, 'isStarted', {
2200 | get: function(){ return isStarted; },
2201 | enumerable: true
2202 | });
2203 | Object.defineProperty(gyroscope, 'x', {
2204 | get: function(){ return valueX; },
2205 | enumerable: true
2206 | });
2207 | Object.defineProperty(gyroscope, 'y', {
2208 | get: function(){ return valueY; },
2209 | enumerable: true
2210 | });
2211 | Object.defineProperty(gyroscope, 'z', {
2212 | get: function(){ return valueZ; },
2213 | enumerable: true
2214 | });
2215 |
2216 | WebView.onEvent('gyroscope_started', onGyroscopeStarted);
2217 | WebView.onEvent('gyroscope_stopped', onGyroscopeStopped);
2218 | WebView.onEvent('gyroscope_changed', onGyroscopeChanged);
2219 | WebView.onEvent('gyroscope_failed', onGyroscopeFailed);
2220 |
2221 | function onGyroscopeStarted(eventType, eventData) {
2222 | isStarted = true;
2223 | if (startCallbacks.length > 0) {
2224 | for (var i = 0; i < startCallbacks.length; i++) {
2225 | var callback = startCallbacks[i];
2226 | callback(true);
2227 | }
2228 | startCallbacks = [];
2229 | }
2230 | receiveWebViewEvent('gyroscopeStarted');
2231 | }
2232 | function onGyroscopeStopped(eventType, eventData) {
2233 | isStarted = false;
2234 | if (stopCallbacks.length > 0) {
2235 | for (var i = 0; i < stopCallbacks.length; i++) {
2236 | var callback = stopCallbacks[i];
2237 | callback(true);
2238 | }
2239 | stopCallbacks = [];
2240 | }
2241 | receiveWebViewEvent('gyroscopeStopped');
2242 | }
2243 | function onGyroscopeChanged(eventType, eventData) {
2244 | valueX = eventData.x;
2245 | valueY = eventData.y;
2246 | valueZ = eventData.z;
2247 | receiveWebViewEvent('gyroscopeChanged');
2248 | }
2249 | function onGyroscopeFailed(eventType, eventData) {
2250 | if (startCallbacks.length > 0) {
2251 | for (var i = 0; i < startCallbacks.length; i++) {
2252 | var callback = startCallbacks[i];
2253 | callback(false);
2254 | }
2255 | startCallbacks = [];
2256 | }
2257 | receiveWebViewEvent('gyroscopeFailed', {
2258 | error: eventData.error
2259 | });
2260 | }
2261 |
2262 | function checkVersion() {
2263 | if (!versionAtLeast('8.0')) {
2264 | console.warn('[Telegram.WebApp] Gyroscope is not supported in version ' + webAppVersion);
2265 | return false;
2266 | }
2267 | return true;
2268 | }
2269 |
2270 | gyroscope.start = function(params, callback) {
2271 | params = params || {};
2272 | if (!checkVersion()) {
2273 | return gyroscope;
2274 | }
2275 | var req_params = {};
2276 | var refresh_rate = parseInt(params.refresh_rate || 1000);
2277 | if (isNaN(refresh_rate) || refresh_rate < 20 || refresh_rate > 1000) {
2278 | console.warn('[Telegram.WebApp] Gyroscope refresh_rate is invalid', refresh_rate);
2279 | } else {
2280 | req_params.refresh_rate = refresh_rate;
2281 | }
2282 |
2283 | if (callback) {
2284 | startCallbacks.push(callback);
2285 | }
2286 | WebView.postEvent('web_app_start_gyroscope', false, req_params);
2287 | return gyroscope;
2288 | };
2289 | gyroscope.stop = function(callback) {
2290 | if (!checkVersion()) {
2291 | return gyroscope;
2292 | }
2293 | if (callback) {
2294 | stopCallbacks.push(callback);
2295 | }
2296 | WebView.postEvent('web_app_stop_gyroscope');
2297 | return gyroscope;
2298 | };
2299 | return gyroscope;
2300 | })();
2301 |
2302 | var webAppInvoices = {};
2303 | function onInvoiceClosed(eventType, eventData) {
2304 | if (eventData.slug && webAppInvoices[eventData.slug]) {
2305 | var invoiceData = webAppInvoices[eventData.slug];
2306 | delete webAppInvoices[eventData.slug];
2307 | if (invoiceData.callback) {
2308 | invoiceData.callback(eventData.status);
2309 | }
2310 | receiveWebViewEvent('invoiceClosed', {
2311 | url: invoiceData.url,
2312 | status: eventData.status
2313 | });
2314 | }
2315 | }
2316 |
2317 | var webAppPopupOpened = false;
2318 | function onPopupClosed(eventType, eventData) {
2319 | if (webAppPopupOpened) {
2320 | var popupData = webAppPopupOpened;
2321 | webAppPopupOpened = false;
2322 | var button_id = null;
2323 | if (typeof eventData.button_id !== 'undefined') {
2324 | button_id = eventData.button_id;
2325 | }
2326 | if (popupData.callback) {
2327 | popupData.callback(button_id);
2328 | }
2329 | receiveWebViewEvent('popupClosed', {
2330 | button_id: button_id
2331 | });
2332 | }
2333 | }
2334 |
2335 | var webAppScanQrPopupOpened = false;
2336 | function onQrTextReceived(eventType, eventData) {
2337 | if (webAppScanQrPopupOpened) {
2338 | var popupData = webAppScanQrPopupOpened;
2339 | var data = null;
2340 | if (typeof eventData.data !== 'undefined') {
2341 | data = eventData.data;
2342 | }
2343 | if (popupData.callback) {
2344 | if (popupData.callback(data)) {
2345 | webAppScanQrPopupOpened = false;
2346 | WebView.postEvent('web_app_close_scan_qr_popup', false);
2347 | }
2348 | }
2349 | receiveWebViewEvent('qrTextReceived', {
2350 | data: data
2351 | });
2352 | }
2353 | }
2354 | function onScanQrPopupClosed(eventType, eventData) {
2355 | webAppScanQrPopupOpened = false;
2356 | receiveWebViewEvent('scanQrPopupClosed');
2357 | }
2358 |
2359 | function onClipboardTextReceived(eventType, eventData) {
2360 | if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
2361 | var requestData = webAppCallbacks[eventData.req_id];
2362 | delete webAppCallbacks[eventData.req_id];
2363 | var data = null;
2364 | if (typeof eventData.data !== 'undefined') {
2365 | data = eventData.data;
2366 | }
2367 | if (requestData.callback) {
2368 | requestData.callback(data);
2369 | }
2370 | receiveWebViewEvent('clipboardTextReceived', {
2371 | data: data
2372 | });
2373 | }
2374 | }
2375 |
2376 | var WebAppWriteAccessRequested = false;
2377 | function onWriteAccessRequested(eventType, eventData) {
2378 | if (WebAppWriteAccessRequested) {
2379 | var requestData = WebAppWriteAccessRequested;
2380 | WebAppWriteAccessRequested = false;
2381 | if (requestData.callback) {
2382 | requestData.callback(eventData.status == 'allowed');
2383 | }
2384 | receiveWebViewEvent('writeAccessRequested', {
2385 | status: eventData.status
2386 | });
2387 | }
2388 | }
2389 |
2390 | function getRequestedContact(callback, timeout) {
2391 | var reqTo, fallbackTo, reqDelay = 0;
2392 | var reqInvoke = function() {
2393 | invokeCustomMethod('getRequestedContact', {}, function(err, res) {
2394 | if (res && res.length) {
2395 | clearTimeout(fallbackTo);
2396 | callback(res);
2397 | } else {
2398 | reqDelay += 50;
2399 | reqTo = setTimeout(reqInvoke, reqDelay);
2400 | }
2401 | });
2402 | };
2403 | var fallbackInvoke = function() {
2404 | clearTimeout(reqTo);
2405 | callback('');
2406 | };
2407 | fallbackTo = setTimeout(fallbackInvoke, timeout);
2408 | reqInvoke();
2409 | }
2410 |
2411 | var WebAppContactRequested = false;
2412 | function onPhoneRequested(eventType, eventData) {
2413 | if (WebAppContactRequested) {
2414 | var requestData = WebAppContactRequested;
2415 | WebAppContactRequested = false;
2416 | var requestSent = eventData.status == 'sent';
2417 | var webViewEvent = {
2418 | status: eventData.status
2419 | };
2420 | if (requestSent) {
2421 | getRequestedContact(function(res) {
2422 | if (res && res.length) {
2423 | webViewEvent.response = res;
2424 | webViewEvent.responseUnsafe = Utils.urlParseQueryString(res);
2425 | for (var key in webViewEvent.responseUnsafe) {
2426 | var val = webViewEvent.responseUnsafe[key];
2427 | try {
2428 | if (val.substr(0, 1) == '{' && val.substr(-1) == '}' ||
2429 | val.substr(0, 1) == '[' && val.substr(-1) == ']') {
2430 | webViewEvent.responseUnsafe[key] = JSON.parse(val);
2431 | }
2432 | } catch (e) {}
2433 | }
2434 | }
2435 | if (requestData.callback) {
2436 | requestData.callback(requestSent, webViewEvent);
2437 | }
2438 | receiveWebViewEvent('contactRequested', webViewEvent);
2439 | }, 3000);
2440 | } else {
2441 | if (requestData.callback) {
2442 | requestData.callback(requestSent, webViewEvent);
2443 | }
2444 | receiveWebViewEvent('contactRequested', webViewEvent);
2445 | }
2446 | }
2447 | }
2448 |
2449 | var webAppDownloadFileRequested = false;
2450 | function onFileDownloadRequested(eventType, eventData) {
2451 | if (webAppDownloadFileRequested) {
2452 | var requestData = webAppDownloadFileRequested;
2453 | webAppDownloadFileRequested = false;
2454 | var isDownloading = eventData.status == 'downloading';
2455 | if (requestData.callback) {
2456 | requestData.callback(isDownloading);
2457 | }
2458 | receiveWebViewEvent('fileDownloadRequested', {
2459 | status: isDownloading ? 'downloading' : 'cancelled'
2460 | });
2461 | }
2462 | }
2463 |
2464 | function onCustomMethodInvoked(eventType, eventData) {
2465 | if (eventData.req_id && webAppCallbacks[eventData.req_id]) {
2466 | var requestData = webAppCallbacks[eventData.req_id];
2467 | delete webAppCallbacks[eventData.req_id];
2468 | var res = null, err = null;
2469 | if (typeof eventData.result !== 'undefined') {
2470 | res = eventData.result;
2471 | }
2472 | if (typeof eventData.error !== 'undefined') {
2473 | err = eventData.error;
2474 | }
2475 | if (requestData.callback) {
2476 | requestData.callback(err, res);
2477 | }
2478 | }
2479 | }
2480 |
2481 | function invokeCustomMethod(method, params, callback) {
2482 | if (!versionAtLeast('6.9')) {
2483 | console.error('[Telegram.WebApp] Method invokeCustomMethod is not supported in version ' + webAppVersion);
2484 | throw Error('WebAppMethodUnsupported');
2485 | }
2486 | var req_id = generateCallbackId(16);
2487 | var req_params = {req_id: req_id, method: method, params: params || {}};
2488 | webAppCallbacks[req_id] = {
2489 | callback: callback
2490 | };
2491 | WebView.postEvent('web_app_invoke_custom_method', false, req_params);
2492 | };
2493 |
2494 | if (!window.Telegram) {
2495 | window.Telegram = {};
2496 | }
2497 |
2498 | Object.defineProperty(WebApp, 'initData', {
2499 | get: function(){ return webAppInitData; },
2500 | enumerable: true
2501 | });
2502 | Object.defineProperty(WebApp, 'initDataUnsafe', {
2503 | get: function(){ return webAppInitDataUnsafe; },
2504 | enumerable: true
2505 | });
2506 | Object.defineProperty(WebApp, 'version', {
2507 | get: function(){ return webAppVersion; },
2508 | enumerable: true
2509 | });
2510 | Object.defineProperty(WebApp, 'platform', {
2511 | get: function(){ return webAppPlatform; },
2512 | enumerable: true
2513 | });
2514 | Object.defineProperty(WebApp, 'colorScheme', {
2515 | get: function(){ return colorScheme; },
2516 | enumerable: true
2517 | });
2518 | Object.defineProperty(WebApp, 'themeParams', {
2519 | get: function(){ return themeParams; },
2520 | enumerable: true
2521 | });
2522 | Object.defineProperty(WebApp, 'isExpanded', {
2523 | get: function(){ return isExpanded; },
2524 | enumerable: true
2525 | });
2526 | Object.defineProperty(WebApp, 'viewportHeight', {
2527 | get: function(){ return (viewportHeight === false ? window.innerHeight : viewportHeight) - bottomBarHeight; },
2528 | enumerable: true
2529 | });
2530 | Object.defineProperty(WebApp, 'viewportStableHeight', {
2531 | get: function(){ return (viewportStableHeight === false ? window.innerHeight : viewportStableHeight) - bottomBarHeight; },
2532 | enumerable: true
2533 | });
2534 | Object.defineProperty(WebApp, 'safeAreaInset', {
2535 | get: function(){ return safeAreaInset; },
2536 | enumerable: true
2537 | });
2538 | Object.defineProperty(WebApp, 'contentSafeAreaInset', {
2539 | get: function(){ return contentSafeAreaInset; },
2540 | enumerable: true
2541 | });
2542 | Object.defineProperty(WebApp, 'isClosingConfirmationEnabled', {
2543 | set: function(val){ setClosingConfirmation(val); },
2544 | get: function(){ return isClosingConfirmationEnabled; },
2545 | enumerable: true
2546 | });
2547 | Object.defineProperty(WebApp, 'isVerticalSwipesEnabled', {
2548 | set: function(val){ toggleVerticalSwipes(val); },
2549 | get: function(){ return isVerticalSwipesEnabled; },
2550 | enumerable: true
2551 | });
2552 | Object.defineProperty(WebApp, 'isFullscreen', {
2553 | get: function(){ return webAppIsFullscreen; },
2554 | enumerable: true
2555 | });
2556 | Object.defineProperty(WebApp, 'isOrientationLocked', {
2557 | set: function(val){ toggleOrientationLock(val); },
2558 | get: function(){ return webAppIsOrientationLocked; },
2559 | enumerable: true
2560 | });
2561 | Object.defineProperty(WebApp, 'isActive', {
2562 | get: function(){ return webAppIsActive; },
2563 | enumerable: true
2564 | });
2565 | Object.defineProperty(WebApp, 'headerColor', {
2566 | set: function(val){ setHeaderColor(val); },
2567 | get: function(){ return getHeaderColor(); },
2568 | enumerable: true
2569 | });
2570 | Object.defineProperty(WebApp, 'backgroundColor', {
2571 | set: function(val){ setBackgroundColor(val); },
2572 | get: function(){ return getBackgroundColor(); },
2573 | enumerable: true
2574 | });
2575 | Object.defineProperty(WebApp, 'bottomBarColor', {
2576 | set: function(val){ setBottomBarColor(val); },
2577 | get: function(){ return getBottomBarColor(); },
2578 | enumerable: true
2579 | });
2580 | Object.defineProperty(WebApp, 'BackButton', {
2581 | value: BackButton,
2582 | enumerable: true
2583 | });
2584 | Object.defineProperty(WebApp, 'MainButton', {
2585 | value: MainButton,
2586 | enumerable: true
2587 | });
2588 | Object.defineProperty(WebApp, 'SecondaryButton', {
2589 | value: SecondaryButton,
2590 | enumerable: true
2591 | });
2592 | Object.defineProperty(WebApp, 'SettingsButton', {
2593 | value: SettingsButton,
2594 | enumerable: true
2595 | });
2596 | Object.defineProperty(WebApp, 'HapticFeedback', {
2597 | value: HapticFeedback,
2598 | enumerable: true
2599 | });
2600 | Object.defineProperty(WebApp, 'CloudStorage', {
2601 | value: CloudStorage,
2602 | enumerable: true
2603 | });
2604 | Object.defineProperty(WebApp, 'BiometricManager', {
2605 | value: BiometricManager,
2606 | enumerable: true
2607 | });
2608 | Object.defineProperty(WebApp, 'Accelerometer', {
2609 | value: Accelerometer,
2610 | enumerable: true
2611 | });
2612 | Object.defineProperty(WebApp, 'DeviceOrientation', {
2613 | value: DeviceOrientation,
2614 | enumerable: true
2615 | });
2616 | Object.defineProperty(WebApp, 'Gyroscope', {
2617 | value: Gyroscope,
2618 | enumerable: true
2619 | });
2620 | Object.defineProperty(WebApp, 'LocationManager', {
2621 | value: LocationManager,
2622 | enumerable: true
2623 | });
2624 | WebApp.isVersionAtLeast = function(ver) {
2625 | return versionAtLeast(ver);
2626 | };
2627 | WebApp.setHeaderColor = function(color_key) {
2628 | WebApp.headerColor = color_key;
2629 | };
2630 | WebApp.setBackgroundColor = function(color) {
2631 | WebApp.backgroundColor = color;
2632 | };
2633 | WebApp.setBottomBarColor = function(color) {
2634 | WebApp.bottomBarColor = color;
2635 | };
2636 | WebApp.enableClosingConfirmation = function() {
2637 | WebApp.isClosingConfirmationEnabled = true;
2638 | };
2639 | WebApp.disableClosingConfirmation = function() {
2640 | WebApp.isClosingConfirmationEnabled = false;
2641 | };
2642 | WebApp.enableVerticalSwipes = function() {
2643 | WebApp.isVerticalSwipesEnabled = true;
2644 | };
2645 | WebApp.disableVerticalSwipes = function() {
2646 | WebApp.isVerticalSwipesEnabled = false;
2647 | };
2648 | WebApp.lockOrientation = function() {
2649 | WebApp.isOrientationLocked = true;
2650 | };
2651 | WebApp.unlockOrientation = function() {
2652 | WebApp.isOrientationLocked = false;
2653 | };
2654 | WebApp.requestFullscreen = function() {
2655 | if (!versionAtLeast('8.0')) {
2656 | console.error('[Telegram.WebApp] Method requestFullscreen is not supported in version ' + webAppVersion);
2657 | throw Error('WebAppMethodUnsupported');
2658 | }
2659 | WebView.postEvent('web_app_request_fullscreen');
2660 | };
2661 | WebApp.exitFullscreen = function() {
2662 | if (!versionAtLeast('8.0')) {
2663 | console.error('[Telegram.WebApp] Method exitFullscreen is not supported in version ' + webAppVersion);
2664 | throw Error('WebAppMethodUnsupported');
2665 | }
2666 | WebView.postEvent('web_app_exit_fullscreen');
2667 | };
2668 | WebApp.addToHomeScreen = function() {
2669 | if (!versionAtLeast('8.0')) {
2670 | console.error('[Telegram.WebApp] Method addToHomeScreen is not supported in version ' + webAppVersion);
2671 | throw Error('WebAppMethodUnsupported');
2672 | }
2673 | WebView.postEvent('web_app_add_to_home_screen');
2674 | };
2675 | WebApp.checkHomeScreenStatus = function(callback) {
2676 | if (!versionAtLeast('8.0')) {
2677 | console.error('[Telegram.WebApp] Method checkHomeScreenStatus is not supported in version ' + webAppVersion);
2678 | throw Error('WebAppMethodUnsupported');
2679 | }
2680 | if (callback) {
2681 | homeScreenCallbacks.push(callback);
2682 | }
2683 | WebView.postEvent('web_app_check_home_screen');
2684 | };
2685 | WebApp.onEvent = function(eventType, callback) {
2686 | onWebViewEvent(eventType, callback);
2687 | };
2688 | WebApp.offEvent = function(eventType, callback) {offWebViewEvent(eventType, callback);
2689 | };
2690 | WebApp.sendData = function (data) {
2691 | if (!data || !data.length) {
2692 | console.error('[Telegram.WebApp] Data is required', data);
2693 | throw Error('WebAppDataInvalid');
2694 | }
2695 | if (byteLength(data) > 4096) {
2696 | console.error('[Telegram.WebApp] Data is too long', data);
2697 | throw Error('WebAppDataInvalid');
2698 | }
2699 | WebView.postEvent('web_app_data_send', false, {data: data});
2700 | };
2701 | WebApp.switchInlineQuery = function (query, choose_chat_types) {
2702 | if (!versionAtLeast('6.6')) {
2703 | console.error('[Telegram.WebApp] Method switchInlineQuery is not supported in version ' + webAppVersion);
2704 | throw Error('WebAppMethodUnsupported');
2705 | }
2706 | if (!initParams.tgWebAppBotInline) {
2707 | console.error('[Telegram.WebApp] Inline mode is disabled for this bot. Read more about inline mode: https://core.telegram.org/bots/inline');
2708 | throw Error('WebAppInlineModeDisabled');
2709 | }
2710 | query = query || '';
2711 | if (query.length > 256) {
2712 | console.error('[Telegram.WebApp] Inline query is too long', query);
2713 | throw Error('WebAppInlineQueryInvalid');
2714 | }
2715 | var chat_types = [];
2716 | if (choose_chat_types) {
2717 | if (!Array.isArray(choose_chat_types)) {
2718 | console.error('[Telegram.WebApp] Choose chat types should be an array', choose_chat_types);
2719 | throw Error('WebAppInlineChooseChatTypesInvalid');
2720 | }
2721 | var good_types = {users: 1, bots: 1, groups: 1, channels: 1};
2722 | for (var i = 0; i < choose_chat_types.length; i++) {
2723 | var chat_type = choose_chat_types[i];
2724 | if (!good_types[chat_type]) {
2725 | console.error('[Telegram.WebApp] Choose chat type is invalid', chat_type);
2726 | throw Error('WebAppInlineChooseChatTypeInvalid');
2727 | }
2728 | if (good_types[chat_type] != 2) {
2729 | good_types[chat_type] = 2;
2730 | chat_types.push(chat_type);
2731 | }
2732 | }
2733 | }
2734 | WebView.postEvent('web_app_switch_inline_query', false, {query: query, chat_types: chat_types});
2735 | };
2736 | WebApp.openLink = function (url, options) {
2737 | var a = document.createElement('A');
2738 | a.href = url;
2739 | if (a.protocol != 'http:' &&
2740 | a.protocol != 'https:') {
2741 | console.error('[Telegram.WebApp] Url protocol is not supported', url);
2742 | throw Error('WebAppTgUrlInvalid');
2743 | }
2744 | var url = a.href;
2745 | options = options || {};
2746 | if (versionAtLeast('6.1')) {
2747 | var req_params = {url: url};
2748 | if (versionAtLeast('6.4') && options.try_instant_view) {
2749 | req_params.try_instant_view = true;
2750 | }
2751 | if (versionAtLeast('7.6') && options.try_browser) {
2752 | req_params.try_browser = options.try_browser;
2753 | }
2754 | WebView.postEvent('web_app_open_link', false, req_params);
2755 | } else {
2756 | window.open(url, '_blank');
2757 | }
2758 | };
2759 | WebApp.openTelegramLink = function (url, options) {
2760 | var a = document.createElement('A');
2761 | a.href = url;
2762 | if (a.protocol != 'http:' &&
2763 | a.protocol != 'https:') {
2764 | console.error('[Telegram.WebApp] Url protocol is not supported', url);
2765 | throw Error('WebAppTgUrlInvalid');
2766 | }
2767 | if (a.hostname != 't.me') {
2768 | console.error('[Telegram.WebApp] Url host is not supported', url);
2769 | throw Error('WebAppTgUrlInvalid');
2770 | }
2771 | var path_full = a.pathname + a.search;
2772 | options = options || {};
2773 | if (isIframe || versionAtLeast('6.1')) {
2774 | var req_params = {path_full: path_full};
2775 | if (options.force_request) {
2776 | req_params.force_request = true;
2777 | }
2778 | WebView.postEvent('web_app_open_tg_link', false, req_params);
2779 | } else {
2780 | location.href = 'https://t.me' + path_full;
2781 | }
2782 | };
2783 | WebApp.openInvoice = function (url, callback) {
2784 | var a = document.createElement('A'), match, slug;
2785 | a.href = url;
2786 | if (a.protocol != 'http:' &&
2787 | a.protocol != 'https:' ||
2788 | a.hostname != 't.me' ||
2789 | !(match = a.pathname.match(/^\/(\$|invoice\/)([A-Za-z0-9\-_=]+)$/)) ||
2790 | !(slug = match[2])) {
2791 | console.error('[Telegram.WebApp] Invoice url is invalid', url);
2792 | throw Error('WebAppInvoiceUrlInvalid');
2793 | }
2794 | if (!versionAtLeast('6.1')) {
2795 | console.error('[Telegram.WebApp] Method openInvoice is not supported in version ' + webAppVersion);
2796 | throw Error('WebAppMethodUnsupported');
2797 | }
2798 | if (webAppInvoices[slug]) {
2799 | console.error('[Telegram.WebApp] Invoice is already opened');
2800 | throw Error('WebAppInvoiceOpened');
2801 | }
2802 | webAppInvoices[slug] = {
2803 | url: url,
2804 | callback: callback
2805 | };
2806 | WebView.postEvent('web_app_open_invoice', false, {slug: slug});
2807 | };
2808 | WebApp.showPopup = function (params, callback) {
2809 | if (!versionAtLeast('6.2')) {
2810 | console.error('[Telegram.WebApp] Method showPopup is not supported in version ' + webAppVersion);
2811 | throw Error('WebAppMethodUnsupported');
2812 | }
2813 | if (webAppPopupOpened) {
2814 | console.error('[Telegram.WebApp] Popup is already opened');
2815 | throw Error('WebAppPopupOpened');
2816 | }
2817 | var title = '';
2818 | var message = '';
2819 | var buttons = [];
2820 | var popup_buttons = {};
2821 | var popup_params = {};
2822 | if (typeof params.title !== 'undefined') {
2823 | title = strTrim(params.title);
2824 | if (title.length > 64) {
2825 | console.error('[Telegram.WebApp] Popup title is too long', title);
2826 | throw Error('WebAppPopupParamInvalid');
2827 | }
2828 | if (title.length > 0) {
2829 | popup_params.title = title;
2830 | }
2831 | }
2832 | if (typeof params.message !== 'undefined') {
2833 | message = strTrim(params.message);
2834 | }
2835 | if (!message.length) {
2836 | console.error('[Telegram.WebApp] Popup message is required', params.message);
2837 | throw Error('WebAppPopupParamInvalid');
2838 | }
2839 | if (message.length > 256) {
2840 | console.error('[Telegram.WebApp] Popup message is too long', message);
2841 | throw Error('WebAppPopupParamInvalid');
2842 | }
2843 | popup_params.message = message;
2844 | if (typeof params.buttons !== 'undefined') {
2845 | if (!Array.isArray(params.buttons)) {
2846 | console.error('[Telegram.WebApp] Popup buttons should be an array', params.buttons);
2847 | throw Error('WebAppPopupParamInvalid');
2848 | }
2849 | for (var i = 0; i < params.buttons.length; i++) {
2850 | var button = params.buttons[i];
2851 | var btn = {};
2852 | var id = '';
2853 | if (typeof button.id !== 'undefined') {
2854 | id = button.id.toString();
2855 | if (id.length > 64) {
2856 | console.error('[Telegram.WebApp] Popup button id is too long', id);
2857 | throw Error('WebAppPopupParamInvalid');
2858 | }
2859 | }
2860 | btn.id = id;
2861 | var button_type = button.type;
2862 | if (typeof button_type === 'undefined') {
2863 | button_type = 'default';
2864 | }
2865 | btn.type = button_type;
2866 | if (button_type == 'ok' ||
2867 | button_type == 'close' ||
2868 | button_type == 'cancel') {
2869 | // no params needed
2870 | } else if (button_type == 'default' ||
2871 | button_type == 'destructive') {
2872 | var text = '';
2873 | if (typeof button.text !== 'undefined') {
2874 | text = strTrim(button.text);
2875 | }
2876 | if (!text.length) {
2877 | console.error('[Telegram.WebApp] Popup button text is required for type ' + button_type, button.text);
2878 | throw Error('WebAppPopupParamInvalid');
2879 | }
2880 | if (text.length > 64) {
2881 | console.error('[Telegram.WebApp] Popup button text is too long', text);
2882 | throw Error('WebAppPopupParamInvalid');
2883 | }
2884 | btn.text = text;
2885 | } else {
2886 | console.error('[Telegram.WebApp] Popup button type is invalid', button_type);
2887 | throw Error('WebAppPopupParamInvalid');
2888 | }
2889 | buttons.push(btn);
2890 | }
2891 | } else {
2892 | buttons.push({id: '', type: 'close'});
2893 | }
2894 | if (buttons.length < 1) {
2895 | console.error('[Telegram.WebApp] Popup should have at least one button');
2896 | throw Error('WebAppPopupParamInvalid');
2897 | }
2898 | if (buttons.length > 3) {
2899 | console.error('[Telegram.WebApp] Popup should not have more than 3 buttons');
2900 | throw Error('WebAppPopupParamInvalid');
2901 | }
2902 | popup_params.buttons = buttons;
2903 |
2904 | webAppPopupOpened = {
2905 | callback: callback
2906 | };
2907 | WebView.postEvent('web_app_open_popup', false, popup_params);
2908 | };
2909 | WebApp.showAlert = function (message, callback) {
2910 | WebApp.showPopup({
2911 | message: message
2912 | }, callback ? function(){ callback(); } : null);
2913 | };
2914 | WebApp.showConfirm = function (message, callback) {
2915 | WebApp.showPopup({
2916 | message: message,
2917 | buttons: [
2918 | {type: 'ok', id: 'ok'},
2919 | {type: 'cancel'}
2920 | ]
2921 | }, callback ? function (button_id) {
2922 | callback(button_id == 'ok');
2923 | } : null);
2924 | };
2925 | WebApp.showScanQrPopup = function (params, callback) {
2926 | if (!versionAtLeast('6.4')) {
2927 | console.error('[Telegram.WebApp] Method showScanQrPopup is not supported in version ' + webAppVersion);
2928 | throw Error('WebAppMethodUnsupported');
2929 | }
2930 | if (webAppScanQrPopupOpened) {
2931 | console.error('[Telegram.WebApp] Popup is already opened');
2932 | throw Error('WebAppScanQrPopupOpened');
2933 | }
2934 | var text = '';
2935 | var popup_params = {};
2936 | if (typeof params.text !== 'undefined') {
2937 | text = strTrim(params.text);
2938 | if (text.length > 64) {
2939 | console.error('[Telegram.WebApp] Scan QR popup text is too long', text);
2940 | throw Error('WebAppScanQrPopupParamInvalid');
2941 | }
2942 | if (text.length > 0) {
2943 | popup_params.text = text;
2944 | }
2945 | }
2946 |
2947 | webAppScanQrPopupOpened = {
2948 | callback: callback
2949 | };
2950 | WebView.postEvent('web_app_open_scan_qr_popup', false, popup_params);
2951 | };
2952 | WebApp.closeScanQrPopup = function () {
2953 | if (!versionAtLeast('6.4')) {
2954 | console.error('[Telegram.WebApp] Method closeScanQrPopup is not supported in version ' + webAppVersion);
2955 | throw Error('WebAppMethodUnsupported');
2956 | }
2957 |
2958 | webAppScanQrPopupOpened = false;
2959 | WebView.postEvent('web_app_close_scan_qr_popup', false);
2960 | };
2961 | WebApp.readTextFromClipboard = function (callback) {
2962 | if (!versionAtLeast('6.4')) {
2963 | console.error('[Telegram.WebApp] Method readTextFromClipboard is not supported in version ' + webAppVersion);
2964 | throw Error('WebAppMethodUnsupported');
2965 | }
2966 | var req_id = generateCallbackId(16);
2967 | var req_params = {req_id: req_id};
2968 | webAppCallbacks[req_id] = {
2969 | callback: callback
2970 | };
2971 | WebView.postEvent('web_app_read_text_from_clipboard', false, req_params);
2972 | };
2973 | WebApp.requestWriteAccess = function (callback) {
2974 | if (!versionAtLeast('6.9')) {
2975 | console.error('[Telegram.WebApp] Method requestWriteAccess is not supported in version ' + webAppVersion);
2976 | throw Error('WebAppMethodUnsupported');
2977 | }
2978 | if (WebAppWriteAccessRequested) {
2979 | console.error('[Telegram.WebApp] Write access is already requested');
2980 | throw Error('WebAppWriteAccessRequested');
2981 | }
2982 | WebAppWriteAccessRequested = {
2983 | callback: callback
2984 | };
2985 | WebView.postEvent('web_app_request_write_access');
2986 | };
2987 | WebApp.requestContact = function (callback) {
2988 | if (!versionAtLeast('6.9')) {
2989 | console.error('[Telegram.WebApp] Method requestContact is not supported in version ' + webAppVersion);
2990 | throw Error('WebAppMethodUnsupported');
2991 | }
2992 | if (WebAppContactRequested) {
2993 | console.error('[Telegram.WebApp] Contact is already requested');
2994 | throw Error('WebAppContactRequested');
2995 | }
2996 | WebAppContactRequested = {
2997 | callback: callback
2998 | };
2999 | WebView.postEvent('web_app_request_phone');
3000 | };
3001 | WebApp.downloadFile = function (params, callback) {
3002 | if (!versionAtLeast('8.0')) {
3003 | console.error('[Telegram.WebApp] Method downloadFile is not supported in version ' + webAppVersion);
3004 | throw Error('WebAppMethodUnsupported');
3005 | }
3006 | if (webAppDownloadFileRequested) {
3007 | console.error('[Telegram.WebApp] Popup is already opened');
3008 | throw Error('WebAppDownloadFilePopupOpened');
3009 | }
3010 | var a = document.createElement('A');
3011 |
3012 | var dl_params = {};
3013 | if (!params || !params.url || !params.url.length) {
3014 | console.error('[Telegram.WebApp] Url is required');
3015 | throw Error('WebAppDownloadFileParamInvalid');
3016 | }
3017 | a.href = params.url;
3018 | if (a.protocol != 'https:') {
3019 | console.error('[Telegram.WebApp] Url protocol is not supported', url);
3020 | throw Error('WebAppDownloadFileParamInvalid');
3021 | }
3022 | dl_params.url = a.href;
3023 |
3024 | if (!params || !params.file_name || !params.file_name.length) {
3025 | console.error('[Telegram.WebApp] File name is required');
3026 | throw Error('WebAppDownloadFileParamInvalid');
3027 | }
3028 | dl_params.file_name = params.file_name;
3029 |
3030 | webAppDownloadFileRequested = {
3031 | callback: callback
3032 | };
3033 | WebView.postEvent('web_app_request_file_download', false, dl_params);
3034 | };
3035 | WebApp.shareToStory = function (media_url, params) {
3036 | params = params || {};
3037 | if (!versionAtLeast('7.8')) {
3038 | console.error('[Telegram.WebApp] Method shareToStory is not supported in version ' + webAppVersion);
3039 | throw Error('WebAppMethodUnsupported');
3040 | }
3041 | var a = document.createElement('A');
3042 | a.href = media_url;
3043 | if (a.protocol != 'http:' &&
3044 | a.protocol != 'https:') {
3045 | console.error('[Telegram.WebApp] Media url protocol is not supported', url);
3046 | throw Error('WebAppMediaUrlInvalid');
3047 | }
3048 | var share_params = {};
3049 | share_params.media_url = a.href;
3050 | if (typeof params.text !== 'undefined') {
3051 | var text = strTrim(params.text);
3052 | if (text.length > 2048) {
3053 | console.error('[Telegram.WebApp] Text is too long', text);
3054 | throw Error('WebAppShareToStoryParamInvalid');
3055 | }
3056 | if (text.length > 0) {
3057 | share_params.text = text;
3058 | }
3059 | }
3060 | if (typeof params.widget_link !== 'undefined') {
3061 | params.widget_link = params.widget_link || {};
3062 | a.href = params.widget_link.url;
3063 | if (a.protocol != 'http:' &&
3064 | a.protocol != 'https:') {
3065 | console.error('[Telegram.WebApp] Link protocol is not supported', url);
3066 | throw Error('WebAppShareToStoryParamInvalid');
3067 | }
3068 | var widget_link = {
3069 | url: a.href
3070 | };
3071 | if (typeof params.widget_link.name !== 'undefined') {
3072 | var link_name = strTrim(params.widget_link.name);
3073 | if (link_name.length > 48) {
3074 | console.error('[Telegram.WebApp] Link name is too long', link_name);
3075 | throw Error('WebAppShareToStoryParamInvalid');
3076 | }
3077 | if (link_name.length > 0) {
3078 | widget_link.name = link_name;
3079 | }
3080 | }
3081 | share_params.widget_link = widget_link;
3082 | }
3083 |
3084 | WebView.postEvent('web_app_share_to_story', false, share_params);
3085 | };
3086 | WebApp.shareMessage = function (msg_id, callback) {
3087 | if (!versionAtLeast('8.0')) {
3088 | console.error('[Telegram.WebApp] Method shareMessage is not supported in version ' + webAppVersion);
3089 | throw Error('WebAppMethodUnsupported');
3090 | }
3091 | if (WebAppShareMessageOpened) {
3092 | console.error('[Telegram.WebApp] Share message is already opened');
3093 | throw Error('WebAppShareMessageOpened');
3094 | }
3095 | WebAppShareMessageOpened = {
3096 | callback: callback
3097 | };
3098 | WebView.postEvent('web_app_send_prepared_message', false, {id: msg_id});
3099 | };
3100 | WebApp.setEmojiStatus = function (custom_emoji_id, params, callback) {
3101 | params = params || {};
3102 | if (!versionAtLeast('8.0')) {
3103 | console.error('[Telegram.WebApp] Method setEmojiStatus is not supported in version ' + webAppVersion);
3104 | throw Error('WebAppMethodUnsupported');
3105 | }
3106 | var status_params = {};
3107 | status_params.custom_emoji_id = custom_emoji_id;
3108 | if (typeof params.duration !== 'undefined') {
3109 | status_params.duration = params.duration;
3110 | }
3111 | if (WebAppEmojiStatusRequested) {
3112 | console.error('[Telegram.WebApp] Emoji status is already requested');
3113 | throw Error('WebAppEmojiStatusRequested');
3114 | }
3115 | WebAppEmojiStatusRequested = {
3116 | callback: callback
3117 | };
3118 | WebView.postEvent('web_app_set_emoji_status', false, status_params);
3119 | };
3120 | WebApp.requestEmojiStatusAccess = function (callback) {
3121 | if (!versionAtLeast('8.0')) {
3122 | console.error('[Telegram.WebApp] Method requestEmojiStatusAccess is not supported in version ' + webAppVersion);
3123 | throw Error('WebAppMethodUnsupported');
3124 | }
3125 | if (WebAppEmojiStatusAccessRequested) {
3126 | console.error('[Telegram.WebApp] Emoji status permission is already requested');
3127 | throw Error('WebAppEmojiStatusAccessRequested');
3128 | }
3129 | WebAppEmojiStatusAccessRequested = {
3130 | callback: callback
3131 | };
3132 | WebView.postEvent('web_app_request_emoji_status_access');
3133 | };
3134 | WebApp.invokeCustomMethod = function (method, params, callback) {
3135 | invokeCustomMethod(method, params, callback);
3136 | };
3137 | WebApp.ready = function () {
3138 | WebView.postEvent('web_app_ready');
3139 | };
3140 | WebApp.expand = function () {
3141 | WebView.postEvent('web_app_expand');
3142 | };
3143 | WebApp.close = function (options) {
3144 | options = options || {};
3145 | var req_params = {};
3146 | if (versionAtLeast('7.6') && options.return_back) {
3147 | req_params.return_back = true;
3148 | }
3149 | WebView.postEvent('web_app_close', false, req_params);
3150 | };
3151 |
3152 | window.Telegram.WebApp = WebApp;
3153 |
3154 | updateHeaderColor();
3155 | updateBackgroundColor();
3156 | updateBottomBarColor();
3157 | setViewportHeight();
3158 | if (initParams.tgWebAppShowSettings) {
3159 | SettingsButton.show();
3160 | }
3161 |
3162 | window.addEventListener('resize', onWindowResize);
3163 | if (isIframe) {
3164 | document.addEventListener('click', linkHandler);
3165 | }
3166 |
3167 | WebView.onEvent('theme_changed', onThemeChanged);
3168 | WebView.onEvent('viewport_changed', onViewportChanged);
3169 | WebView.onEvent('safe_area_changed', onSafeAreaChanged);
3170 | WebView.onEvent('content_safe_area_changed', onContentSafeAreaChanged);
3171 | WebView.onEvent('visibility_changed', onVisibilityChanged);
3172 | WebView.onEvent('invoice_closed', onInvoiceClosed);
3173 | WebView.onEvent('popup_closed', onPopupClosed);
3174 | WebView.onEvent('qr_text_received', onQrTextReceived);
3175 | WebView.onEvent('scan_qr_popup_closed', onScanQrPopupClosed);
3176 | WebView.onEvent('clipboard_text_received', onClipboardTextReceived);
3177 | WebView.onEvent('write_access_requested', onWriteAccessRequested);
3178 | WebView.onEvent('phone_requested', onPhoneRequested);
3179 | WebView.onEvent('file_download_requested', onFileDownloadRequested);
3180 | WebView.onEvent('custom_method_invoked', onCustomMethodInvoked);
3181 | WebView.onEvent('fullscreen_changed', onFullscreenChanged);
3182 | WebView.onEvent('fullscreen_failed', onFullscreenFailed);
3183 | WebView.onEvent('home_screen_added', onHomeScreenAdded);
3184 | WebView.onEvent('home_screen_checked', onHomeScreenChecked);
3185 | WebView.onEvent('prepared_message_sent', onPreparedMessageSent);
3186 | WebView.onEvent('prepared_message_failed', onPreparedMessageFailed);
3187 | WebView.onEvent('emoji_status_set', onEmojiStatusSet);
3188 | WebView.onEvent('emoji_status_failed', onEmojiStatusFailed);
3189 | WebView.onEvent('emoji_status_access_requested', onEmojiStatusAccessRequested);
3190 | WebView.postEvent('web_app_request_theme');
3191 | WebView.postEvent('web_app_request_viewport');
3192 | WebView.postEvent('web_app_request_safe_area');
3193 | WebView.postEvent('web_app_request_content_safe_area');
3194 |
3195 | })();
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "sourceMap": true,
4 | "target": "es5",
5 | "lib": ["dom", "dom.iterable", "esnext"],
6 | "strict": true,
7 | "module": "CommonJS",
8 | "moduleResolution": "Node",
9 | "isolatedModules": true,
10 | "jsx": "react-jsx",
11 | "declaration": true,
12 | "allowJs": true
13 | },
14 | "include": ["src"]
15 | }
16 |
--------------------------------------------------------------------------------