├── .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 | [![npm version](https://img.shields.io/npm/v/@twa-dev/sdk)](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 | --------------------------------------------------------------------------------