diff --git a/README.md b/README.md index f3cbef4..e821143 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## `vue-tg` - Telegram integration for Vue [![docs](https://img.shields.io/badge/Documentation-gray?style=flat)](https://vue-tg.deptyped.com/) -[![version](https://img.shields.io/badge/Bot%20API-7.8-478be6?logo=telegram&style=flat)](https://core.telegram.org/bots/webapps#july-31-2024) +[![version](https://img.shields.io/badge/Bot%20API-8.0-478be6?logo=telegram&style=flat)](https://core.telegram.org/bots/webapps#november-17-2024) [![downloads](https://img.shields.io/npm/dm/vue-tg?label=Downloads&logo=npm&style=flat&color=478be6)](https://www.npmjs.com/package/vue-tg) [![size](https://img.shields.io/bundlephobia/minzip/vue-tg?label=Size&style=flat&color=478be6)](https://bundlephobia.com/result?p=vue-tg@latest) @@ -15,9 +15,9 @@ A lightweight package for seamless integration of [Telegram Mini Apps](https://c ``` @@ -78,46 +78,66 @@ To connect your Mini App to the Telegram client, place the script `telegram-web- | Field | Composable | | ---------------------------- | ------------------------------------------------------------------------------------------------------- | -| initData | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| initDataUnsafe | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| version | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| platform | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| colorScheme | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| themeParams | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| isExpanded | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| viewportHeight | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| viewportStableHeight | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| headerColor | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| backgroundColor | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| isClosingConfirmationEnabled | [useWebAppClosingConfirmation](https://vue-tg.deptyped.com/mini-apps.html#usewebappclosingconfirmation) | -| isVerticalSwipesEnabled | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| BackButton | [useWebAppBackButton](https://vue-tg.deptyped.com/mini-apps.html#usewebappbackbutton) | -| MainButton | [useWebAppMainButton](https://vue-tg.deptyped.com/mini-apps.html#usewebappmainbutton) | -| HapticFeedback | [useWebAppHapticFeedback](https://vue-tg.deptyped.com/mini-apps.html#usewebapphapticfeedback) | -| BiometricManager | [useWebAppBiometricManager](https://vue-tg.deptyped.com/mini-apps.html#usewebappbiometricmanager) | -| isVersionAtLeast | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| setHeaderColor | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| setBackgroundColor | [useWebAppTheme](https://vue-tg.deptyped.com/mini-apps.html#usewebapptheme) | -| enableClosingConfirmation | [useWebAppClosingConfirmation](https://vue-tg.deptyped.com/mini-apps.html#usewebappclosingconfirmation) | -| disableClosingConfirmation | [useWebAppClosingConfirmation](https://vue-tg.deptyped.com/mini-apps.html#usewebappclosingconfirmation) | -| enableVerticalSwipes | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| disableVerticalSwipes | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| onEvent | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| offEvent | [Handled automagically 🪄](https://vue-tg.deptyped.com/mini-apps.html#managing-event-subscriptions) | -| sendData | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| switchInlineQuery | [useWebAppNavigation](https://vue-tg.deptyped.com/mini-apps.html#usewebappnavigation) | -| openLink | [useWebAppNavigation](https://vue-tg.deptyped.com/mini-apps.html#usewebappnavigation) | -| openTelegramLink | [useWebAppNavigation](https://vue-tg.deptyped.com/mini-apps.html#usewebappnavigation) | -| openInvoice | [useWebAppNavigation](https://vue-tg.deptyped.com/mini-apps.html#usewebappnavigation) | -| shareToStory | [useWebAppShare](https://vue-tg.deptyped.com/mini-apps.html#usewebappshare) | -| showPopup | [useWebAppPopup](https://vue-tg.deptyped.com/mini-apps.html#usewebapppopup) | -| showAlert | [useWebAppPopup](https://vue-tg.deptyped.com/mini-apps.html#usewebapppopup) | -| showConfirm | [useWebAppPopup](https://vue-tg.deptyped.com/mini-apps.html#usewebapppopup) | -| showScanQrPopup | [useWebAppQrScanner](https://vue-tg.deptyped.com/mini-apps.html#usewebappqrscanner) | -| closeScanQrPopup | [useWebAppQrScanner](https://vue-tg.deptyped.com/mini-apps.html#usewebappqrscanner) | -| readTextFromClipboard | [useWebAppClipboard](https://vue-tg.deptyped.com/mini-apps.html#usewebappclipboard) | -| requestWriteAccess | [useWebAppRequests](https://vue-tg.deptyped.com/mini-apps.html#usewebapprequests) | -| requestContact | [useWebAppRequests](https://vue-tg.deptyped.com/mini-apps.html#usewebapprequests) | -| ready | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | -| expand | [useWebAppViewport](https://vue-tg.deptyped.com/mini-apps.html#usewebappviewport) | -| close | [useWebApp](https://vue-tg.deptyped.com/mini-apps.html#usewebapp) | +| initData | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| initDataUnsafe | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| version | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| platform | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| colorScheme | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| themeParams | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| isActive | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| isExpanded | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| viewportHeight | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| viewportStableHeight | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| headerColor | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| backgroundColor | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| isClosingConfirmationEnabled | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| isVerticalSwipesEnabled | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| isFullscreen | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| isOrientationLocked | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| safeAreaInset | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| contentSafeAreaInset | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| BackButton | [useBackButton](https://vue-tg.deptyped.com/mini-apps.html#usebackbutton) | +| MainButton | [useMainButton](https://vue-tg.deptyped.com/mini-apps.html#usemainbutton) | +| HapticFeedback | [useHapticFeedback](https://vue-tg.deptyped.com/mini-apps.html#usehapticfeedback) | +| BiometricManager | [useBiometricManager](https://vue-tg.deptyped.com/mini-apps.html#usebiometricmanager) | +| Accelerometer | [useAccelerometer](https://vue-tg.deptyped.com/mini-apps.html#useaccelerometer) | +| DeviceOrientation | [useDeviceOrientation](https://vue-tg.deptyped.com/mini-apps.html#usedeviceorientation) | +| Gyroscope | [useGyroscope](https://vue-tg.deptyped.com/mini-apps.html#usegyroscope) | +| LocationManager | [useLocationManager](https://vue-tg.deptyped.com/mini-apps.html#uselocationmanager) | +| isVersionAtLeast | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| setHeaderColor | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| setBackgroundColor | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| setBottomBarColor | [useTheme](https://vue-tg.deptyped.com/mini-apps.html#usetheme) | +| enableClosingConfirmation | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| disableClosingConfirmation | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| enableVerticalSwipes | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| disableVerticalSwipes | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| requestFullscreen | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| exitFullscreen | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| lockOrientation | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| unlockOrientation | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| addToHomeScreen | [useHomeScreen](https://vue-tg.deptyped.com/mini-apps.html#usehomescreen) | +| checkHomeScreenStatus | [useHomeScreen](https://vue-tg.deptyped.com/mini-apps.html#usehomescreen) | +| onEvent | [Event Handling](https://vue-tg.deptyped.com/mini-apps.html#event-handling) | +| offEvent | [Managing Event Subscriptions](https://vue-tg.deptyped.com/mini-apps.html#managing-event-subscriptions) | +| sendData | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| switchInlineQuery | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| openLink | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| openTelegramLink | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| openInvoice | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| shareToStory | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| shareMessage | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| setEmojiStatus | [useEmojiStatus](https://vue-tg.deptyped.com/mini-apps.html#useemojistatus) | +| requestEmojiStatusAccess | [useEmojiStatus](https://vue-tg.deptyped.com/mini-apps.html#useemojistatus) | +| downloadFile | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| showPopup | [usePopup](https://vue-tg.deptyped.com/mini-apps.html#usepopup) | +| showAlert | [usePopup](https://vue-tg.deptyped.com/mini-apps.html#usepopup) | +| showConfirm | [usePopup](https://vue-tg.deptyped.com/mini-apps.html#usepopup) | +| showScanQrPopup | [useQrScanner](https://vue-tg.deptyped.com/mini-apps.html#useqrscanner) | +| closeScanQrPopup | [useQrScanner](https://vue-tg.deptyped.com/mini-apps.html#useqrscanner) | +| readTextFromClipboard | [useClipboard](https://vue-tg.deptyped.com/mini-apps.html#useclipboard) | +| requestWriteAccess | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| requestContact | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| ready | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | +| expand | [useViewport](https://vue-tg.deptyped.com/mini-apps.html#useviewport) | +| close | [useMiniApp](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) | diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 4af68fa..9ea9258 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,10 +1,10 @@ -import { defineConfig } from 'vitepress' import { transformerTwoslash } from '@shikijs/vitepress-twoslash' +import { defineConfig } from 'vitepress' // https://vitepress.dev/reference/site-config export default defineConfig({ - title: "vue-tg", - description: "Vue-Telegram Documentation", + title: 'vue-tg', + description: 'Vue-Telegram Documentation', markdown: { codeTransformers: [ transformerTwoslash({ @@ -13,13 +13,22 @@ export default defineConfig({ noErrorTruncation: true, paths: { 'vue-tg': [ - './dist' - ] - } - } - } - }) - ] + './dist', + ], + 'vue-tg/7.8': [ + './dist/versions/7.8', + ], + 'vue-tg/8.0': [ + './dist/versions/8.0', + ], + 'vue-tg/latest': [ + './dist/versions/latest', + ], + }, + }, + }, + }), + ], }, themeConfig: { search: { @@ -27,33 +36,36 @@ export default defineConfig({ options: { detailedView: true, _render(src, env, md) { - if (env.relativePath.startsWith('mini-apps/components')) return '' - if (env.relativePath.startsWith('mini-apps/composables')) return '' - if (env.relativePath.startsWith('widgets/')) return '' + if (env.relativePath.startsWith('mini-apps/components')) + return '' + if (env.relativePath.startsWith('mini-apps/composables')) + return '' + if (env.relativePath.startsWith('widgets/')) + return '' return md.render(src, env) - } - } + }, + }, }, // https://vitepress.dev/reference/default-theme-config nav: [ { text: 'Installation', - link: "/installation", + link: '/installation', }, { text: 'Mini Apps', - link: "/mini-apps", + link: '/mini-apps', }, { text: 'Widgets', - link: "/widgets", - } + link: '/widgets', + }, ], socialLinks: [ - { icon: 'github', link: 'https://github.com/deptyped/vue-telegram' } - ] - } + { icon: 'github', link: 'https://github.com/deptyped/vue-telegram' }, + ], + }, }) diff --git a/docs/installation.md b/docs/installation.md index 88ee5f8..8f5ba41 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -64,6 +64,7 @@ import { Alert } from 'vue-tg' | [MainButton](/mini-apps#mainbutton) | `tg-main-button` | | [Popup](/mini-apps#Popup) | `tg-popup` | | [ScanQr](/mini-apps#scanqr) | `tg-scan-qr` | +| [SecondaryButton](/mini-apps#secondarybutton) | `tg-secondary-button` | | [SettingsButton](/mini-apps#settingsbutton) | `tg-settings-button` | | [ShareWidget](/widgets#share-widget) | `tg-share-widget` | | [PostWidget](/widgets#post-widget) | `tg-post-widget` | diff --git a/docs/mini-apps.md b/docs/mini-apps.md index c9d7ef4..1472f8c 100644 --- a/docs/mini-apps.md +++ b/docs/mini-apps.md @@ -11,94 +11,226 @@ outline: [2, 3] | Field | Composable | | ---------------------------- | ------------------------------------------------------------- | -| initData | [useWebApp](#usewebapp) | -| initDataUnsafe | [useWebApp](#usewebapp) | -| version | [useWebApp](#usewebapp) | -| platform | [useWebApp](#usewebapp) | -| colorScheme | [useWebAppTheme](#usewebapptheme) | -| themeParams | [useWebAppTheme](#usewebapptheme) | -| isExpanded | [useWebAppViewport](#usewebappviewport) | -| viewportHeight | [useWebAppViewport](#usewebappviewport) | -| viewportStableHeight | [useWebAppViewport](#usewebappviewport) | -| headerColor | [useWebAppTheme](#usewebapptheme) | -| backgroundColor | [useWebAppTheme](#usewebapptheme) | -| isClosingConfirmationEnabled | [useWebAppClosingConfirmation](#usewebappclosingconfirmation) | -| isVerticalSwipesEnabled | [useWebAppViewport](#usewebappviewport) | -| BackButton | [useWebAppBackButton](#usewebappbackbutton) | -| MainButton | [useWebAppMainButton](#usewebappmainbutton) | -| HapticFeedback | [useWebAppHapticFeedback](#usewebapphapticfeedback) | -| BiometricManager | [useWebAppBiometricManager](#usewebappbiometricmanager) | -| isVersionAtLeast | [useWebApp](#usewebapp) | -| setHeaderColor | [useWebAppTheme](#usewebapptheme) | -| setBackgroundColor | [useWebAppTheme](#usewebapptheme) | -| enableClosingConfirmation | [useWebAppClosingConfirmation](#usewebappclosingconfirmation) | -| disableClosingConfirmation | [useWebAppClosingConfirmation](#usewebappclosingconfirmation) | -| enableVerticalSwipes | [useWebAppViewport](#usewebappviewport) | -| disableVerticalSwipes | [useWebAppViewport](#usewebappviewport) | -| onEvent | [useWebApp](#usewebapp) | -| offEvent | [Handled automagically 🪄](#managing-event-subscriptions) | -| sendData | [useWebApp](#usewebapp) | -| switchInlineQuery | [useWebAppNavigation](#usewebappnavigation) | -| openLink | [useWebAppNavigation](#usewebappnavigation) | -| openTelegramLink | [useWebAppNavigation](#usewebappnavigation) | -| openInvoice | [useWebAppNavigation](#usewebappnavigation) | -| shareToStory | [useWebAppShare](#usewebappshare) | -| showPopup | [useWebAppPopup](#usewebapppopup) | -| showAlert | [useWebAppPopup](#usewebapppopup) | -| showConfirm | [useWebAppPopup](#usewebapppopup) | -| showScanQrPopup | [useWebAppQrScanner](#usewebappqrscanner) | -| closeScanQrPopup | [useWebAppQrScanner](#usewebappqrscanner) | -| readTextFromClipboard | [useWebAppClipboard](#usewebappclipboard) | -| requestWriteAccess | [useWebAppRequests](#usewebapprequests) | -| requestContact | [useWebAppRequests](#usewebapprequests) | -| ready | [useWebApp](#usewebapp) | -| expand | [useWebAppViewport](#usewebappviewport) | -| close | [useWebApp](#usewebapp) | - -### Event Handling - -The package provides a set of functions for event handling. By convention, the name of the functions consists of the prefix `on` + the name of the Telegram event in camelCase. So `themeChanged` event turns into `onThemeChanged` and so on. [onEvent](#usewebapp) is also available if you prefer it instead. +| initData | [useMiniApp](#useminiapp) | +| initDataUnsafe | [useMiniApp](#useminiapp) | +| version | [useMiniApp](#useminiapp) | +| platform | [useMiniApp](#useminiapp) | +| colorScheme | [useTheme](#usetheme) | +| themeParams | [useTheme](#usetheme) | +| isActive | [useMiniApp](#useminiapp) | +| isExpanded | [useViewport](#useviewport) | +| viewportHeight | [useViewport](#useviewport) | +| viewportStableHeight | [useViewport](#useviewport) | +| headerColor | [useTheme](#usetheme) | +| backgroundColor | [useTheme](#usetheme) | +| isClosingConfirmationEnabled | [useMiniApp](#useminiapp) | +| isVerticalSwipesEnabled | [useViewport](#useviewport) | +| isFullscreen | [useViewport](#useviewport) | +| isOrientationLocked | [useViewport](#useviewport) | +| safeAreaInset | [useViewport](#useviewport) | +| contentSafeAreaInset | [useViewport](#useviewport) | +| BackButton | [useBackButton](#usebackbutton) | +| MainButton | [useMainButton](#usemainbutton) | +| HapticFeedback | [useHapticFeedback](#usehapticfeedback) | +| BiometricManager | [useBiometricManager](#usebiometricmanager) | +| Accelerometer | [useAccelerometer](#useaccelerometer) | +| DeviceOrientation | [useDeviceOrientation](#usedeviceorientation) | +| Gyroscope | [useGyroscope](#usegyroscope) | +| LocationManager | [useLocationManager](#uselocationmanager) | +| isVersionAtLeast | [useMiniApp](#useminiapp) | +| setHeaderColor | [useTheme](#usetheme) | +| setBackgroundColor | [useTheme](#usetheme) | +| setBottomBarColor | [useTheme](#usetheme) | +| enableClosingConfirmation | [useMiniApp](#useminiapp) | +| disableClosingConfirmation | [useMiniApp](#useminiapp) | +| enableVerticalSwipes | [useViewport](#useviewport) | +| disableVerticalSwipes | [useViewport](#useviewport) | +| requestFullscreen | [useViewport](#useviewport) | +| exitFullscreen | [useViewport](#useviewport) | +| lockOrientation | [useViewport](#useviewport) | +| unlockOrientation | [useViewport](#useviewport) | +| addToHomeScreen | [useHomeScreen](#usehomescreen) | +| checkHomeScreenStatus | [useHomeScreen](#usehomescreen) | +| onEvent | [Event Handling](#event-handling) | +| offEvent | [Managing Event Subscriptions](#managing-event-subscriptions) | +| sendData | [useMiniApp](#useminiapp) | +| switchInlineQuery | [useMiniApp](#useminiapp) | +| openLink | [useMiniApp](#useminiapp) | +| openTelegramLink | [useMiniApp](#useminiapp) | +| openInvoice | [useMiniApp](#useminiapp) | +| shareToStory | [useMiniApp](#useminiapp) | +| shareMessage | [useMiniApp](#useminiapp) | +| setEmojiStatus | [useEmojiStatus](#useemojistatus) | +| requestEmojiStatusAccess | [useEmojiStatus](#useemojistatus) | +| downloadFile | [useMiniApp](#useminiapp) | +| showPopup | [usePopup](#usepopup) | +| showAlert | [usePopup](#usepopup) | +| showConfirm | [usePopup](#usepopup) | +| showScanQrPopup | [useQrScanner](#useqrscanner) | +| closeScanQrPopup | [useQrScanner](#useqrscanner) | +| readTextFromClipboard | [useClipboard](#useclipboard) | +| requestWriteAccess | [useMiniApp](#useminiapp) | +| requestContact | [useMiniApp](#useminiapp) | +| ready | [useMiniApp](#useminiapp) | +| expand | [useViewport](#useviewport) | +| close | [useMiniApp](#useminiapp) | + +## Version Check + +Features are introduced in specific versions of the Bot API, but users may not always use clients that support the latest version. +Always verify version compatibility to ensure feature support. + +For example, `shareToStory` was introduced in version __7.8__: + +```ts twoslash +import { useMiniApp } from 'vue-tg' + +const miniApp = useMiniApp() + +// error because this method was introduced in version 7.8 +// @errors: 2722 +miniApp.shareToStory("https://url-to-image") + +// first, ensure the version is 7.8 or higher +if (miniApp.isVersionAtLeast('7.8')) { + miniApp.shareToStory("https://url-to-image") // no error +} +``` -```ts -import { useWebAppTheme } from 'vue-tg' +You can explicitly set the base version: + +```ts twoslash +import { useMiniApp } from 'vue-tg/7.8' +// ^^^ + +const miniApp = useMiniApp() + +miniApp.shareToStory("https://url-to-image") // no error + +// error because this method was introduced in version 8.0 +// @errors: 2722 +miniApp.downloadFile({ url: "https://url-to-image", file_name: "kitten.png" }) +``` + +To skip all version checks, use `latest`, which is an alias for the latest version. +This is useful for prototyping but unreliable for production. +**Use it only if you know what you are doing.** + +```ts twoslash +import { useMiniApp } from 'vue-tg/latest' +// ^^^^^^ + +const miniApp = useMiniApp() + +miniApp.shareToStory("https://url-to-image") // no error +``` + +Specifying the version every time can be tedious. +For convenience, create a file `telegram.ts` with following content: -const { onThemeChanged } = useWebAppTheme() +```ts twoslash +import { isVersionAtLeast } from 'vue-tg' +import { usePopup, useMiniApp } from 'vue-tg/latest' + +const popup = usePopup() +const miniApp = useMiniApp() + +if (!isVersionAtLeast('8.0')) { + // ^^^ + popup.showAlert( + "Please update Telegram to the latest version!", + miniApp.close + ) +} + +export * from 'vue-tg/8.0' +// ^^^ +``` + +Now, you can import composables from `telegram.ts` and be sure that the client supports the specified version (`8.0` in this case). + +## Event Handling + +Event-handling functions follow the naming convention `on` in camelCase. +For example, the `themeChanged` event becomes `onThemeChanged`, and so on. +A generic `onEvent` is also available if you prefer to use it instead. + +```ts +import { onThemeChanged } from 'vue-tg' onThemeChanged(() => { // handle theme update }) ``` -#### Mapping +You can also use composables for event handling: -| Event name | Handler | -| ----------------------- | ----------------------------------------------------------------------------------- | -| themeChanged | [useWebAppTheme → onThemeChanged](#usewebapptheme) | -| viewportChanged | [useWebAppViewport → onViewportChanged](#usewebappviewport) | -| mainButtonClicked | [useWebAppMainButton → onMainButtonClicked](#usewebappmainbutton) | -| backButtonClicked | [useWebAppBackButton → onBackButtonClicked](#usewebappbackbutton) | -| settingsButtonClicked | [useWebAppSettingsButton → onSettingsButtonClicked](#usewebappsettingsbutton) | -| invoiceClosed | [useWebAppNavigation → onInvoiceClosed](#usewebappnavigation) | -| popupClosed | [useWebAppPopup → onPopupClosed](#usewebapppopup) | -| qrTextReceived | [useWebAppQrScanner → onQrTextReceived](#usewebappqrscanner) | -| scanQrPopupClosed | [useWebAppQrScanner → onScanQrPopupClosed](#usewebappqrscanner) | -| clipboardTextReceived | [useWebAppClipboard → onClipboardTextReceived](#usewebappclipboard) | -| writeAccessRequested | [useWebAppRequests → onWriteAccessRequested](#usewebapprequests) | -| contactRequested | [useWebAppRequests → onContactRequested](#usewebapprequests) | -| biometricManagerUpdated | [useWebAppBiometricManager → onBiometricManagerUpdated](#usewebappbiometricmanager) | -| biometricAuthRequested | [useWebAppBiometricManager → onBiometricAuthRequested](#usewebappbiometricmanager) | -| biometricTokenUpdated | [useWebAppBiometricManager → onBiometricTokenUpdated](#usewebappbiometricmanager) | +```ts +import { useTheme } from 'vue-tg' +const theme = useTheme() -#### Managing event subscriptions +theme.onChange(() => { + // handle theme update +}) +``` -By default, event handlers are automatically unsubscribed when the component is unmounted. -But you can unsubscribe before that if you need to: +::: details Event Mapping +| Event name | Handler | Composable Alias | +| -------------------------- | ---------------------------- | ------------------------------------------------------------------ | +| activated | onActivated | [useMiniApp →
onActive](#useminiapp) | +| deactivated | onDeactivated | [useMiniApp →
onDeactive](#useminiapp) | +| themeChanged | onThemeChanged | [useTheme →
onChange](#usetheme) | +| viewportChanged | onViewportChanged | [useViewport →
onChange](#useviewport) | +| safeAreaChanged | onSafeAreaChanged | [useViewport →
onSafeAreaChange](#useviewport) | +| contentSafeAreaChanged | onContentSafeAreaChanged | [useViewport →
onContentSafeAreaChange](#useviewport) | +| mainButtonClicked | onMainButtonClicked | [useMainButton →
onClick](#usemainbutton) | +| secondaryButtonClicked | onSecondaryButtonClicked | [useSecondaryButton →
onClick](#usesecondarybutton) | +| backButtonClicked | onBackButtonClicked | [useBackButton →
onClick](#usebackbutton) | +| settingsButtonClicked | onSettingsButtonClicked | [useSettingsButton →
onClick](#usesettingsbutton) | +| invoiceClosed | onInvoiceClosed | [useMiniApp →
onInvoiceClose](#useminiapp) | +| popupClosed | onPopupClosed | [usePopup →
onClose](#usepopup) | +| qrTextReceived | onQrTextReceived | [useQrScanner →
onScan](#useqrscanner) | +| scanQrPopupClosed | onScanQrPopupClosed | [useQrScanner →
onClose](#useqrscanner) | +| clipboardTextReceived | onClipboardTextReceived | [useClipboard →
onRead](#useclipboard) | +| writeAccessRequested | onWriteAccessRequested | [useMiniApp →
onWriteAccessRequest](#useminiapp) | +| contactRequested | onContactRequested | [useMiniApp →
onContactRequest](#useminiapp) | +| biometricManagerUpdated | onBiometricManagerUpdated | [useBiometricManager →
onManagerUpdate](#usebiometricmanager) | +| biometricAuthRequested | onBiometricAuthRequested | [useBiometricManager →
onAuthRequest](#usebiometricmanager) | +| biometricTokenUpdated | onBiometricTokenUpdated | [useBiometricManager →
onTokenUpdate](#usebiometricmanager) | +| fullscreenChanged | onFullscreenChanged | [useViewport →
onFullscreenChange](#useviewport) | +| fullscreenFailed | onFullscreenFailed | [useViewport →
onFullscreenFail](#useviewport) | +| homeScreenAdded | onHomeScreenAdded | [useHomeScreen →
onShortcutAdd](#usehomescreen) | +| homeScreenChecked | onHomeScreenChecked | [useHomeScreen →
onShortcutCheck](#usehomescreen) | +| accelerometerStarted | onAccelerometerStarted | [useAccelerometer →
onStart](#useaccelerometer) | +| accelerometerStopped | onAccelerometerStopped | [useAccelerometer →
onStop](#useaccelerometer) | +| accelerometerChanged | onAccelerometerChanged | [useAccelerometer →
onChange](#useaccelerometer) | +| accelerometerFailed | onAccelerometerFailed | [useAccelerometer →
onFail](#useaccelerometer) | +| deviceOrientationStarted | onDeviceOrientationStarted | [useDeviceOrientation →
onStart](#usedeviceorientation) | +| deviceOrientationStopped | onDeviceOrientationStopped | [useDeviceOrientation →
onStop](#usedeviceorientation) | +| deviceOrientationChanged | onDeviceOrientationChanged | [useDeviceOrientation →
onChange](#usedeviceorientation) | +| deviceOrientationFailed | onDeviceOrientationFailed | [useDeviceOrientation →
onFail](#usedeviceorientation) | +| gyroscopeStarted | onGyroscopeStarted | [useGyroscope →
onStart](#usegyroscope) | +| gyroscopeStopped | onGyroscopeStopped | [useGyroscope →
onStop](#usegyroscope) | +| gyroscopeChanged | onGyroscopeChanged | [useGyroscope →
onChange](#usegyroscope) | +| gyroscopeFailed | onGyroscopeFailed | [useGyroscope →
onFail](#usegyroscope) | +| locationManagerUpdated | onLocationManagerUpdated | [useLocationManager →
onManagerUpdate](#uselocationmanager) | +| locationRequested | onLocationRequested | [useLocationManager →
onRequest](#uselocationmanager) | +| shareMessageSent | onShareMessageSent | [useMiniApp →
onShareMessageSent](#useminiapp) | +| shareMessageFailed | onShareMessageFailed | [useMiniApp →
onShareMessageFail](#useminiapp) | +| emojiStatusSet | onEmojiStatusSet | [useEmojiStatus →
onSet](#useemojistatus) | +| emojiStatusAccessRequested | onEmojiStatusAccessRequested | [useEmojiStatus →
onAccessRequest](#useemojistatus) | +| emojiStatusFailed | onEmojiStatusFailed | [useEmojiStatus →
onFail](#useemojistatus) | +| fileDownloadRequested | onFileDownloadRequested | [useMiniApp →
onFileDownloadRequest](#useminiapp) | +::: + +#### Managing Event Subscriptions -```ts{9-10} -import { useWebAppTheme } from 'vue-tg' +Event handlers automatically unsubscribe when the component unmounts. +However, you can unsubscribe earlier if needed: -const { onThemeChanged } = useWebAppTheme() +```ts{7-8} +import { onThemeChanged } from 'vue-tg' const handler = onThemeChanged(() => { // handle theme update @@ -108,12 +240,10 @@ const handler = onThemeChanged(() => { handler.off() ``` -You can also disable automatic unsubscribing completely: +To disable automatic unsubscribing, set manual mode: -```ts{9,12-13} -import { useWebAppTheme } from 'vue-tg' - -const { onThemeChanged } = useWebAppTheme() +```ts +import { onThemeChanged } from 'vue-tg' const handler = onThemeChanged( () => { @@ -127,8 +257,8 @@ handler.off() ``` ::: warning -Please note that in `manual` mode, you are responsible for managing subscription. -If subscription is not managed properly, it can lead to memory leaks and other issues. +In `manual` mode, you are responsible for managing the subscription. +Improper management may lead to memory leaks or other issues. ::: ## Components @@ -151,38 +281,80 @@ If subscription is not managed properly, it can lead to memory leaks and other i + + ## Composables - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## Composables (Legacy) + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/mini-apps/components/main-button.md b/docs/mini-apps/components/main-button.md index 31e28c9..a0f6b53 100644 --- a/docs/mini-apps/components/main-button.md +++ b/docs/mini-apps/components/main-button.md @@ -18,14 +18,15 @@ function handleMainButton() { #### Props -| Name | Type | Required | Description | -| --------- | ------- | -------- | ------------------------------------------------------------ | -| visible | boolean | false | Shows whether the button is visible. Set to true by default. | -| disabled | boolean | false | Shows whether the button is disable. | -| progress | boolean | false | Shows whether the button is displaying a loading indicator. | -| text | string | false | Current button text. | -| color | string | false | Current button color. | -| textColor | string | false | Current button text color. | +| Name | Type | Required | Description | +| -------------- | ------- | -------- | ------------------------------------------------------------ | +| visible | boolean | false | Shows whether the button is visible. Set to true by default. | +| disabled | boolean | false | Shows whether the button is disable. | +| progress | boolean | false | Shows whether the button is displaying a loading indicator. | +| text | string | false | | +| color | string | false | | +| textColor | string | false | | +| hasShineEffect | boolean | false | | #### Events diff --git a/docs/mini-apps/components/secondary-button.md b/docs/mini-apps/components/secondary-button.md new file mode 100644 index 0000000..be13313 --- /dev/null +++ b/docs/mini-apps/components/secondary-button.md @@ -0,0 +1,36 @@ +### SecondaryButton + +A component that enables the secondary button when is rendered. + +```vue + + + +``` + +#### Props + +| Name | Type | Required | Description | +| -------------- | ------- | -------- | ------------------------------------------------------------ | +| visible | boolean | false | Shows whether the button is visible. Set to true by default. | +| disabled | boolean | false | Shows whether the button is disable. | +| progress | boolean | false | Shows whether the button is displaying a loading indicator. | +| text | string | false | | +| color | string | false | | +| textColor | string | false | | +| hasShineEffect | boolean | false | | +| position | string | false | | + +#### Events + +| Name | Type | Description | +| ----- | ------------ | -------------------------------------- | +| click | `() => void` | Emits when the main button is pressed. | diff --git a/docs/mini-apps/composables-legacy/use-web-app-back-button.md b/docs/mini-apps/composables-legacy/use-web-app-back-button.md new file mode 100644 index 0000000..f3f3d2b --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-back-button.md @@ -0,0 +1,16 @@ +### ~~useWebAppBackButton~~ + +::: danger Deprecated +Use [useBackButton](#usebackbutton) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppBackButton } from 'vue-tg' +``` + +| Name | Description | +| :-------------------- | :-------------------------------------------------------------------------------------------------- | +| `isBackButtonVisible` |
| +| `showBackButton` | | +| `hideBackButton` | | diff --git a/docs/mini-apps/composables/use-web-app-biometric-manager.md b/docs/mini-apps/composables-legacy/use-web-app-biometric-manager.md similarity index 89% rename from docs/mini-apps/composables/use-web-app-biometric-manager.md rename to docs/mini-apps/composables-legacy/use-web-app-biometric-manager.md index dbc9708..3551628 100644 --- a/docs/mini-apps/composables/use-web-app-biometric-manager.md +++ b/docs/mini-apps/composables-legacy/use-web-app-biometric-manager.md @@ -1,4 +1,8 @@ -### useWebAppBiometricManager +### ~~useWebAppBiometricManager~~ + +::: danger Deprecated +Use [useBiometricManager](#usebiometricmanager) instead. +::: ```ts twoslash // Hover to inspect type @@ -19,6 +23,6 @@ import { useWebAppBiometricManager } from 'vue-tg' | `authenticateBiometric` | | | `updateBiometricToken` | | | `openBiometricSettings` | | -| `onBiometricManagerUpdated` | A method that sets the `biometricManagerUpdated` [event handler](#event-handling). | -| `onBiometricAuthRequested` | A method that sets the `biometricAuthRequested` [event handler](#event-handling). | -| `onBiometricTokenUpdated` | A method that sets the `biometricTokenUpdated` [event handler](#event-handling). | +| `onManagerUpdated` | A method that sets the `biometricManagerUpdated` [event handler](#event-handling). | +| `onAuthRequested` | A method that sets the `biometricAuthRequested` [event handler](#event-handling). | +| `onTokenUpdated` | A method that sets the `biometricTokenUpdated` [event handler](#event-handling). | diff --git a/docs/mini-apps/composables-legacy/use-web-app-clipboard.md b/docs/mini-apps/composables-legacy/use-web-app-clipboard.md new file mode 100644 index 0000000..506c0ef --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-clipboard.md @@ -0,0 +1,14 @@ +### ~~useWebAppClipboard~~ + +::: danger Deprecated +Use [useClipboard](#useclipboard) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppClipboard } from 'vue-tg' +``` + +| Name | Type | +| :---------------------- | :------------------------------------------------------------ | +| `readTextFromClipboard` | | diff --git a/docs/mini-apps/composables/use-web-app-closing-confirmation.md b/docs/mini-apps/composables-legacy/use-web-app-closing-confirmation.md similarity index 89% rename from docs/mini-apps/composables/use-web-app-closing-confirmation.md rename to docs/mini-apps/composables-legacy/use-web-app-closing-confirmation.md index c95a28f..87a4054 100644 --- a/docs/mini-apps/composables/use-web-app-closing-confirmation.md +++ b/docs/mini-apps/composables-legacy/use-web-app-closing-confirmation.md @@ -1,4 +1,8 @@ -### useWebAppClosingConfirmation +### ~~useWebAppClosingConfirmation~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-cloud-storage.md b/docs/mini-apps/composables-legacy/use-web-app-cloud-storage.md similarity index 87% rename from docs/mini-apps/composables/use-web-app-cloud-storage.md rename to docs/mini-apps/composables-legacy/use-web-app-cloud-storage.md index 99df7d8..df3c122 100644 --- a/docs/mini-apps/composables/use-web-app-cloud-storage.md +++ b/docs/mini-apps/composables-legacy/use-web-app-cloud-storage.md @@ -1,4 +1,8 @@ -### useWebAppCloudStorage +### ~~useWebAppCloudStorage~~ + +::: danger Deprecated +Use [useCloudStorage](#usecloudstorage) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-haptic-feedback.md b/docs/mini-apps/composables-legacy/use-web-app-haptic-feedback.md similarity index 83% rename from docs/mini-apps/composables/use-web-app-haptic-feedback.md rename to docs/mini-apps/composables-legacy/use-web-app-haptic-feedback.md index 217e049..e2c861b 100644 --- a/docs/mini-apps/composables/use-web-app-haptic-feedback.md +++ b/docs/mini-apps/composables-legacy/use-web-app-haptic-feedback.md @@ -1,4 +1,8 @@ -### useWebAppHapticFeedback +### ~~useWebAppHapticFeedback~~ + +::: danger Deprecated +Use [useHapticFeedback](#usehapticfeedback) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-main-button.md b/docs/mini-apps/composables-legacy/use-web-app-main-button.md similarity index 93% rename from docs/mini-apps/composables/use-web-app-main-button.md rename to docs/mini-apps/composables-legacy/use-web-app-main-button.md index 3749c52..3a065d3 100644 --- a/docs/mini-apps/composables/use-web-app-main-button.md +++ b/docs/mini-apps/composables-legacy/use-web-app-main-button.md @@ -1,4 +1,8 @@ -### useWebAppMainButton +### ~~useWebAppMainButton~~ + +::: danger Deprecated +Use [useMainButton](#usemainbutton) instead. +::: ```ts twoslash // Hover to inspect type @@ -14,7 +18,6 @@ import { useWebAppMainButton } from 'vue-tg' | `isMainButtonActive` |
| | `isMainButtonProgressVisible` |
| | `setMainButtonText` | | -| `onMainButtonClicked` | A method that sets the `mainButtonClicked` [event handler](#event-handling). | | `showMainButton` | | | `hideMainButton` | | | `enableMainButton` | | diff --git a/docs/mini-apps/composables-legacy/use-web-app-navigation.md b/docs/mini-apps/composables-legacy/use-web-app-navigation.md new file mode 100644 index 0000000..8b66b3e --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-navigation.md @@ -0,0 +1,17 @@ +### ~~useWebAppNavigation~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppNavigation } from 'vue-tg' +``` + +| Name | Type | +| :------------------ | :-------------------------------------------------------- | +| `openInvoice` | | +| `openLink` | | +| `openTelegramLink` | | +| `switchInlineQuery` | | diff --git a/docs/mini-apps/composables-legacy/use-web-app-popup.md b/docs/mini-apps/composables-legacy/use-web-app-popup.md new file mode 100644 index 0000000..bf05d35 --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-popup.md @@ -0,0 +1,16 @@ +### ~~useWebAppPopup~~ + +::: danger Deprecated +Use [usePopup](#usepopup) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppPopup } from 'vue-tg' +``` + +| Name | Type | +| :------------ | :-------------------------------------------------- | +| `showAlert` | | +| `showConfirm` | | +| `showPopup` | | diff --git a/docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md b/docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md new file mode 100644 index 0000000..13b2861 --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md @@ -0,0 +1,15 @@ +### ~~useWebAppQrScanner~~ + +::: danger Deprecated +Use [useQrScanner](#useqrscanner) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppQrScanner } from 'vue-tg' +``` + +| Name | Type | +| :----------------- | :------------------------------------------------------- | +| `showScanQrPopup` | | +| `closeScanQrPopup` | | diff --git a/docs/mini-apps/composables-legacy/use-web-app-requests.md b/docs/mini-apps/composables-legacy/use-web-app-requests.md new file mode 100644 index 0000000..da81847 --- /dev/null +++ b/docs/mini-apps/composables-legacy/use-web-app-requests.md @@ -0,0 +1,15 @@ +### ~~useWebAppRequests~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: + +```ts twoslash +// Hover to inspect type +import { useWebAppRequests } from 'vue-tg' +``` + +| Name | Type | +| :------------------- | :--------------------------------------------------------- | +| `requestContact` | | +| `requestWriteAccess` | | diff --git a/docs/mini-apps/composables/use-web-app-settings-button.md b/docs/mini-apps/composables-legacy/use-web-app-settings-button.md similarity index 69% rename from docs/mini-apps/composables/use-web-app-settings-button.md rename to docs/mini-apps/composables-legacy/use-web-app-settings-button.md index 9233207..e782d9e 100644 --- a/docs/mini-apps/composables/use-web-app-settings-button.md +++ b/docs/mini-apps/composables-legacy/use-web-app-settings-button.md @@ -1,13 +1,16 @@ -### useWebAppSettingsButton +### ~~useWebAppSettingsButton~~ + +::: danger Deprecated +Use [useSettingsButton](#usesettingsbutton) instead. +::: ```ts twoslash // Hover to inspect type import { useWebAppSettingsButton } from 'vue-tg' ``` -| Name | Type | -| :------------------------ | :------------------------------------------------------------------------------------------------------------------------ | -| `isSettingsButtonVisible` |
| -| `onSettingsButtonClicked` | A method that sets the `settingsButtonClicked` [event handler](#event-handling). | -| `showSettingsButton` | | -| `hideSettingsButton` | | +| Name | Type | +| :------------------------ | :----------------------------------------------------------------------------------------------------- | +| `isSettingsButtonVisible` |
| +| `showSettingsButton` | | +| `hideSettingsButton` | | diff --git a/docs/mini-apps/composables/use-web-app-share.md b/docs/mini-apps/composables-legacy/use-web-app-share.md similarity index 75% rename from docs/mini-apps/composables/use-web-app-share.md rename to docs/mini-apps/composables-legacy/use-web-app-share.md index 358a96a..e9c52e2 100644 --- a/docs/mini-apps/composables/use-web-app-share.md +++ b/docs/mini-apps/composables-legacy/use-web-app-share.md @@ -1,4 +1,8 @@ -### useWebAppShare +### ~~useWebAppShare~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: ```ts twoslash // Hover to inspect type @@ -7,4 +11,4 @@ import { useWebAppShare } from 'vue-tg' | Name | Type | | :------------- | :--------------------------------------------------- | -| `shareToStory` | | \ No newline at end of file +| `shareToStory` | | diff --git a/docs/mini-apps/composables/use-web-app-theme.md b/docs/mini-apps/composables-legacy/use-web-app-theme.md similarity index 88% rename from docs/mini-apps/composables/use-web-app-theme.md rename to docs/mini-apps/composables-legacy/use-web-app-theme.md index 432288b..8c9c02d 100644 --- a/docs/mini-apps/composables/use-web-app-theme.md +++ b/docs/mini-apps/composables-legacy/use-web-app-theme.md @@ -1,4 +1,8 @@ -### useWebAppTheme +### ~~useWebAppTheme~~ + +::: danger Deprecated +Use [useTheme](#usetheme) instead. +::: ```ts twoslash // Hover to inspect type @@ -13,4 +17,3 @@ import { useWebAppTheme } from 'vue-tg' | `backgroundColor` |
| | `setHeaderColor` | | | `setBackgroundColor` | | -| `onThemeChanged` | A method that sets the `themeParams` [event handler](#event-handling). | diff --git a/docs/mini-apps/composables/use-web-app-viewport.md b/docs/mini-apps/composables-legacy/use-web-app-viewport.md similarity index 89% rename from docs/mini-apps/composables/use-web-app-viewport.md rename to docs/mini-apps/composables-legacy/use-web-app-viewport.md index d82a63d..601651b 100644 --- a/docs/mini-apps/composables/use-web-app-viewport.md +++ b/docs/mini-apps/composables-legacy/use-web-app-viewport.md @@ -1,4 +1,8 @@ -### useWebAppViewport +### ~~useWebAppViewport~~ + +::: danger Deprecated +Use [useViewport](#useviewport) instead. +::: ```ts twoslash // Hover to inspect type @@ -14,4 +18,3 @@ import { useWebAppViewport } from 'vue-tg' | `expand` | | | `enableVerticalSwipes` | | | `disableVerticalSwipes` | | -| `onViewportChanged` | A method that sets the `viewportChanged` [event handler](#event-handling). | diff --git a/docs/mini-apps/composables/use-web-app.md b/docs/mini-apps/composables-legacy/use-web-app.md similarity index 93% rename from docs/mini-apps/composables/use-web-app.md rename to docs/mini-apps/composables-legacy/use-web-app.md index fac90a1..317b2ee 100644 --- a/docs/mini-apps/composables/use-web-app.md +++ b/docs/mini-apps/composables-legacy/use-web-app.md @@ -1,4 +1,8 @@ -### useWebApp +### ~~useWebApp~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: ```ts twoslash // Hover to inspect type @@ -12,7 +16,6 @@ import { useWebApp } from 'vue-tg' | `version` | | | `platform` | | | `isVersionAtLeast` | | -| `onEvent` | | | `sendData` | | | `ready` | | | `close` | | diff --git a/docs/mini-apps/composables/use-accelerometer.md b/docs/mini-apps/composables/use-accelerometer.md new file mode 100644 index 0000000..cdd634a --- /dev/null +++ b/docs/mini-apps/composables/use-accelerometer.md @@ -0,0 +1,22 @@ +### useAccelerometer + +```ts +import { useAccelerometer } from 'vue-tg' + +const accelerometer = useAccelerometer() +``` + +| Name | Description | +| :----------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| `isStarted` |
| +| `x` |
| +| `y` |
| +| `z` |
| +| `start` |
| +| `onStart` | A method that sets event handler. An alias for onAccelerometerStarted. | +| `onChange` | A method that sets event handler. An alias for onAccelerometerChanged. | +| `onFail` | A method that sets event handler. An alias for onAccelerometerFailed. | +| `stop` |
| +| `onStop` | A method that sets event handler. An alias for onAccelerometerStopped. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-back-button.md b/docs/mini-apps/composables/use-back-button.md new file mode 100644 index 0000000..aa809b6 --- /dev/null +++ b/docs/mini-apps/composables/use-back-button.md @@ -0,0 +1,16 @@ +### useBackButton + +```ts +import { useBackButton } from 'vue-tg' + +const backButton = useBackButton() +``` + +| Name | Description | +| :----------------- | :-------------------------------------------------------------------------------------------------- | +| `isVisible` |
| +| `show` | | +| `hide` | | +| `onClick` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-biometric-manager.md b/docs/mini-apps/composables/use-biometric-manager.md new file mode 100644 index 0000000..24cb25e --- /dev/null +++ b/docs/mini-apps/composables/use-biometric-manager.md @@ -0,0 +1,27 @@ +### useBiometricManager + +```ts +import { useBiometricManager } from 'vue-tg' + +const biometricManager = useBiometricManager() +``` + +| Name | Type | +| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------ | +| `isInited` |
| +| `isBiometricAvailable` |
| +| `biometricType` |
| +| `isAccessRequested` |
| +| `isAccessGranted` |
| +| `isBiometricTokenSaved` |
| +| `deviceId` |
| +| `init` |
| +| `requestAccess` |
| +| `onManagerUpdate` | A method that sets event handler. An alias for onBiometricManagerUpdated. | +| `authenticate` |
| +| `onAuthRequest` | A method that sets event handler. An alias for onBiometricAuthRequested. | +| `updateToken` |
| +| `onTokenUpdate` | A method that sets event handler. An alias for onBiometricTokenUpdated. | +| `openSettings` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-clipboard.md b/docs/mini-apps/composables/use-clipboard.md new file mode 100644 index 0000000..14c4c82 --- /dev/null +++ b/docs/mini-apps/composables/use-clipboard.md @@ -0,0 +1,14 @@ +### useClipboard + +```ts +import { useClipboard } from 'vue-tg' + +const clipboard = useClipboard() +``` + +| Name | Description | +| :----------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| `readText` |
| +| `onReadText` | A method that sets event handler. An alias for onClipboardTextReceived. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-cloud-storage.md b/docs/mini-apps/composables/use-cloud-storage.md new file mode 100644 index 0000000..c13ac48 --- /dev/null +++ b/docs/mini-apps/composables/use-cloud-storage.md @@ -0,0 +1,18 @@ +### useCloudStorage + +```ts +import { useCloudStorage } from 'vue-tg' + +const cloudStorage = useCloudStorage() +``` + +| Name | Type | +| :----------------- | :------------------------------------------------------------------------------------------------- | +| `setItem` |
| +| `getItem` |
| +| `getItems` |
| +| `removeItem` |
| +| `removeItems` |
| +| `getKeys` |
| +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-device-orientation.md b/docs/mini-apps/composables/use-device-orientation.md new file mode 100644 index 0000000..14583bb --- /dev/null +++ b/docs/mini-apps/composables/use-device-orientation.md @@ -0,0 +1,23 @@ +### useDeviceOrientation + +```ts +import { useDeviceOrientation } from 'vue-tg' + +const deviceOrientation = useDeviceOrientation() +``` + +| Name | Description | +| :----------------- | :------------------------------------------------------------------------------------------------------------------------------- | +| `isStarted` |
| +| `absolute` |
| +| `alpha` |
| +| `beta` |
| +| `gamma` |
| +| `start` |
| +| `onStart` | A method that sets event handler. An alias for onDeviceOrientationStarted. | +| `onChange` | A method that sets event handler. An alias for onDeviceOrientationChanged. | +| `onFail` | A method that sets event handler. An alias for onDeviceOrientationFailed. | +| `stop` |
| +| `onStop` | A method that sets event handler. An alias for onDeviceOrientationStopped. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-emoji-status.md b/docs/mini-apps/composables/use-emoji-status.md new file mode 100644 index 0000000..93003cf --- /dev/null +++ b/docs/mini-apps/composables/use-emoji-status.md @@ -0,0 +1,17 @@ +### useEmojiStatus + +```ts +import { useEmojiStatus } from 'vue-tg' + +const emojiStatus = useEmojiStatus() +``` + +| Name | Description | +| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------- | +| `set` |
| +| `onSet` | A method that sets event handler. An alias for onEmojiStatusSet. | +| `onFail` | A method that sets event handler. An alias for onEmojiStatusFailed. | +| `requestAccess` |
| +| `onAccessRequest` | A method that sets event handler. An alias for onEmojiStatusAccessRequested. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-gyroscope.md b/docs/mini-apps/composables/use-gyroscope.md new file mode 100644 index 0000000..327d877 --- /dev/null +++ b/docs/mini-apps/composables/use-gyroscope.md @@ -0,0 +1,22 @@ +### useGyroscope + +```ts +import { useGyroscope } from 'vue-tg' + +const gyroscope = useGyroscope() +``` + +| Name | Description | +| :----------------- | :----------------------------------------------------------------------------------------------------------------------- | +| `isStarted` |
| +| `x` |
| +| `y` |
| +| `z` |
| +| `start` |
| +| `onStart` | A method that sets event handler. An alias for onGyroscopeStarted. | +| `onChange` | A method that sets event handler. An alias for onGyroscopeChanged. | +| `onFail` | A method that sets event handler. An alias for onGyroscopeFailed. | +| `stop` |
| +| `onStop` | A method that sets event handler. An alias for onGyroscopeStopped. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-haptic-feedback.md b/docs/mini-apps/composables/use-haptic-feedback.md new file mode 100644 index 0000000..11deb57 --- /dev/null +++ b/docs/mini-apps/composables/use-haptic-feedback.md @@ -0,0 +1,15 @@ +### useHapticFeedback + +```ts +import { useHapticFeedback } from 'vue-tg' + +const hapticFeedback = useHapticFeedback() +``` + +| Name | Description | +| :--------------------- | :------------------------------------------------------------------- | +| `impactOccurred` | | +| `notificationOccurred` | | +| `selectionChanged` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-home-screen.md b/docs/mini-apps/composables/use-home-screen.md new file mode 100644 index 0000000..859d687 --- /dev/null +++ b/docs/mini-apps/composables/use-home-screen.md @@ -0,0 +1,16 @@ +### useHomeScreen + +```ts +import { useHomeScreen } from 'vue-tg' + +const homeScreen = useHomeScreen() +``` + +| Name | Type | +| :-------------------- | :------------------------------------------------------------------------------------------------------------------------ | +| `addShortcut` | | +| `onShortcutAdd` | A method that sets event handler. An alias for onHomeScreenAdded. | +| `checkShortcutStatus` |
| +| `onShortcutCheck` | A method that sets event handler. An alias for onHomeScreenChecked. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-location-manager.md b/docs/mini-apps/composables/use-location-manager.md new file mode 100644 index 0000000..6e06437 --- /dev/null +++ b/docs/mini-apps/composables/use-location-manager.md @@ -0,0 +1,21 @@ +### useLocationManager + +```ts +import { useLocationManager } from 'vue-tg' + +const locationManager = useLocationManager() +``` + +| Name | Description | +| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------- | +| `isInited` |
| +| `isLocationAvailable` |
| +| `isAccessRequested` |
| +| `isAccessGranted` |
| +| `init` |
| +| `onManagerUpdate` | A method that sets event handler. An alias for onLocationManagerUpdated. | +| `getLocation` |
| +| `onRequest` | A method that sets event handler. An alias for onLocationRequested. | +| `openSettings` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-main-button.md b/docs/mini-apps/composables/use-main-button.md new file mode 100644 index 0000000..e7efa84 --- /dev/null +++ b/docs/mini-apps/composables/use-main-button.md @@ -0,0 +1,27 @@ +### useMainButton + +```ts +import { useMainButton } from 'vue-tg' + +const mainButton = useMainButton() +``` + +| Name | Description | +| :------------------ | :-------------------------------------------------------------------------------------------------------- | +| `text` |
| +| `color` |
| +| `textColor` |
| +| `isVisible` |
| +| `isActive` |
| +| `isProgressVisible` |
| +| `hasShineEffect` |
| +| `show` | | +| `hide` | | +| `enable` | | +| `disable` | | +| `showProgress` | | +| `hideProgress` | | +| `setParams` | | +| `onClick` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-mini-app.md b/docs/mini-apps/composables/use-mini-app.md new file mode 100644 index 0000000..0420fac --- /dev/null +++ b/docs/mini-apps/composables/use-mini-app.md @@ -0,0 +1,39 @@ +### useMiniApp + +```ts +import { useMiniApp } from 'vue-tg' + +const miniApp = useMiniApp() +``` + +| Name | Description | +| :----------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | +| `initData` | | +| `initDataUnsafe` | | +| `platform` | | +| `isActive` |
| +| `onActive` | A method that sets event handler. An alias for onActivated. | +| `onDeactive` | A method that sets event handler. An alias for onDeactivated. | +| `sendData` | | +| `switchInlineQuery` | | +| `openLink` | | +| `openTelegramLink` | | +| `openInvoice` |
| +| `onInvoiceClose` | A method that sets event handler. An alias for onInvoiceClosed. | +| `shareToStory` | | +| `shareMessage` |
| +| `onShareMessageSent` | A method that sets event handler. An alias for onShareMessageSent. | +| `onShareMessageFail` | A method that sets event handler. An alias for shareMessageFailed. | +| `downloadFile` |
| +| `onFileDownloadRequest` | A method that sets event handler. An alias for onFileDownloadRequested. | +| `requestWriteAccess` |
| +| `onWriteAccessRequest` | A method that sets event handler. An alias for onWriteAccessRequested. | +| `requestContact` |
| +| `onContactRequest` | A method that sets event handler. An alias for onContactRequested. | +| `isClosingConfirmationEnabled` |
| +| `ready` | | +| `close` | | +| `isReady` | Boolean indicating if the app is ready.
| +| `isPlatform` | Function to check if the app is running on a specified platform.
| +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-popup.md b/docs/mini-apps/composables/use-popup.md new file mode 100644 index 0000000..baaa521 --- /dev/null +++ b/docs/mini-apps/composables/use-popup.md @@ -0,0 +1,16 @@ +### usePopup + +```ts +import { usePopup } from 'vue-tg' + +const popup = usePopup() +``` + +| Name | Type | +| :----------------- | :------------------------------------------------------------------------------------------------------------------ | +| `showConfirm` |
| +| `showAlert` |
| +| `showPopup` |
| +| `onClose` | A method that sets event handler. An alias for onPopupClosed. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-qr-scanner.md b/docs/mini-apps/composables/use-qr-scanner.md new file mode 100644 index 0000000..0995dc9 --- /dev/null +++ b/docs/mini-apps/composables/use-qr-scanner.md @@ -0,0 +1,16 @@ +### useQrScanner + +```ts +import { useQrScanner } from 'vue-tg' + +const qrScanner = useQrScanner() +``` + +| Name | Description | +| :----------------- | :------------------------------------------------------------------------------------------------------------------------ | +| `show` | | +| `close` | | +| `onScan` | A method that sets event handler. An alias for onQrTextReceived. | +| `onClose` | A method that sets event handler. An alias for onScanQrPopupClosed. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-secondary-button.md b/docs/mini-apps/composables/use-secondary-button.md new file mode 100644 index 0000000..2a94307 --- /dev/null +++ b/docs/mini-apps/composables/use-secondary-button.md @@ -0,0 +1,28 @@ +### useSecondaryButton + +```ts +import { useSecondaryButton } from 'vue-tg' + +const secondaryButton = useSecondaryButton() +``` + +| Name | Description | +| :------------------ | :-------------------------------------------------------------------------------------------------------- | +| `text` |
| +| `color` |
| +| `textColor` |
| +| `isVisible` |
| +| `isActive` |
| +| `isProgressVisible` |
| +| `hasShineEffect` |
| +| `position` |
| +| `show` | | +| `hide` | | +| `enable` | | +| `disable` | | +| `showProgress` | | +| `hideProgress` | | +| `setParams` | | +| `onClick` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-settings-button.md b/docs/mini-apps/composables/use-settings-button.md new file mode 100644 index 0000000..cfec170 --- /dev/null +++ b/docs/mini-apps/composables/use-settings-button.md @@ -0,0 +1,16 @@ +### useSettingsButton + +```ts +import { useSettingsButton } from 'vue-tg' + +const settingsButton = useSettingsButton() +``` + +| Name | Description | +| :----------------- | :---------------------------------------------------------------------------------------------------- | +| `isVisible` |
| +| `show` | | +| `hide` | | +| `onClick` | | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-theme.md b/docs/mini-apps/composables/use-theme.md new file mode 100644 index 0000000..b19ba06 --- /dev/null +++ b/docs/mini-apps/composables/use-theme.md @@ -0,0 +1,18 @@ +### useTheme + +```ts +import { useTheme } from 'vue-tg' + +const theme = useTheme() +``` + +| Name | Description | +| :----------------- | :------------------------------------------------------------------------------------------------------- | +| `colorScheme` |
| +| `themeParams` |
| +| `headerColor` |
| +| `backgroundColor` |
| +| `bottomBarColor` |
| +| `onChange` | A method that sets event handler. An alias for onThemeChanged. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-viewport.md b/docs/mini-apps/composables/use-viewport.md new file mode 100644 index 0000000..8cef545 --- /dev/null +++ b/docs/mini-apps/composables/use-viewport.md @@ -0,0 +1,26 @@ +### useViewport + +```ts +import { useViewport } from 'vue-tg' + +const viewport = useViewport() +``` + +| Name | Description | +| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------- | +| `isExpanded` |
| +| `expand` | | +| `viewportHeight` |
| +| `viewportStableHeight` |
| +| `onChange` | A method that sets event handler. An alias for onViewportChanged. | +| `isFullscreen` |
| +| `onFullscreenChange` | A method that sets event handler. An alias for onFullscreenChanged. | +| `onFullscreenFail` | A method that sets event handler. An alias for onFullscreenFailed. | +| `isOrientationLocked` |
| +| `isVerticalSwipesEnabled` |
| +| `safeAreaInset` |
| +| `onSafeAreaChange` | A method that sets event handler. An alias for onSafeAreaChanged. | +| `contentSafeAreaInset` |
| +| `onContentSafeAreaChange` | A method that sets event handler. An alias for onContentSafeAreaChanged. | +| `version` | | +| `isVersionAtLeast` | | diff --git a/docs/mini-apps/composables/use-web-app-back-button.md b/docs/mini-apps/composables/use-web-app-back-button.md deleted file mode 100644 index e361a3e..0000000 --- a/docs/mini-apps/composables/use-web-app-back-button.md +++ /dev/null @@ -1,13 +0,0 @@ -### useWebAppBackButton - -```ts twoslash -// Hover to inspect type -import { useWebAppBackButton } from 'vue-tg' -``` - -| Name | Description | -| :-------------------- | :-------------------------------------------------------------------------------------------------------------------- | -| `isBackButtonVisible` |
| -| `onBackButtonClicked` | A method that sets the `backButtonClicked` [event handler](#event-handling). | -| `showBackButton` | | -| `hideBackButton` | | diff --git a/docs/mini-apps/composables/use-web-app-clipboard.md b/docs/mini-apps/composables/use-web-app-clipboard.md deleted file mode 100644 index 7271e46..0000000 --- a/docs/mini-apps/composables/use-web-app-clipboard.md +++ /dev/null @@ -1,11 +0,0 @@ -### useWebAppClipboard - -```ts twoslash -// Hover to inspect type -import { useWebAppClipboard } from 'vue-tg' -``` - -| Name | Type | -| :------------------------ | :------------------------------------------------------------------------------------------------------------------------ | -| `onClipboardTextReceived` | A method that sets the `clipboardTextReceived` [event handler](#event-handling). | -| `readTextFromClipboard` | | diff --git a/docs/mini-apps/composables/use-web-app-navigation.md b/docs/mini-apps/composables/use-web-app-navigation.md deleted file mode 100644 index 25153dd..0000000 --- a/docs/mini-apps/composables/use-web-app-navigation.md +++ /dev/null @@ -1,14 +0,0 @@ -### useWebAppNavigation - -```ts twoslash -// Hover to inspect type -import { useWebAppNavigation } from 'vue-tg' -``` - -| Name | Type | -| :------------------ | :---------------------------------------------------------------------------------------------------------------- | -| `onInvoiceClosed` | A method that sets the `invoiceClosed` [event handler](#event-handling). | -| `openInvoice` | | -| `openLink` | | -| `openTelegramLink` | | -| `switchInlineQuery` | | diff --git a/docs/mini-apps/composables/use-web-app-popup.md b/docs/mini-apps/composables/use-web-app-popup.md deleted file mode 100644 index 55f85fb..0000000 --- a/docs/mini-apps/composables/use-web-app-popup.md +++ /dev/null @@ -1,13 +0,0 @@ -### useWebAppPopup - -```ts twoslash -// Hover to inspect type -import { useWebAppPopup } from 'vue-tg' -``` - -| Name | Type | -| :-------------- | :-------------------------------------------------------------------------------------------------------------- | -| `onPopupClosed` | A method that sets the `popupClosed` [event handler](#event-handling). | -| `showAlert` | | -| `showConfirm` | | -| `showPopup` | | diff --git a/docs/mini-apps/composables/use-web-app-qr-scanner.md b/docs/mini-apps/composables/use-web-app-qr-scanner.md deleted file mode 100644 index e02fab1..0000000 --- a/docs/mini-apps/composables/use-web-app-qr-scanner.md +++ /dev/null @@ -1,13 +0,0 @@ -### useWebAppQrScanner - -```ts twoslash -// Hover to inspect type -import { useWebAppQrScanner } from 'vue-tg' -``` - -| Name | Type | -| :-------------------- | :-------------------------------------------------------------------------------------------------------------------- | -| `showScanQrPopup` | | -| `closeScanQrPopup` | | -| `onQrTextReceived` | A method that sets the `qrTextReceived` [event handler](#event-handling). | -| `onScanQrPopupClosed` | A method that sets the `scanQrPopupClosed` [event handler](#event-handling). | diff --git a/docs/mini-apps/composables/use-web-app-requests.md b/docs/mini-apps/composables/use-web-app-requests.md deleted file mode 100644 index c6f328e..0000000 --- a/docs/mini-apps/composables/use-web-app-requests.md +++ /dev/null @@ -1,13 +0,0 @@ -### useWebAppRequests - -```ts twoslash -// Hover to inspect type -import { useWebAppRequests } from 'vue-tg' -``` - -| Name | Type | -| :----------------------- | :----------------------------------------------------------------------------------------------------------------------- | -| `onContactRequested` | A method that sets the `contactRequested` [event handler](#event-handling). | -| `onWriteAccessRequested` | A method that sets the `writeAccessRequested` [event handler](#event-handling). | -| `requestContact` | | -| `requestWriteAccess` | | diff --git a/eslint.config.mjs b/eslint.config.mjs index 8de3dd7..a8d5bc8 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,6 +2,7 @@ import antfu from '@antfu/eslint-config' export default antfu({ rules: { + 'ts/consistent-type-definitions': 'off', 'vue/valid-template-root': 'off', 'vue/require-component-is': 'off', 'vue/block-order': ['error', { diff --git a/package-lock.json b/package-lock.json index 3fe7af5..f3eaacb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "vue-tg", "version": "0.8.0", "license": "MIT", - "dependencies": { - "@types/telegram-web-app": "^7" - }, "devDependencies": { "@antfu/eslint-config": "^3.11.2", "@shikijs/vitepress-twoslash": "^1.24.2", @@ -2263,12 +2260,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/telegram-web-app": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@types/telegram-web-app/-/telegram-web-app-7.10.1.tgz", - "integrity": "sha512-GKL659G6lnHRAt3Dt7L1Fa0dwvc+ZZQtJcYrJVJGwjvsbi/Rcp1qKs9pFwb34/KC04+J+TlQj4D7yKo10sBSEw==", - "license": "MIT" - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", diff --git a/package.json b/package.json index f22e9be..8fba017 100644 --- a/package.json +++ b/package.json @@ -52,9 +52,6 @@ "peerDependencies": { "vue": "^3" }, - "dependencies": { - "@types/telegram-web-app": "^7" - }, "devDependencies": { "@antfu/eslint-config": "^3.11.2", "@shikijs/vitepress-twoslash": "^1.24.2", diff --git a/scripts/generate-webapps-docs-snippets.ts b/scripts/generate-webapps-docs-snippets.ts index cf4ca47..bddcf46 100644 --- a/scripts/generate-webapps-docs-snippets.ts +++ b/scripts/generate-webapps-docs-snippets.ts @@ -113,35 +113,55 @@ async function main() { writeFileSync(`${OUTPUT_PATH}/WebApp-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const backButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(175)')) + const backButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(176)')) for (const field of backButtonSection.fields) { writeFileSync(`${OUTPUT_PATH}/BackButton-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const mainButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(179)')) + const mainButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(180)')) for (const field of mainButtonSection.fields) { writeFileSync(`${OUTPUT_PATH}/MainButton-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const settingsButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(183)')) + const settingsButtonSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(184)')) for (const field of settingsButtonSection.fields) { writeFileSync(`${OUTPUT_PATH}/SettingsButton-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const hapticFeedbackSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(187)')) + const hapticFeedbackSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(188)')) for (const field of hapticFeedbackSection.fields) { writeFileSync(`${OUTPUT_PATH}/HapticFeedback-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const cloudStorageSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(191)')) + const cloudStorageSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(192)')) for (const field of cloudStorageSection.fields) { writeFileSync(`${OUTPUT_PATH}/CloudStorage-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } - const biometricManagerSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(195)')) + const biometricManagerSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(196)')) for (const field of biometricManagerSection.fields) { writeFileSync(`${OUTPUT_PATH}/BiometricManager-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) } + + const accelerometerSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(206)')) + for (const field of accelerometerSection.fields) { + writeFileSync(`${OUTPUT_PATH}/Accelerometer-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) + } + + const deviceOrientationSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(214)')) + for (const field of deviceOrientationSection.fields) { + writeFileSync(`${OUTPUT_PATH}/DeviceOrientation-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) + } + + const gyroscopeSection = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(222)')) + for (const field of gyroscopeSection.fields) { + writeFileSync(`${OUTPUT_PATH}/Gyroscope-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) + } + + const locationManager = parseSection(dom.window.document.querySelector('#dev_page_content > h4:nth-child(230)')) + for (const field of locationManager.fields) { + writeFileSync(`${OUTPUT_PATH}/LocationManager-${normalizeFieldName(field.name)}.md`, preprocessDescription(field.description)) + } } main() diff --git a/src/components/Alert.vue b/src/components/Alert.vue index e19ff24..8b3e619 100644 --- a/src/components/Alert.vue +++ b/src/components/Alert.vue @@ -2,7 +2,7 @@ diff --git a/src/components/BackButton.vue b/src/components/BackButton.vue index 31ebe05..90488dd 100644 --- a/src/components/BackButton.vue +++ b/src/components/BackButton.vue @@ -2,7 +2,7 @@ diff --git a/src/components/BiometricManager.vue b/src/components/BiometricManager.vue index 73bba39..7655e1b 100644 --- a/src/components/BiometricManager.vue +++ b/src/components/BiometricManager.vue @@ -2,13 +2,15 @@ diff --git a/src/components/ClosingConfirmation.vue b/src/components/ClosingConfirmation.vue index 96b58ed..c8b108c 100644 --- a/src/components/ClosingConfirmation.vue +++ b/src/components/ClosingConfirmation.vue @@ -2,12 +2,17 @@ diff --git a/src/components/Confirm.vue b/src/components/Confirm.vue index 6fc8159..140b7f4 100644 --- a/src/components/Confirm.vue +++ b/src/components/Confirm.vue @@ -2,7 +2,7 @@ diff --git a/src/components/ExpandedViewport.vue b/src/components/ExpandedViewport.vue index af8344c..afe2a4c 100644 --- a/src/components/ExpandedViewport.vue +++ b/src/components/ExpandedViewport.vue @@ -2,22 +2,21 @@ diff --git a/src/components/MainButton.vue b/src/components/MainButton.vue index ea1f641..7218abe 100644 --- a/src/components/MainButton.vue +++ b/src/components/MainButton.vue @@ -2,7 +2,7 @@ diff --git a/src/components/Popup.vue b/src/components/Popup.vue index 63da9f8..a953718 100644 --- a/src/components/Popup.vue +++ b/src/components/Popup.vue @@ -2,8 +2,9 @@ diff --git a/src/components/ScanQr.vue b/src/components/ScanQr.vue index 553fcc0..22df0fe 100644 --- a/src/components/ScanQr.vue +++ b/src/components/ScanQr.vue @@ -2,7 +2,7 @@ diff --git a/src/components/SecondaryButton.vue b/src/components/SecondaryButton.vue new file mode 100644 index 0000000..447ca32 --- /dev/null +++ b/src/components/SecondaryButton.vue @@ -0,0 +1,118 @@ + + + diff --git a/src/components/SettingsButton.vue b/src/components/SettingsButton.vue index 15d6dae..b098682 100644 --- a/src/components/SettingsButton.vue +++ b/src/components/SettingsButton.vue @@ -2,7 +2,7 @@ diff --git a/src/composables-legacy/index.ts b/src/composables-legacy/index.ts new file mode 100644 index 0000000..1d2774d --- /dev/null +++ b/src/composables-legacy/index.ts @@ -0,0 +1,17 @@ +export { useWebApp } from './useWebApp' +export { useWebAppBackButton } from './useWebAppBackButton' +export { useWebAppBiometricManager } from './useWebAppBiometricManager' +export { useWebAppClipboard } from './useWebAppClipboard' +export { useWebAppClosingConfirmation } from './useWebAppClosingConfirmation' +export { useWebAppCloudStorage } from './useWebAppCloudStorage' +export { useWebAppHapticFeedback } from './useWebAppHapticFeedback' +export { useWebAppMainButton } from './useWebAppMainButton' +export { useWebAppNavigation } from './useWebAppNavigation' +export { useWebAppPopup } from './useWebAppPopup' +export { useWebAppQrScanner } from './useWebAppQrScanner' +export { useWebAppRequests } from './useWebAppRequests' +export { useWebAppSendData } from './useWebAppSendData' +export { useWebAppSettingsButton } from './useWebAppSettingsButton' +export { useWebAppShare } from './useWebAppShare' +export { useWebAppTheme } from './useWebAppTheme' +export { useWebAppViewport } from './useWebAppViewport' diff --git a/src/composables-legacy/useWebApp.ts b/src/composables-legacy/useWebApp.ts new file mode 100644 index 0000000..409fdee --- /dev/null +++ b/src/composables-legacy/useWebApp.ts @@ -0,0 +1,61 @@ +import { useMiniApp } from '../composables/useMiniApp' +import { onEvent } from '../events' +import { getWebApp } from '../sdk' + +const featureSupportVersion = { + ClosingConfirmation: '6.2', + CloudStorage: '6.9', + RequestWriteAccess: '6.9', + RequestContact: '6.9', + SettingsButton: '7.0', + BiometricManager: '7.2', + DisableVerticalSwipes: '7.7', +} +function isFeatureSupported(name: keyof typeof featureSupportVersion) { + return getWebApp().isVersionAtLeast(featureSupportVersion[name]) +} + +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ +export function useWebApp() { + const webApp = getWebApp() + const { + initData, + initDataUnsafe, + version, + isReady, + platform, + isPlatform, + sendData, + ready, + close, + } = useMiniApp({ version: '8.0' }) + + const isPlatformUnknown = isPlatform('unknown') + + const canSendData = !isPlatformUnknown && initData === '' + + return { + initData, + initDataUnsafe, + version, + platform, + isVersionAtLeast: webApp.isVersionAtLeast, + sendData, + ready, + close, + isReady, + isPlatform, + isPlatformUnknown, + isFeatureSupported, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onEvent, + /** + * @deprecated + */ + canSendData, + } +} diff --git a/src/composables-legacy/useWebAppBackButton.ts b/src/composables-legacy/useWebAppBackButton.ts new file mode 100644 index 0000000..a694a99 --- /dev/null +++ b/src/composables-legacy/useWebAppBackButton.ts @@ -0,0 +1,19 @@ +import { useBackButton } from '../composables/useBackButton' +import { onBackButtonClicked } from '../events' + +/** + * @deprecated Use [`useBackButton`](https://vue-tg.deptyped.com/mini-apps.html#usebackbutton) instead + */ +export function useWebAppBackButton() { + const backButton = useBackButton({ version: '8.0' }) + + return { + isBackButtonVisible: backButton.isVisible, + showBackButton: backButton.show, + hideBackButton: backButton.hide, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onBackButtonClicked, + } +} diff --git a/src/composables-legacy/useWebAppBiometricManager.ts b/src/composables-legacy/useWebAppBiometricManager.ts new file mode 100644 index 0000000..bac1251 --- /dev/null +++ b/src/composables-legacy/useWebAppBiometricManager.ts @@ -0,0 +1,49 @@ +import { useBiometricManager } from '../composables/useBiometricManager' +import { onBiometricAuthRequested, onBiometricManagerUpdated, onBiometricTokenUpdated } from '../events' + +/** + * @deprecated Use [`useBiometricManager`](https://vue-tg.deptyped.com/mini-apps.html#usebiometricmanager) instead + */ +export function useWebAppBiometricManager() { + const { + isInited, + isBiometricAvailable, + biometricType, + isAccessRequested, + isAccessGranted, + deviceId, + isBiometricTokenSaved, + init, + authenticate, + requestAccess, + openSettings, + updateToken, + } = useBiometricManager({ version: '8.0' }) + + return { + isBiometricInited: isInited, + isBiometricAvailable, + biometricType, + isBiometricAccessRequested: isAccessRequested, + isBiometricAccessGranted: isAccessGranted, + isBiometricTokenSaved, + biometricDeviceId: deviceId, + initBiometric: init, + requestBiometricAccess: requestAccess, + authenticateBiometric: authenticate, + updateBiometricToken: updateToken, + openBiometricSettings: openSettings, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onBiometricManagerUpdated, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onBiometricAuthRequested, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onBiometricTokenUpdated, + } +} diff --git a/src/composables-legacy/useWebAppClipboard.ts b/src/composables-legacy/useWebAppClipboard.ts new file mode 100644 index 0000000..bab2f40 --- /dev/null +++ b/src/composables-legacy/useWebAppClipboard.ts @@ -0,0 +1,17 @@ +import { useClipboard } from '../composables/useClipboard' +import { onClipboardTextReceived } from '../events' + +/** + * @deprecated Use [`useClipboard`](https://vue-tg.deptyped.com/mini-apps.html#useclipboard) instead + */ +export function useWebAppClipboard() { + const { readText } = useClipboard({ version: '8.0' }) + + return { + readTextFromClipboard: readText, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onClipboardTextReceived, + } +} diff --git a/src/composables-legacy/useWebAppClosingConfirmation.ts b/src/composables-legacy/useWebAppClosingConfirmation.ts new file mode 100644 index 0000000..56b02f0 --- /dev/null +++ b/src/composables-legacy/useWebAppClosingConfirmation.ts @@ -0,0 +1,18 @@ +import { useMiniApp } from '../composables/useMiniApp' + +/** + * @deprecated Use [`useClosingConfirmation`](https://vue-tg.deptyped.com/mini-apps.html#useclosingconfirmation) instead + */ +export function useWebAppClosingConfirmation() { + const { isClosingConfirmationEnabled } = useMiniApp({ version: '8.0' }) + + return { + isClosingConfirmationEnabled, + enableClosingConfirmation() { + isClosingConfirmationEnabled.value = true + }, + disableClosingConfirmation() { + isClosingConfirmationEnabled.value = false + }, + } +} diff --git a/src/composables-legacy/useWebAppCloudStorage.ts b/src/composables-legacy/useWebAppCloudStorage.ts new file mode 100644 index 0000000..04f2019 --- /dev/null +++ b/src/composables-legacy/useWebAppCloudStorage.ts @@ -0,0 +1,17 @@ +import { useCloudStorage } from '../composables/useCloudStorage' + +/** + * @deprecated Use [`useCloudStorage`](https://vue-tg.deptyped.com/mini-apps.html#usecloudstorage) instead + */ +export function useWebAppCloudStorage() { + const cloudStorage = useCloudStorage({ version: '8.0' }) + + return { + setStorageItem: cloudStorage.setItem, + getStorageItem: cloudStorage.getItem, + getStorageItems: cloudStorage.getItems, + removeStorageItem: cloudStorage.removeItem, + removeStorageItems: cloudStorage.removeItems, + getStorageKeys: cloudStorage.getKeys, + } +} diff --git a/src/composables-legacy/useWebAppHapticFeedback.ts b/src/composables-legacy/useWebAppHapticFeedback.ts new file mode 100644 index 0000000..4f4dceb --- /dev/null +++ b/src/composables-legacy/useWebAppHapticFeedback.ts @@ -0,0 +1,14 @@ +import { useHapticFeedback } from '../composables/useHapticFeedback' + +/** + * @deprecated Use [`useHapticFeedback`](https://vue-tg.deptyped.com/mini-apps.html#usehapticfeedback) instead + */ +export function useWebAppHapticFeedback() { + const { impactOccurred, notificationOccurred, selectionChanged } = useHapticFeedback({ version: '8.0' }) + + return { + impactOccurred, + notificationOccurred, + selectionChanged, + } +} diff --git a/src/composables-legacy/useWebAppMainButton.ts b/src/composables-legacy/useWebAppMainButton.ts new file mode 100644 index 0000000..f1359b8 --- /dev/null +++ b/src/composables-legacy/useWebAppMainButton.ts @@ -0,0 +1,33 @@ +import type { WebApp } from '../sdk' +import { useMainButton } from '../composables/useMainButton' +import { onMainButtonClicked } from '../events' + +/** + * @deprecated Use [`useMainButton`](https://vue-tg.deptyped.com/mini-apps.html#usemainbutton) instead + */ +export function useWebAppMainButton() { + const mainButton = useMainButton({ version: '8.0' }) + + return { + mainButtonText: mainButton.text, + mainButtonColor: mainButton.color, + mainButtonTextColor: mainButton.textColor, + isMainButtonVisible: mainButton.isVisible, + isMainButtonActive: mainButton.isActive, + isMainButtonProgressVisible: mainButton.isProgressVisible, + setMainButtonText(text: Parameters[0]) { + mainButton.text.value = text + }, + showMainButton: mainButton.show, + hideMainButton: mainButton.hide, + enableMainButton: mainButton.enable, + disableMainButton: mainButton.disable, + showMainButtonProgress: mainButton.showProgress, + hideMainButtonProgress: mainButton.hideProgress, + setMainButtonParams: mainButton.setParams, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onMainButtonClicked, + } +} diff --git a/src/composables-legacy/useWebAppNavigation.ts b/src/composables-legacy/useWebAppNavigation.ts new file mode 100644 index 0000000..2a3a107 --- /dev/null +++ b/src/composables-legacy/useWebAppNavigation.ts @@ -0,0 +1,20 @@ +import { useMiniApp } from '../composables/useMiniApp' +import { onInvoiceClosed } from '../events' + +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ +export function useWebAppNavigation() { + const { switchInlineQuery, openLink, openTelegramLink, openInvoice } = useMiniApp({ version: '8.0' }) + + return { + switchInlineQuery, + openLink, + openTelegramLink, + openInvoice, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onInvoiceClosed, + } +} diff --git a/src/composables-legacy/useWebAppPopup.ts b/src/composables-legacy/useWebAppPopup.ts new file mode 100644 index 0000000..0a98447 --- /dev/null +++ b/src/composables-legacy/useWebAppPopup.ts @@ -0,0 +1,19 @@ +import { usePopup } from '../composables/usePopup' +import { onPopupClosed } from '../events' + +/** + * @deprecated Use [`usePopup`](https://vue-tg.deptyped.com/mini-apps.html#usepopup) instead + */ +export function useWebAppPopup() { + const { showPopup, showAlert, showConfirm } = usePopup({ version: '8.0' }) + + return { + showPopup, + showAlert, + showConfirm, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onPopupClosed, + } +} diff --git a/src/composables-legacy/useWebAppQrScanner.ts b/src/composables-legacy/useWebAppQrScanner.ts new file mode 100644 index 0000000..ea827f6 --- /dev/null +++ b/src/composables-legacy/useWebAppQrScanner.ts @@ -0,0 +1,22 @@ +import { useQrScanner } from '../composables/useQrScanner' +import { onQrTextReceived, onScanQrPopupClosed } from '../events' + +/** + * @deprecated Use [`useQrScanner`](https://vue-tg.deptyped.com/mini-apps.html#useqrscanner) instead + */ +export function useWebAppQrScanner() { + const qrScanner = useQrScanner({ version: '8.0' }) + + return { + showScanQrPopup: qrScanner.show, + closeScanQrPopup: qrScanner.close, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onQrTextReceived, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onScanQrPopupClosed, + } +} diff --git a/src/composables-legacy/useWebAppRequests.ts b/src/composables-legacy/useWebAppRequests.ts new file mode 100644 index 0000000..c5c44e6 --- /dev/null +++ b/src/composables-legacy/useWebAppRequests.ts @@ -0,0 +1,22 @@ +import { useMiniApp } from '../composables/useMiniApp' +import { onContactRequested, onWriteAccessRequested } from '../events' + +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ +export function useWebAppRequests() { + const { requestContact, requestWriteAccess } = useMiniApp({ version: '8.0' }) + + return { + requestContact, + requestWriteAccess, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onContactRequested, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onWriteAccessRequested, + } +} diff --git a/src/composables/useWebAppSendData.ts b/src/composables-legacy/useWebAppSendData.ts similarity index 90% rename from src/composables/useWebAppSendData.ts rename to src/composables-legacy/useWebAppSendData.ts index bd2f279..c81cc8d 100644 --- a/src/composables/useWebAppSendData.ts +++ b/src/composables-legacy/useWebAppSendData.ts @@ -1,5 +1,5 @@ import { ref } from 'vue' -import { useWebApp } from './useWebApp' +import { useMiniApp } from '../composables/useMiniApp' /** * @deprecated @@ -20,7 +20,7 @@ export function useWebAppSendData( const isLoading = ref(false) - const { initData, initDataUnsafe, sendData, close } = useWebApp() + const { initData, initDataUnsafe, sendData, close } = useMiniApp({ version: '8.0' }) return { error, diff --git a/src/composables-legacy/useWebAppSettingsButton.ts b/src/composables-legacy/useWebAppSettingsButton.ts new file mode 100644 index 0000000..a66f443 --- /dev/null +++ b/src/composables-legacy/useWebAppSettingsButton.ts @@ -0,0 +1,19 @@ +import { useSettingsButton } from '../composables/useSettingsButton' +import { onSettingsButtonClicked } from '../events' + +/** + * @deprecated Use [`useSettingsButton`](https://vue-tg.deptyped.com/mini-apps.html#usesettingsbutton) instead + */ +export function useWebAppSettingsButton() { + const settingsButton = useSettingsButton({ version: '8.0' }) + + return { + isSettingsButtonVisible: settingsButton.isVisible, + showSettingsButton: settingsButton.show, + hideSettingsButton: settingsButton.hide, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onSettingsButtonClicked, + } +} diff --git a/src/composables-legacy/useWebAppShare.ts b/src/composables-legacy/useWebAppShare.ts new file mode 100644 index 0000000..cc5b82f --- /dev/null +++ b/src/composables-legacy/useWebAppShare.ts @@ -0,0 +1,12 @@ +import { useMiniApp } from '../composables/useMiniApp' + +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ +export function useWebAppShare() { + const { shareToStory } = useMiniApp({ version: '8.0' }) + + return { + shareToStory, + } +} diff --git a/src/composables-legacy/useWebAppTheme.ts b/src/composables-legacy/useWebAppTheme.ts new file mode 100644 index 0000000..77b7ddb --- /dev/null +++ b/src/composables-legacy/useWebAppTheme.ts @@ -0,0 +1,32 @@ +import type { WebApp } from '../sdk' +import { useTheme } from '../composables/useTheme' +import { onThemeChanged } from '../events' + +/** + * @deprecated Use [`useTheme`](https://vue-tg.deptyped.com/mini-apps.html#usetheme) instead + */ +export function useWebAppTheme() { + const { + colorScheme, + themeParams, + headerColor, + backgroundColor, + } = useTheme({ version: '8.0' }) + + return { + colorScheme, + themeParams, + headerColor, + backgroundColor, + setHeaderColor(color: Parameters[0]) { + headerColor.value = color + }, + setBackgroundColor(color: Parameters[0]) { + backgroundColor.value = color + }, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onThemeChanged, + } +} diff --git a/src/composables-legacy/useWebAppViewport.ts b/src/composables-legacy/useWebAppViewport.ts new file mode 100644 index 0000000..c49a0a0 --- /dev/null +++ b/src/composables-legacy/useWebAppViewport.ts @@ -0,0 +1,33 @@ +import { useViewport } from '../composables/useViewport' +import { onViewportChanged } from '../events' + +/** + * @deprecated Use [`useViewport`](https://vue-tg.deptyped.com/mini-apps.html#useviewport) instead + */ +export function useWebAppViewport() { + const { + isExpanded, + expand, + viewportHeight, + viewportStableHeight, + isVerticalSwipesEnabled, + } = useViewport({ version: '8.0' }) + + return { + isExpanded, + viewportHeight, + viewportStableHeight, + expand, + isVerticalSwipesEnabled, + enableVerticalSwipes() { + isVerticalSwipesEnabled.value = true + }, + disableVerticalSwipes() { + isVerticalSwipesEnabled.value = false + }, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onViewportChanged, + } +} diff --git a/src/composables/useAccelerometer.ts b/src/composables/useAccelerometer.ts new file mode 100644 index 0000000..7f6c2e6 --- /dev/null +++ b/src/composables/useAccelerometer.ts @@ -0,0 +1,126 @@ +import type { AccelerometerCallback, AccelerometerStartParams } from '../sdk' +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { readonly, ref } from 'vue' +import { onAccelerometerChanged, onAccelerometerFailed, onAccelerometerStarted, onAccelerometerStopped } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type AccelerometerV60 = ReturnType +type AccelerometerV80 = ReturnType + +type AccelerometerV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } & AccelerometerV60 + >; +} + +type AccelerometerV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + AccelerometerV60to80['6.0'], + { version: version } & AccelerometerV80 + >; +} + +type Accelerometer = + & AccelerometerV60to80 + & AccelerometerV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + const isStarted = ref(webApp.Accelerometer.isStarted) + const x = ref(webApp.Accelerometer.x) + const y = ref(webApp.Accelerometer.y) + const z = ref(webApp.Accelerometer.z) + + const updateState = () => { + isStarted.value = webApp.Accelerometer.isStarted + x.value = webApp.Accelerometer.x + y.value = webApp.Accelerometer.y + z.value = webApp.Accelerometer.z + } + + return { + webApp, + updateState, + isStarted, + x, + y, + z, + } +}) + +function useAccelerometer60() { + const { + isStarted, + x, + y, + z, + } = useStore() + + return { + isStarted: readonly(isStarted), + x: readonly(x), + y: readonly(y), + z: readonly(z), + } +} + +function useAccelerometer80() { + const { + webApp, + updateState, + } = useStore() + + const startAsync = promisify(webApp.Accelerometer.start) + + function start(params: AccelerometerStartParams): ReturnType + function start(params: AccelerometerStartParams, callback?: AccelerometerCallback['start']): void + function start(params: AccelerometerStartParams, callback?: AccelerometerCallback['start']): ReturnType | void { + if (callback) + webApp.Accelerometer.start(params, callback) + else + return startAsync(params) + } + + const stopAsync = promisify(webApp.Accelerometer.stop) + + function stop(): ReturnType + function stop(callback?: AccelerometerCallback['stop']): void + function stop(callback?: AccelerometerCallback['stop']): ReturnType | void { + if (callback) + webApp.Accelerometer.stop(callback) + else + return stopAsync() + } + + onAccelerometerChanged(updateState) + onAccelerometerFailed(updateState) + + return { + start, + stop, + onStart: onAccelerometerStarted, + onStop: onAccelerometerStopped, + onChange: onAccelerometerChanged, + onFail: onAccelerometerFailed, + } +} + +export function useAccelerometer( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useAccelerometer60(), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useAccelerometer80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useBackButton.ts b/src/composables/useBackButton.ts new file mode 100644 index 0000000..906d44c --- /dev/null +++ b/src/composables/useBackButton.ts @@ -0,0 +1,106 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { computed, readonly, ref } from 'vue' +import { onBackButtonClicked } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type BackButtonV60 = ReturnType +type BackButtonV61 = ReturnType + +type BackButtonV60to61 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.1'>>]: Merge< + Partial, + { version: version } & BackButtonV60 + >; +} + +type BackButtonV61toLatest = { + [version in BotApiVersionRange<'6.1', LATEST_VERSION>]: Merge< + BackButtonV60to61['6.0'], + { version: version } & BackButtonV61 + >; +} + +type BackButton = + & BackButtonV60to61 + & BackButtonV61toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const isVisible = ref(webApp.BackButton.isVisible) + + const updateState = () => { + isVisible.value = webApp.BackButton.isVisible + } + + return { + webApp, + isVisible, + updateState, + } +}) + +function useBackButton60() { + const { + isVisible, + } = useStore() + + return { + isVisible: readonly(isVisible), + } +} + +function useBackButton61() { + const { + webApp, + isVisible, + updateState, + } = useStore() + + const show = wrapFunction(webApp.BackButton.show, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const hide = wrapFunction(webApp.BackButton.hide, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + + return { + isVisible: computed({ + get() { + return isVisible.value + }, + set(isVisible) { + if (isVisible) + show() + else + hide() + }, + }), + show, + hide, + onClick: onBackButtonClicked, + } +} + +export function useBackButton( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useBackButton60(), + ...(isVersionGreaterOrEqual(version, '6.1') + ? useBackButton61() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useBiometricManager.ts b/src/composables/useBiometricManager.ts new file mode 100644 index 0000000..45b6df1 --- /dev/null +++ b/src/composables/useBiometricManager.ts @@ -0,0 +1,171 @@ +import type { BiometricAuthenticateParams, BiometricManagerCallback, BiometricRequestAccessParams } from '../sdk' +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { readonly, ref } from 'vue' +import { onBiometricAuthRequested, onBiometricManagerUpdated, onBiometricTokenUpdated } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify, promisifyWithDataObject, promisifyWithNoData, wrapFunction } from '../utils' + +type BiometricManagerV60 = ReturnType +type BiometricManagerV72 = ReturnType + +type BiometricManagerV60to72 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'7.2'>>]: Merge< + Partial, + { version: version } & BiometricManagerV60 + >; +} + +type BiometricManagerV72toLatest = { + [version in BotApiVersionRange<'7.2', LATEST_VERSION>]: Merge< + BiometricManagerV60to72['6.0'], + { version: version } & BiometricManagerV72 + >; +} + +type BiometricManager = + & BiometricManagerV60to72 + & BiometricManagerV72toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + const isInited = ref(webApp.BiometricManager.isInited) + const isBiometricAvailable = ref(webApp.BiometricManager.isBiometricAvailable) + const biometricType = ref(webApp.BiometricManager.biometricType) + const isAccessRequested = ref(webApp.BiometricManager.isAccessRequested) + const isAccessGranted = ref(webApp.BiometricManager.isAccessGranted) + const isBiometricTokenSaved = ref(webApp.BiometricManager.isBiometricTokenSaved) + const deviceId = ref(webApp.BiometricManager.deviceId) + + const updateState = () => { + isInited.value = webApp.BiometricManager.isInited + isBiometricAvailable.value = webApp.BiometricManager.isBiometricAvailable + biometricType.value = webApp.BiometricManager.biometricType + isAccessRequested.value = webApp.BiometricManager.isAccessRequested + isAccessGranted.value = webApp.BiometricManager.isAccessGranted + isBiometricTokenSaved.value = webApp.BiometricManager.isBiometricTokenSaved + deviceId.value = webApp.BiometricManager.deviceId + } + + return { + webApp, + updateState, + isInited, + isBiometricAvailable, + biometricType, + isAccessRequested, + isAccessGranted, + isBiometricTokenSaved, + deviceId, + } +}) + +function useBiometricManager60() { + const { + isInited, + isBiometricAvailable, + biometricType, + isAccessRequested, + isAccessGranted, + isBiometricTokenSaved, + deviceId, + } = useStore() + + return { + isInited: readonly(isInited), + isBiometricAvailable: readonly(isBiometricAvailable), + biometricType: readonly(biometricType), + isAccessRequested: readonly(isAccessRequested), + isAccessGranted: readonly(isAccessGranted), + isBiometricTokenSaved: readonly(isBiometricTokenSaved), + deviceId: readonly(deviceId), + } +} + +function useBiometricManager72() { + const { + webApp, + updateState, + } = useStore() + + const initAsync = promisifyWithNoData(webApp.BiometricManager.init) + + function init(): ReturnType + function init(callback?: BiometricManagerCallback['init']): void + function init(callback?: BiometricManagerCallback['init']): ReturnType | void { + if (callback) + webApp.BiometricManager.init(callback) + else + return initAsync() + } + + const requestAccessAsync = promisify(webApp.BiometricManager.requestAccess) + + function requestAccess(params: BiometricRequestAccessParams): ReturnType + function requestAccess(params: BiometricRequestAccessParams, callback?: BiometricManagerCallback['requestAccess']): void + function requestAccess(params: BiometricRequestAccessParams, callback?: BiometricManagerCallback['requestAccess']): ReturnType | void { + if (callback) + webApp.BiometricManager.requestAccess(params, callback) + else + return requestAccessAsync(params) + } + + const authenticateAsync = promisifyWithDataObject( + webApp.BiometricManager.authenticate, + (isAuthenticated: boolean, token?: string) => ({ isAuthenticated, token }), + ) + + function authenticate(params: BiometricAuthenticateParams): ReturnType + function authenticate(params: BiometricAuthenticateParams, callback?: BiometricManagerCallback['authenticate']): void + function authenticate(params: BiometricAuthenticateParams, callback?: BiometricManagerCallback['authenticate']): ReturnType | void { + if (callback) + webApp.BiometricManager.authenticate(params, callback) + else + return authenticateAsync(params) + } + + const updateBiometricTokenAsync = promisify(webApp.BiometricManager.updateBiometricToken) + + function updateBiometricToken(token: string,): ReturnType + function updateBiometricToken(token: string, callback?: BiometricManagerCallback['updateBiometricToken']): void + function updateBiometricToken(token: string, callback?: BiometricManagerCallback['updateBiometricToken']): ReturnType | void { + if (callback) + webApp.BiometricManager.updateBiometricToken(token, callback) + else + return updateBiometricTokenAsync(token) + } + + onBiometricManagerUpdated(updateState) + onBiometricAuthRequested(updateState) + onBiometricTokenUpdated(updateState) + + return { + init, + requestAccess, + authenticate, + updateToken: updateBiometricToken, + openSettings: wrapFunction(webApp.BiometricManager.openSettings, { + omitReturn: true, + }), + onManagerUpdate: onBiometricManagerUpdated, + onAuthRequest: onBiometricAuthRequested, + onTokenUpdate: onBiometricTokenUpdated, + } +} + +export function useBiometricManager( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useBiometricManager60(), + ...(isVersionGreaterOrEqual(version, '7.2') + ? useBiometricManager72() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useClipboard.ts b/src/composables/useClipboard.ts new file mode 100644 index 0000000..58fbeb0 --- /dev/null +++ b/src/composables/useClipboard.ts @@ -0,0 +1,71 @@ +import type { WebAppCallback } from '../sdk' +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { onClipboardTextReceived } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type ClipboardV64 = ReturnType + +type ClipboardV60to64 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.4'>>]: Merge< + Partial, + { version: version } + >; +} + +type ClipboardV64toLatest = { + [version in BotApiVersionRange<'6.4', LATEST_VERSION>]: Merge< + ClipboardV60to64['6.0'], + { version: version } & ClipboardV64 + >; +} + +type Clipboard = + & ClipboardV60to64 + & ClipboardV64toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useClipboard64() { + const { + webApp, + } = useStore() + + const readTextFromClipboardAsync = promisify(webApp.readTextFromClipboard) + + function readTextFromClipboard(): ReturnType + function readTextFromClipboard(callback?: WebAppCallback['readTextFromClipboard']): void + function readTextFromClipboard(callback?: WebAppCallback['readTextFromClipboard']): ReturnType | void { + if (callback) + webApp.readTextFromClipboard(callback) + else + return readTextFromClipboardAsync() + } + + return { + readText: readTextFromClipboard, + onReadText: onClipboardTextReceived, + } +} + +export function useClipboard( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '6.4') + ? useClipboard64() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useCloudStorage.ts b/src/composables/useCloudStorage.ts new file mode 100644 index 0000000..52fdb44 --- /dev/null +++ b/src/composables/useCloudStorage.ts @@ -0,0 +1,129 @@ +import type { CloudStorageCallback } from '../sdk' +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisifyWithError } from '../utils' + +type CloudStorageV69 = ReturnType + +type CloudStorageV60to69 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.9'>>]: Merge< + Partial, + { version: version } + >; +} + +type CloudStorageV69toLatest = { + [version in BotApiVersionRange<'6.9', LATEST_VERSION>]: Merge< + CloudStorageV60to69['6.0'], + { version: version } & CloudStorageV69 + >; +} + +type CloudStorage = + & CloudStorageV60to69 + & CloudStorageV69toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useCloudStorage69() { + const { + webApp, + } = useStore() + + const setItemAsync = promisifyWithError(webApp.CloudStorage.setItem) + + function setItem(key: string, value: string): ReturnType + function setItem(key: string, value: string, callback?: CloudStorageCallback['setItem']): void + function setItem(key: string, value: string, callback?: CloudStorageCallback['setItem']): ReturnType | void { + if (callback) + webApp.CloudStorage.setItem(key, value, callback) + else + return setItemAsync(key, value) + } + + const getItemAsync = promisifyWithError(webApp.CloudStorage.getItem) + + function getItem(key: string): ReturnType + function getItem(key: string, callback?: CloudStorageCallback['getItem']): void + function getItem(key: string, callback?: CloudStorageCallback['getItem']): ReturnType | void { + if (callback) + webApp.CloudStorage.getItem(key, callback) + else + return getItemAsync(key) + } + + const getItemsAsync = promisifyWithError(webApp.CloudStorage.getItems) + + function getItems(keys: string[]): ReturnType + function getItems(keys: string[], callback?: CloudStorageCallback['getItems']): void + function getItems(keys: string[], callback?: CloudStorageCallback['getItems']): ReturnType | void { + if (callback) + webApp.CloudStorage.getItems(keys, callback) + else + return getItemsAsync(keys) + } + + const removeItemAsync = promisifyWithError(webApp.CloudStorage.removeItem) + + function removeItem(key: string): ReturnType + function removeItem(key: string, callback?: CloudStorageCallback['removeItem']): void + function removeItem(key: string, callback?: CloudStorageCallback['removeItem']): ReturnType | void { + if (callback) + webApp.CloudStorage.removeItem(key, callback) + else + return removeItemAsync(key) + } + + const removeItemsAsync = promisifyWithError(webApp.CloudStorage.removeItems) + + function removeItems(keys: string[]): ReturnType + function removeItems(keys: string[], callback?: CloudStorageCallback['removeItems']): void + function removeItems(keys: string[], callback?: CloudStorageCallback['removeItems']): ReturnType | void { + if (callback) + webApp.CloudStorage.removeItems(keys, callback) + else + return removeItemsAsync(keys) + } + + const getKeysAsync = promisifyWithError(webApp.CloudStorage.getKeys) + + function getKeys(): ReturnType + function getKeys(callback?: CloudStorageCallback['getKeys']): void + function getKeys(callback?: CloudStorageCallback['getKeys']): ReturnType | void { + if (callback) + webApp.CloudStorage.getKeys(callback) + else + return getKeysAsync() + } + + return { + setItem, + getItem, + getItems, + removeItem, + removeItems, + getKeys, + } +} + +export function useCloudStorage( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '6.9') + ? useCloudStorage69() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useDeviceOrientation.ts b/src/composables/useDeviceOrientation.ts new file mode 100644 index 0000000..5827d15 --- /dev/null +++ b/src/composables/useDeviceOrientation.ts @@ -0,0 +1,138 @@ +import type { DeviceOrientationCallback, DeviceOrientationStartParams } from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { readonly, ref } from 'vue' +import { onDeviceOrientationChanged, onDeviceOrientationFailed, onDeviceOrientationStarted, onDeviceOrientationStopped } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type DeviceOrientationV60 = ReturnType +type DeviceOrientationV80 = ReturnType + +type DeviceOrientationV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } & DeviceOrientationV60 + >; +} + +type DeviceOrientationV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + DeviceOrientationV60to80['6.0'], + { version: version } & DeviceOrientationV80 + >; +} + +type DeviceOrientation = + & DeviceOrientationV60to80 + & DeviceOrientationV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + const isStarted = ref(webApp.DeviceOrientation.isStarted) + const absolute = ref(webApp.DeviceOrientation.absolute) + const alpha = ref(webApp.DeviceOrientation.alpha) + const beta = ref(webApp.DeviceOrientation.beta) + const gamma = ref(webApp.DeviceOrientation.gamma) + + const updateState = () => { + isStarted.value = webApp.DeviceOrientation.isStarted + absolute.value = webApp.DeviceOrientation.absolute + alpha.value = webApp.DeviceOrientation.alpha + beta.value = webApp.DeviceOrientation.beta + gamma.value = webApp.DeviceOrientation.gamma + } + + return { + webApp, + updateState, + isStarted, + absolute, + alpha, + beta, + gamma, + } +}) + +function useDeviceOrientation60() { + const { + isStarted, + absolute, + alpha, + beta, + gamma, + } = useStore() + + return { + isStarted: readonly(isStarted), + absolute: readonly(absolute), + alpha: readonly(alpha), + beta: readonly(beta), + gamma: readonly(gamma), + } +} + +function useDeviceOrientation80() { + const { + webApp, + updateState, + } = useStore() + + const startAsync = promisify(webApp.DeviceOrientation.start) + + function start(params: DeviceOrientationStartParams): ReturnType + function start(params: DeviceOrientationStartParams, callback?: DeviceOrientationCallback['start']): void + function start(params: DeviceOrientationStartParams, callback?: DeviceOrientationCallback['start']): ReturnType | void { + if (callback) + webApp.DeviceOrientation.start(params, callback) + else + return startAsync(params) + } + + const stopAsync = promisify(webApp.DeviceOrientation.stop) + + function stop(): ReturnType + function stop(callback?: DeviceOrientationCallback['stop']): void + function stop(callback?: DeviceOrientationCallback['stop']): ReturnType | void { + if (callback) + webApp.DeviceOrientation.stop(callback) + else + return stopAsync() + } + + onDeviceOrientationChanged(updateState) + onDeviceOrientationFailed(updateState) + + return { + start, + stop, + onStart: onDeviceOrientationStarted, + onStop: onDeviceOrientationStopped, + onChange: onDeviceOrientationChanged, + onFail: onDeviceOrientationFailed, + } +} + +export function useDeviceOrientation( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useDeviceOrientation60(), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useDeviceOrientation80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useEmojiStatus.ts b/src/composables/useEmojiStatus.ts new file mode 100644 index 0000000..9f81906 --- /dev/null +++ b/src/composables/useEmojiStatus.ts @@ -0,0 +1,92 @@ +import type { EmojiStatusParams, WebAppCallback } from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { onEmojiStatusAccessRequested, onEmojiStatusFailed, onEmojiStatusSet } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type EmojiStatusV80 = ReturnType + +type EmojiStatusV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } + >; +} + +type EmojiStatusV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + EmojiStatusV60to80['6.0'], + { version: version } & EmojiStatusV80 + >; +} + +type EmojiStatus = + & EmojiStatusV60to80 + & EmojiStatusV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useEmojiStatus80() { + const { + webApp, + } = useStore() + + const setEmojiStatusAsync = promisify(webApp.setEmojiStatus) + + function setEmojiStatus(custom_emoji_id: string, params: EmojiStatusParams): ReturnType + function setEmojiStatus(custom_emoji_id: string, params: EmojiStatusParams, callback?: WebAppCallback['setEmojiStatus']): void + function setEmojiStatus(custom_emoji_id: string, params: EmojiStatusParams, callback?: WebAppCallback['setEmojiStatus']): ReturnType | void { + if (callback) + webApp.setEmojiStatus(custom_emoji_id, params, callback) + else + return setEmojiStatusAsync(custom_emoji_id, params) + } + + const requestEmojiStatusAccessAsync = promisify(webApp.requestEmojiStatusAccess) + + function requestEmojiStatusAccess(): ReturnType + function requestEmojiStatusAccess(callback?: WebAppCallback['requestEmojiStatusAccess']): void + function requestEmojiStatusAccess(callback?: WebAppCallback['requestEmojiStatusAccess']): ReturnType | void { + if (callback) + webApp.requestEmojiStatusAccess(callback) + else + return requestEmojiStatusAccessAsync() + } + + return { + set: setEmojiStatus, + requestAccess: requestEmojiStatusAccess, + onSet: onEmojiStatusSet, + onFail: onEmojiStatusFailed, + onAccessRequest: onEmojiStatusAccessRequested, + } +} + +export function useEmojiStatus( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '8.0') + ? useEmojiStatus80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useGyroscope.ts b/src/composables/useGyroscope.ts new file mode 100644 index 0000000..00ace81 --- /dev/null +++ b/src/composables/useGyroscope.ts @@ -0,0 +1,126 @@ +import type { GyroscopeCallback, GyroscopeStartParams } from '../sdk' +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { readonly, ref } from 'vue' +import { onGyroscopeChanged, onGyroscopeFailed, onGyroscopeStarted, onGyroscopeStopped } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type GyroscopeV60 = ReturnType +type GyroscopeV80 = ReturnType + +type GyroscopeV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } & GyroscopeV60 + >; +} + +type GyroscopeV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + GyroscopeV60to80['6.0'], + { version: version } & GyroscopeV80 + >; +} + +type Gyroscope = + & GyroscopeV60to80 + & GyroscopeV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + const isStarted = ref(webApp.Gyroscope.isStarted) + const x = ref(webApp.Gyroscope.x) + const y = ref(webApp.Gyroscope.y) + const z = ref(webApp.Gyroscope.z) + + const updateState = () => { + isStarted.value = webApp.Gyroscope.isStarted + x.value = webApp.Gyroscope.x + y.value = webApp.Gyroscope.y + z.value = webApp.Gyroscope.z + } + + return { + webApp, + updateState, + isStarted, + x, + y, + z, + } +}) + +function useGyroscope60() { + const { + isStarted, + x, + y, + z, + } = useStore() + + return { + isStarted: readonly(isStarted), + x: readonly(x), + y: readonly(y), + z: readonly(z), + } +} + +function useGyroscope80() { + const { + webApp, + updateState, + } = useStore() + + const startAsync = promisify(webApp.Gyroscope.start) + + function start(params: GyroscopeStartParams): ReturnType + function start(params: GyroscopeStartParams, callback?: GyroscopeCallback['start']): void + function start(params: GyroscopeStartParams, callback?: GyroscopeCallback['start']): ReturnType | void { + if (callback) + webApp.Gyroscope.start(params, callback) + else + return startAsync(params) + } + + const stopAsync = promisify(webApp.Gyroscope.stop) + + function stop(): ReturnType + function stop(callback?: GyroscopeCallback['stop']): void + function stop(callback?: GyroscopeCallback['stop']): ReturnType | void { + if (callback) + webApp.Gyroscope.stop(callback) + else + return stopAsync() + } + + onGyroscopeChanged(updateState) + onGyroscopeFailed(updateState) + + return { + start, + stop, + onStart: onGyroscopeStarted, + onStop: onGyroscopeStopped, + onChange: onGyroscopeChanged, + onFail: onGyroscopeFailed, + } +} + +export function useGyroscope( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useGyroscope60(), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useGyroscope80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useHapticFeedback.ts b/src/composables/useHapticFeedback.ts new file mode 100644 index 0000000..f79a2d7 --- /dev/null +++ b/src/composables/useHapticFeedback.ts @@ -0,0 +1,69 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type HapticFeedbackV61 = ReturnType + +type HapticFeedbackV60to61 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.1'>>]: Merge< + Partial, + { version: version } + >; +} + +type HapticFeedbackV61toLatest = { + [version in BotApiVersionRange<'6.1', LATEST_VERSION>]: Merge< + HapticFeedbackV60to61['6.0'], + { version: version } & HapticFeedbackV61 + >; +} + +type HapticFeedback = + & HapticFeedbackV60to61 + & HapticFeedbackV61toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useHapticFeedback61() { + const { + webApp, + } = useStore() + + const impactOccurred = wrapFunction(webApp.HapticFeedback.impactOccurred, { + omitReturn: true, + }) + const notificationOccurred = wrapFunction(webApp.HapticFeedback.notificationOccurred, { + omitReturn: true, + }) + const selectionChanged = wrapFunction(webApp.HapticFeedback.selectionChanged, { + omitReturn: true, + }) + + return { + impactOccurred, + notificationOccurred, + selectionChanged, + } +} + +export function useHapticFeedback( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '6.1') + ? useHapticFeedback61() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useHomeScreen.ts b/src/composables/useHomeScreen.ts new file mode 100644 index 0000000..0e38474 --- /dev/null +++ b/src/composables/useHomeScreen.ts @@ -0,0 +1,78 @@ +import type { WebAppCallback } from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { onHomeScreenAdded, onHomeScreenChecked } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify } from '../utils' + +type HomeScreenV80 = ReturnType + +type HomeScreenV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } + >; +} + +type HomeScreenV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + HomeScreenV60to80['6.0'], + { version: version } & HomeScreenV80 + >; +} + +type HomeScreen = + & HomeScreenV60to80 + & HomeScreenV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useHomeScreen80() { + const { + webApp, + } = useStore() + + const checkHomeScreenStatusAsync = promisify(webApp.checkHomeScreenStatus) + + function checkHomeScreenStatus(): ReturnType + function checkHomeScreenStatus(callback?: WebAppCallback['checkHomeScreenStatus']): void + function checkHomeScreenStatus(callback?: WebAppCallback['checkHomeScreenStatus']): ReturnType | void { + if (callback) + webApp.checkHomeScreenStatus(callback) + else + return checkHomeScreenStatusAsync() + } + + return { + addShortcut: webApp.addToHomeScreen, + checkShortcutStatus: checkHomeScreenStatus, + onShortcutAdd: onHomeScreenAdded, + onShortcutCheck: onHomeScreenChecked, + } +} + +export function useHomeScreen< + Version extends BotApiVersion, +>(options: { version: Version }) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '8.0') + ? useHomeScreen80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useLocationManager.ts b/src/composables/useLocationManager.ts new file mode 100644 index 0000000..a3788f3 --- /dev/null +++ b/src/composables/useLocationManager.ts @@ -0,0 +1,134 @@ +import type { LocationManagerCallback } from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { readonly, ref } from 'vue' +import { onLocationManagerUpdated, onLocationRequested } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify, promisifyWithNoData, wrapFunction } from '../utils' + +type LocationManagerV60 = ReturnType +type LocationManagerV80 = ReturnType + +type LocationManagerV60to80 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'8.0'>>]: Merge< + Partial, + { version: version } & LocationManagerV60 + >; +} + +type LocationManagerV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + LocationManagerV60to80['6.0'], + { version: version } & LocationManagerV80 + >; +} + +type LocationManager = + & LocationManagerV60to80 + & LocationManagerV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + const isInited = ref(webApp.LocationManager.isInited) + const isLocationAvailable = ref(webApp.LocationManager.isLocationAvailable) + const isAccessRequested = ref(webApp.LocationManager.isAccessRequested) + const isAccessGranted = ref(webApp.LocationManager.isAccessGranted) + + const updateState = () => { + isInited.value = webApp.LocationManager.isInited + isLocationAvailable.value = webApp.LocationManager.isLocationAvailable + isAccessRequested.value = webApp.LocationManager.isAccessRequested + isAccessGranted.value = webApp.LocationManager.isAccessGranted + } + + return { + webApp, + updateState, + isInited, + isLocationAvailable, + isAccessRequested, + isAccessGranted, + } +}) + +function useLocationManager60() { + const { + isInited, + isLocationAvailable, + isAccessRequested, + isAccessGranted, + } = useStore() + + return { + isInited: readonly(isInited), + isLocationAvailable: readonly(isLocationAvailable), + isAccessRequested: readonly(isAccessRequested), + isAccessGranted: readonly(isAccessGranted), + } +} + +function useLocationManager80() { + const { + webApp, + updateState, + } = useStore() + + const initAsync = promisifyWithNoData(webApp.LocationManager.init) + + function init(): ReturnType + function init(callback?: LocationManagerCallback['init']): void + function init(callback?: LocationManagerCallback['init']): ReturnType | void { + if (callback) + webApp.LocationManager.init(callback) + else + return initAsync() + } + + const getLocationAsync = promisify(webApp.LocationManager.getLocation) + + function getLocation(): ReturnType + function getLocation(callback?: LocationManagerCallback['getLocation']): void + function getLocation(callback?: LocationManagerCallback['getLocation']): ReturnType | void { + if (callback) + webApp.LocationManager.getLocation(callback) + else + return getLocationAsync() + } + + onLocationManagerUpdated(updateState) + onLocationRequested(updateState) + + return { + init, + getLocation, + openSettings: wrapFunction(webApp.LocationManager.openSettings, { + omitReturn: true, + }), + onManagerUpdate: onLocationManagerUpdated, + onRequest: onLocationRequested, + } +} + +export function useLocationManager( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useLocationManager60(), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useLocationManager80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useMainButton.ts b/src/composables/useMainButton.ts new file mode 100644 index 0000000..a6cf0bd --- /dev/null +++ b/src/composables/useMainButton.ts @@ -0,0 +1,225 @@ +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { computed, readonly, ref } from 'vue' +import { onMainButtonClicked } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type MainButtonV60 = ReturnType +type MainButtonV710 = ReturnType + +type MainButtonV60to710 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'7.10'>>]: Merge< + Partial, + { version: version } & MainButtonV60 + >; +} + +type MainButtonV710toLatest = { + [version in BotApiVersionRange<'7.10', LATEST_VERSION>]: Merge< + MainButtonV60to710['6.0'], + { version: version } & MainButtonV710 + >; +} + +type MainButton = + & MainButtonV60to710 + & MainButtonV710toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const text = ref(webApp.MainButton.text) + const color = ref(webApp.MainButton.color) + const textColor = ref(webApp.MainButton.textColor) + const isVisible = ref(webApp.MainButton.isVisible) + const isActive = ref(webApp.MainButton.isActive) + const isProgressVisible = ref(webApp.MainButton.isProgressVisible) + const hasShineEffect = ref(webApp.MainButton.hasShineEffect) + + const updateState = () => { + text.value = webApp.MainButton.text + color.value = webApp.MainButton.color + textColor.value = webApp.MainButton.textColor + isVisible.value = webApp.MainButton.isVisible + isActive.value = webApp.MainButton.isActive + isProgressVisible.value = webApp.MainButton.isProgressVisible + hasShineEffect.value = webApp.MainButton.hasShineEffect + } + + return { + webApp, + updateState, + text, + color, + textColor, + isVisible, + isActive, + isProgressVisible, + hasShineEffect, + } +}) + +function useMainButton60() { + const { + webApp, + updateState, + text, + color, + textColor, + isVisible, + isActive, + isProgressVisible, + hasShineEffect, + } = useStore() + + const showProgress = wrapFunction(webApp.MainButton.showProgress, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const hideProgress = wrapFunction(webApp.MainButton.hideProgress, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const setParams = wrapFunction(webApp.MainButton.setParams, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + + return { + text: computed({ + get() { + return text.value + }, + set(text) { + setParams({ text }) + }, + }), + color: computed({ + get() { + return color.value + }, + set(color) { + setParams({ color }) + }, + }), + textColor: computed({ + get() { + return textColor.value + }, + set(textColor) { + setParams({ text_color: textColor }) + }, + }), + isVisible: computed({ + get() { + return isVisible.value + }, + set(isVisible) { + setParams({ is_visible: isVisible }) + }, + }), + isActive: computed({ + get() { + return isActive.value + }, + set(isActive) { + setParams({ is_active: isActive }) + }, + }), + isProgressVisible: computed({ + get() { + return isProgressVisible.value + }, + set(isProgressVisible) { + if (isProgressVisible) + showProgress() + else + hideProgress() + }, + }), + hasShineEffect: readonly(hasShineEffect), + show: wrapFunction(webApp.MainButton.show, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + hide: wrapFunction(webApp.MainButton.hide, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + enable: wrapFunction(webApp.MainButton.enable, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + disable: wrapFunction(webApp.MainButton.disable, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + showProgress, + hideProgress, + setParams, + onClick: onMainButtonClicked, + } +} + +function useMainButton710() { + const { + webApp, + updateState, + hasShineEffect, + } = useStore() + + const setParams = wrapFunction(webApp.MainButton.setParams, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + + return { + hasShineEffect: computed({ + get() { + return hasShineEffect.value + }, + set(hasShineEffect) { + setParams({ has_shine_effect: hasShineEffect }) + }, + }), + } +} + +export function useMainButton( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useMainButton60(), + ...(isVersionGreaterOrEqual(version, '7.10') + ? useMainButton710() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useMiniApp.ts b/src/composables/useMiniApp.ts new file mode 100644 index 0000000..78dc592 --- /dev/null +++ b/src/composables/useMiniApp.ts @@ -0,0 +1,325 @@ +import type { + DownloadFileParams, + WebAppCallback, +} from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { computed, readonly, ref } from 'vue' +import { onActivated, onContactRequested, onDeactivated, onFileDownloadRequested, onInvoiceClosed, onShareMessageFailed, onShareMessageSent, onWriteAccessRequested } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify, wrapFunction } from '../utils' + +type MiniAppV60 = ReturnType +type MiniAppV61 = ReturnType +type MiniAppV62 = ReturnType +type MiniAppV67 = ReturnType +type MiniAppV69 = ReturnType +type MiniAppV78 = ReturnType +type MiniAppV80 = ReturnType + +type MiniAppV60to61 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.1'>>]: Merge< + Partial< + & MiniAppV61 + & MiniAppV62 + & MiniAppV67 + & MiniAppV69 + & MiniAppV78 + & MiniAppV80 + >, + { version: version } & MiniAppV60 + >; +} + +type MiniAppV61to62 = { + [version in BotApiVersionRange<'6.1', BotApiPrevVersion<'6.2'>>]: Merge< + MiniAppV60to61['6.0'], + { version: version } & MiniAppV61 + >; +} + +type MiniAppV62to67 = { + [version in BotApiVersionRange<'6.2', BotApiPrevVersion<'6.7'>>]: Merge< + MiniAppV61to62['6.1'], + { version: version } & MiniAppV62 + >; +} + +type MiniAppV67to69 = { + [version in BotApiVersionRange<'6.7', BotApiPrevVersion<'6.9'>>]: Merge< + MiniAppV62to67['6.2'], + { version: version } & MiniAppV67 + >; +} + +type MiniAppV69to78 = { + [version in BotApiVersionRange<'6.9', BotApiPrevVersion<'7.8'>>]: Merge< + MiniAppV67to69['6.7'], + { version: version } & MiniAppV69 + >; +} + +type MiniAppV78to80 = { + [version in BotApiVersionRange<'7.8', BotApiPrevVersion<'8.0'>>]: Merge< + MiniAppV69to78['6.9'], + { version: version } & MiniAppV78 + >; +} + +type MiniAppV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + MiniAppV78to80['7.8'], + { version: version } & MiniAppV80 + >; +} + +type MiniApp = + & MiniAppV60to61 + & MiniAppV61to62 + & MiniAppV62to67 + & MiniAppV67to69 + & MiniAppV69to78 + & MiniAppV78to80 + & MiniAppV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const isReady = ref(false) + const isClosingConfirmationEnabled = ref(webApp.isClosingConfirmationEnabled) + const isActive = ref(webApp.isActive) + + const updateState = () => { + isActive.value = webApp.isActive + isClosingConfirmationEnabled.value = webApp.isClosingConfirmationEnabled + } + + return { + webApp, + updateState, + isReady, + isActive, + isClosingConfirmationEnabled, + } +}) + +function useMiniApp60() { + const { + webApp, + isReady, + isActive, + isClosingConfirmationEnabled, + } = useStore() + + return { + initData: webApp.initData, + initDataUnsafe: webApp.initDataUnsafe, + platform: webApp.platform, + sendData: webApp.sendData, + openLink: webApp.openLink, + openTelegramLink: webApp.openTelegramLink, + ready: wrapFunction(webApp.ready, { + hooks: { + after: () => { + isReady.value = true + }, + }, + }), + close: webApp.close, + isClosingConfirmationEnabled: readonly(isClosingConfirmationEnabled), + isActive: readonly(isActive), + isReady: readonly(isReady), + isPlatform, + } +} + +function useMiniApp61() { + const { webApp } = useStore() + + const openInvoiceAsync = promisify(webApp.openInvoice) + + function openInvoice(url: string): ReturnType + function openInvoice(url: string, callback?: WebAppCallback['openInvoice']): void + function openInvoice(url: string, callback?: WebAppCallback['openInvoice']): ReturnType | void { + if (callback) + webApp.openInvoice(url, callback) + else + return openInvoiceAsync(url) + } + + return { + openInvoice, + onInvoiceClose: onInvoiceClosed, + } +} + +function useMiniApp62() { + const { + webApp, + updateState, + isClosingConfirmationEnabled, + } = useStore() + + const enableClosingConfirmation = wrapFunction(webApp.enableClosingConfirmation, { + hooks: { + after: updateState, + }, + }) + const disableClosingConfirmation = wrapFunction(webApp.disableClosingConfirmation, { + hooks: { + after: updateState, + }, + }) + + return { + isClosingConfirmationEnabled: computed({ + get() { + return isClosingConfirmationEnabled.value + }, + set(isEnabled) { + if (isEnabled) + enableClosingConfirmation() + else + disableClosingConfirmation() + }, + }), + } +} + +function useMiniApp67() { + const { webApp } = useStore() + + return { + switchInlineQuery: webApp.switchInlineQuery, + } +} + +function useMiniApp69() { + const { webApp } = useStore() + + const requestContactAsync = promisify(webApp.requestContact) + + function requestContact(): ReturnType + function requestContact(callback?: WebAppCallback['requestContact']): void + function requestContact(callback?: WebAppCallback['requestContact']): ReturnType | void { + if (callback) + webApp.requestContact(callback) + else + return requestContactAsync() + } + + const requestWriteAccessAsync = promisify(webApp.requestWriteAccess) + + function requestWriteAccess(): ReturnType + function requestWriteAccess(callback?: WebAppCallback['requestWriteAccess']): void + function requestWriteAccess(callback?: WebAppCallback['requestWriteAccess']): ReturnType | void { + if (callback) + webApp.requestWriteAccess(callback) + else + return requestWriteAccessAsync() + } + + return { + requestContact, + requestWriteAccess, + onContactRequest: onContactRequested, + onWriteAccessRequest: onWriteAccessRequested, + } +} + +function useMiniApp78() { + const { webApp } = useStore() + + return { + shareToStory: webApp.shareToStory, + } +} + +function useMiniApp80() { + const { + webApp, + updateState, + } = useStore() + + const shareMessageAsync = promisify(webApp.shareMessage) + + function shareMessage(msg_id: string): ReturnType + function shareMessage(msg_id: string, callback?: WebAppCallback['shareMessage']): void + function shareMessage(msg_id: string, callback?: WebAppCallback['shareMessage']): ReturnType | void { + if (callback) + webApp.shareMessage(msg_id, callback) + else + return shareMessageAsync(msg_id) + } + + const downloadFileAsync = promisify(webApp.downloadFile) + + function downloadFile(params: DownloadFileParams): ReturnType + function downloadFile(params: DownloadFileParams, callback?: WebAppCallback['downloadFile']): void + function downloadFile(params: DownloadFileParams, callback?: WebAppCallback['downloadFile']): ReturnType | void { + if (callback) + webApp.downloadFile(params, callback) + else + return downloadFileAsync(params) + } + + onActivated(updateState) + onDeactivated(updateState) + + return { + shareMessage, + downloadFile, + onActive: onActivated, + onDeactive: onDeactivated, + onShareMessageSent, + onShareMessageFail: onShareMessageFailed, + onFileDownloadRequest: onFileDownloadRequested, + } +} + +export function useMiniApp( + options: { + version: Version + }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useMiniApp60(), + ...(isVersionGreaterOrEqual(version, '6.1') && useMiniApp61()), + ...(isVersionGreaterOrEqual(version, '6.2') && useMiniApp62()), + ...(isVersionGreaterOrEqual(version, '6.7') && useMiniApp67()), + ...(isVersionGreaterOrEqual(version, '6.9') && useMiniApp69()), + ...(isVersionGreaterOrEqual(version, '7.8') && useMiniApp78()), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useMiniApp80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} + +export function isVersionAtLeast(version: BotApiVersion) { + return isVersionGreaterOrEqual(version, getWebApp().version) +} + +function isPlatform( + name: + | (string & Record) + | 'unknown' + | 'android' + | 'android_x' + | 'ios' + | 'macos' + | 'tdesktop' + | 'weba' + | 'webk' + | 'unigram', +) { + return getWebApp().platform === name +} diff --git a/src/composables/usePopup.ts b/src/composables/usePopup.ts new file mode 100644 index 0000000..13bfb3f --- /dev/null +++ b/src/composables/usePopup.ts @@ -0,0 +1,98 @@ +import type { PopupParams, WebAppCallback } from '../sdk' +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { onPopupClosed } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, promisify, promisifyWithNoData } from '../utils' + +type Popup62 = ReturnType + +type PopupV60 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.2'>>]: Merge< + Partial, + { version: version } + >; +} + +type PopupV62toLatest = { + [version in BotApiVersionRange<'6.2', LATEST_VERSION>]: Merge< + PopupV60['6.0'], + { version: version } & Popup62 + >; +} + +type Popup = + & PopupV60 + & PopupV62toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function usePopup62() { + const { + webApp, + } = useStore() + + const showConfirmAsync = promisify(webApp.showConfirm) + + function showConfirm(message: string): ReturnType + function showConfirm(message: string, callback?: WebAppCallback['showConfirm']): void + function showConfirm(message: string, callback?: WebAppCallback['showConfirm']): ReturnType | void { + if (callback) + webApp.showConfirm(message, callback) + else + return showConfirmAsync(message) + } + + const showAlertAsync = promisifyWithNoData(webApp.showAlert) + + function showAlert(message: string): ReturnType + function showAlert(message: string, callback?: WebAppCallback['showAlert']): void + function showAlert(message: string, callback?: WebAppCallback['showAlert']): ReturnType | void { + if (callback) + webApp.showAlert(message, callback) + else + return showAlertAsync(message) + } + + const showPopupAsync = promisify(webApp.showPopup) + + function showPopup(params: PopupParams): ReturnType + function showPopup(params: PopupParams, callback?: WebAppCallback['showPopup']): void + function showPopup(params: PopupParams, callback?: WebAppCallback['showPopup']): ReturnType | void { + if (callback) + webApp.showPopup(params, callback) + else + return showPopupAsync(params) + } + + return { + showConfirm, + showAlert, + showPopup, + onClose: onPopupClosed, + } +} + +export function usePopup(options?: { version?: Version }) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '6.2') + ? usePopup62() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useQrScanner.ts b/src/composables/useQrScanner.ts new file mode 100644 index 0000000..e92c097 --- /dev/null +++ b/src/composables/useQrScanner.ts @@ -0,0 +1,73 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { onQrTextReceived, onScanQrPopupClosed } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual } from '../utils' + +type QrScannerV64 = ReturnType +type QrScannerV77 = ReturnType + +type QrScannerV60to64 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.4'>>]: Merge< + & Partial, + { version: version } + >; +} + +type QrScannerV64to77 = { + [version in BotApiVersionRange<'6.4', BotApiPrevVersion<'7.7'>>]: Merge< + QrScannerV60to64['6.0'], + { version: version } & QrScannerV64 + >; +} +type QrScannerV77toLatest = { + [version in BotApiVersionRange<'7.7', LATEST_VERSION>]: Merge< + QrScannerV64to77['6.4'], + { version: version } & QrScannerV77 + >; +} + +type QrScanner = + & QrScannerV60to64 + & QrScannerV64to77 + & QrScannerV77toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + + return { + webApp, + } +}) + +function useQrScanner64() { + const { + webApp, + } = useStore() + + return { + show: webApp.showScanQrPopup, + close: webApp.closeScanQrPopup, + onScan: onQrTextReceived, + } +} + +function useQrScanner77() { + return { + onClose: onScanQrPopupClosed, + } +} + +export function useQrScanner( + options?: { version?: Version }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...(isVersionGreaterOrEqual(version, '6.4') && useQrScanner64()), + ...(isVersionGreaterOrEqual(version, '7.7') + ? useQrScanner77() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useSecondaryButton.ts b/src/composables/useSecondaryButton.ts new file mode 100644 index 0000000..5d1efb8 --- /dev/null +++ b/src/composables/useSecondaryButton.ts @@ -0,0 +1,233 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { computed, readonly, ref } from 'vue' +import { onSecondaryButtonClicked } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type SecondaryButtonV60 = ReturnType +type SecondaryButtonV710 = ReturnType + +type SecondaryButtonV60to710 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'7.10'>>]: Merge< + & Partial, + { version: version } & SecondaryButtonV60 + >; +} + +type SecondaryButtonV710toLatest = { + [version in BotApiVersionRange<'7.10', LATEST_VERSION>]: Merge< + SecondaryButtonV60to710['6.0'], + { version: version } & SecondaryButtonV710 + >; +} + +type SecondaryButton = + & SecondaryButtonV60to710 + & SecondaryButtonV710toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const text = ref(webApp.SecondaryButton.text) + const color = ref(webApp.SecondaryButton.color) + const textColor = ref(webApp.SecondaryButton.textColor) + const isVisible = ref(webApp.SecondaryButton.isVisible) + const isActive = ref(webApp.SecondaryButton.isActive) + const isProgressVisible = ref(webApp.SecondaryButton.isProgressVisible) + const hasShineEffect = ref(webApp.SecondaryButton.hasShineEffect) + const position = ref(webApp.SecondaryButton.position) + + const updateState = () => { + text.value = webApp.SecondaryButton.text + color.value = webApp.SecondaryButton.color + textColor.value = webApp.SecondaryButton.textColor + isVisible.value = webApp.SecondaryButton.isVisible + isActive.value = webApp.SecondaryButton.isActive + isProgressVisible.value = webApp.SecondaryButton.isProgressVisible + hasShineEffect.value = webApp.SecondaryButton.hasShineEffect + position.value = webApp.SecondaryButton.position + } + + return { + webApp, + updateState, + text, + color, + textColor, + isVisible, + isActive, + isProgressVisible, + hasShineEffect, + position, + } +}) + +function useSecondaryButton60() { + const { + text, + color, + textColor, + isVisible, + isActive, + isProgressVisible, + hasShineEffect, + position, + } = useStore() + + return { + text: readonly(text), + color: readonly(color), + textColor: readonly(textColor), + isVisible: readonly(isVisible), + isActive: readonly(isActive), + isProgressVisible: readonly(isProgressVisible), + hasShineEffect: readonly(hasShineEffect), + position: readonly(position), + } +} + +function useSecondaryButton710() { + const { + webApp, + text, + color, + textColor, + isVisible, + isActive, + isProgressVisible, + hasShineEffect, + position, + updateState, + } = useStore() + + const showProgress = wrapFunction(webApp.SecondaryButton.showProgress, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const hideProgress = wrapFunction(webApp.SecondaryButton.hideProgress, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const setParams = wrapFunction(webApp.SecondaryButton.setParams, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + + return { + text: computed({ + get() { + return text.value + }, + set(text) { + setParams({ text }) + }, + }), + color: computed({ + get() { + return color.value + }, + set(color) { + setParams({ color }) + }, + }), + textColor: computed({ + get() { + return textColor.value + }, + set(textColor) { + setParams({ text_color: textColor }) + }, + }), + isVisible: computed({ + get() { + return isVisible.value + }, + set(isVisible) { + setParams({ is_visible: isVisible }) + }, + }), + isActive: computed({ + get() { + return isActive.value + }, + set(isActive) { + setParams({ is_active: isActive }) + }, + }), + isProgressVisible: computed({ + get() { + return isProgressVisible.value + }, + set(isProgressVisible) { + if (isProgressVisible) + showProgress() + else + hideProgress() + }, + }), + hasShineEffect: computed({ + get() { + return hasShineEffect.value + }, + set(hasShineEffect) { + setParams({ has_shine_effect: hasShineEffect }) + }, + }), + position: computed({ + get() { + return position.value + }, + set(position) { + setParams({ position }) + }, + }), + show: wrapFunction(webApp.SecondaryButton.show, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + hide: wrapFunction(webApp.SecondaryButton.hide, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + enable: wrapFunction(webApp.SecondaryButton.enable, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + disable: wrapFunction(webApp.SecondaryButton.disable, { + hooks: { + after: updateState, + }, + omitReturn: true, + }), + showProgress, + hideProgress, + setParams, + onClick: onSecondaryButtonClicked, + } +} + +export function useSecondaryButton( + options?: { version?: Version }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useSecondaryButton60(), + ...(isVersionGreaterOrEqual(version, '7.10') + ? useSecondaryButton710() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useSettingsButton.ts b/src/composables/useSettingsButton.ts new file mode 100644 index 0000000..21d9729 --- /dev/null +++ b/src/composables/useSettingsButton.ts @@ -0,0 +1,111 @@ +import type { + BotApiPrevVersion, + BotApiVersion, + BotApiVersionRange, + LATEST_VERSION, + Merge, + VersionedReturnType, +} from '../types' +import { computed, readonly, ref } from 'vue' +import { onSettingsButtonClicked } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type SettingsButtonV60 = ReturnType +type SettingsButtonV70 = ReturnType + +type SettingsButtonV60to70 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'7.0'>>]: Merge< + & Partial, + { version: version } & SettingsButtonV60 + >; +} + +type SettingsButtonV70toLatest = { + [version in BotApiVersionRange<'7.0', LATEST_VERSION>]: Merge< + SettingsButtonV60to70['6.0'], + { version: version } & SettingsButtonV70 + >; +} + +type SettingsButton = + & SettingsButtonV60to70 + & SettingsButtonV70toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const isVisible = ref(webApp.SettingsButton.isVisible) + + const updateState = () => { + isVisible.value = webApp.SettingsButton.isVisible + } + + return { + webApp, + isVisible, + updateState, + } +}) + +function useSettingsButton60() { + const { + isVisible, + } = useStore() + + return { + isVisible: readonly(isVisible), + } +} + +function useSettingsButton70() { + const { + webApp, + isVisible, + updateState, + } = useStore() + + const show = wrapFunction(webApp.SettingsButton.show, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + const hide = wrapFunction(webApp.SettingsButton.hide, { + hooks: { + after: updateState, + }, + omitReturn: true, + }) + + return { + isVisible: computed({ + get() { + return isVisible.value + }, + set(isVisible) { + if (isVisible) + show() + else + hide() + }, + }), + show, + hide, + onClick: onSettingsButtonClicked, + } +} + +export function useSettingsButton( + options?: { version?: Version }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useSettingsButton60(), + ...(isVersionGreaterOrEqual(version, '7.0') + ? useSettingsButton70() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useTheme.ts b/src/composables/useTheme.ts new file mode 100644 index 0000000..91f8fd6 --- /dev/null +++ b/src/composables/useTheme.ts @@ -0,0 +1,166 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { computed, readonly, ref } from 'vue' +import { onThemeChanged } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type ThemeV60 = ReturnType +type ThemeV61 = ReturnType +type ThemeV710 = ReturnType + +type ThemeV60to61 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'6.1'>>]: Merge< + Partial & Partial, + { version: version } & ThemeV60 + >; +} + +type ThemeV61to710 = { + [version in BotApiVersionRange<'6.1', BotApiPrevVersion<'7.10'>>]: Merge< + ThemeV60to61['6.0'], + { version: version } & ThemeV61 + >; +} + +type ThemeV710toLatest = { + [version in BotApiVersionRange<'7.10', LATEST_VERSION>]: Merge< + ThemeV61to710['6.1'], + { version: version } & ThemeV710 + >; +} + +type Theme = + & ThemeV60to61 + & ThemeV61to710 + & ThemeV710toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const colorScheme = ref(webApp.colorScheme) + const themeParams = ref(webApp.themeParams) + const headerColor = ref(webApp.headerColor) + const backgroundColor = ref(webApp.backgroundColor) + const bottomBarColor = ref(webApp.bottomBarColor) + + const updateState = () => { + colorScheme.value = webApp.colorScheme + themeParams.value = { + ...webApp.themeParams, + } + headerColor.value = webApp.headerColor + backgroundColor.value = webApp.backgroundColor + bottomBarColor.value = webApp.bottomBarColor + } + + return { + webApp, + updateState, + colorScheme, + themeParams, + headerColor, + backgroundColor, + bottomBarColor, + } +}) + +function useTheme60() { + const { + colorScheme, + themeParams, + headerColor, + backgroundColor, + bottomBarColor, + updateState, + } = useStore() + + onThemeChanged(updateState) + + return { + colorScheme: readonly(colorScheme), + themeParams: readonly(themeParams), + headerColor: readonly(headerColor), + backgroundColor: readonly(backgroundColor), + bottomBarColor: readonly(bottomBarColor), + onChange: onThemeChanged, + } +} + +function useTheme61() { + const { + webApp, + headerColor, + backgroundColor, + updateState, + } = useStore() + + const setHeaderColor = wrapFunction(webApp.setHeaderColor, { + hooks: { + after: updateState, + }, + }) + const setBackgroundColor = wrapFunction(webApp.setBackgroundColor, { + hooks: { + after: updateState, + }, + }) + + return { + headerColor: computed({ + get() { + return headerColor.value + }, + set(newColor: Parameters[0]) { + setHeaderColor(newColor) + }, + }), + backgroundColor: computed({ + get() { + return backgroundColor.value + }, + set(newColor: Parameters[0]) { + setBackgroundColor(newColor) + }, + }), + } +} + +function useTheme710() { + const { + webApp, + bottomBarColor, + updateState, + } = useStore() + + const setBottomBarColor = wrapFunction(webApp.setBottomBarColor, { + hooks: { + after: updateState, + }, + }) + + return { + bottomBarColor: computed({ + get() { + return bottomBarColor.value + }, + set(newColor: Parameters[0]) { + setBottomBarColor(newColor) + }, + }), + } +} + +export function useTheme( + options?: { version?: Version }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useTheme60(), + ...(isVersionGreaterOrEqual(version, '6.1') && useTheme61()), + ...(isVersionGreaterOrEqual(version, '7.10') + ? useTheme710() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useViewport.ts b/src/composables/useViewport.ts new file mode 100644 index 0000000..7b22f42 --- /dev/null +++ b/src/composables/useViewport.ts @@ -0,0 +1,218 @@ +import type { BotApiPrevVersion, BotApiVersion, BotApiVersionRange, LATEST_VERSION, Merge, VersionedReturnType } from '../types' +import { computed, readonly, ref } from 'vue' +import { onContentSafeAreaChanged, onFullscreenChanged, onFullscreenFailed, onSafeAreaChanged, onViewportChanged } from '../events' +import { getWebApp } from '../sdk' +import { defineStore, isVersionGreaterOrEqual, wrapFunction } from '../utils' + +type ViewportV60 = ReturnType +type ViewportV77 = ReturnType +type ViewportV80 = ReturnType + +type ViewportV60to77 = { + [version in BotApiVersionRange<'6.0', BotApiPrevVersion<'7.7'>>]: Merge< + & Partial + & Partial, + { version: version } & ViewportV60 + >; +} + +type ViewportV77to80 = { + [version in BotApiVersionRange<'7.7', BotApiPrevVersion<'8.0'>>]: Merge< + ViewportV60to77['6.0'], + { version: version } & ViewportV77 + >; +} + +type ViewportV80toLatest = { + [version in BotApiVersionRange<'8.0', LATEST_VERSION>]: Merge< + ViewportV77to80['7.7'], + { version: version } & ViewportV80 + >; +} + +type Viewport = + & ViewportV60to77 + & ViewportV77to80 + & ViewportV80toLatest + +const useStore = defineStore(() => { + const webApp = getWebApp() + const isExpanded = ref(webApp.isExpanded) + const viewportHeight = ref(webApp.viewportHeight) + const viewportStableHeight = ref(webApp.viewportStableHeight) + const isFullscreen = ref(webApp.isFullscreen) + const isOrientationLocked = ref(webApp.isOrientationLocked) + const isVerticalSwipesEnabled = ref(webApp.isVerticalSwipesEnabled) + const safeAreaInset = ref(webApp.safeAreaInset) + const contentSafeAreaInset = ref(webApp.contentSafeAreaInset) + + const updateState = () => { + isExpanded.value = webApp.isExpanded + viewportHeight.value = webApp.viewportHeight + viewportStableHeight.value = webApp.viewportStableHeight + isFullscreen.value = webApp.isFullscreen + isOrientationLocked.value = webApp.isOrientationLocked + isVerticalSwipesEnabled.value = webApp.isVerticalSwipesEnabled + safeAreaInset.value = { + ...webApp.safeAreaInset, + } + contentSafeAreaInset.value = { + ...webApp.contentSafeAreaInset, + } + } + + return { + webApp, + updateState, + isExpanded, + viewportHeight, + viewportStableHeight, + isFullscreen, + isOrientationLocked, + isVerticalSwipesEnabled, + safeAreaInset, + contentSafeAreaInset, + } +}) + +function useViewport60() { + const { + webApp, + updateState, + isExpanded, + viewportHeight, + viewportStableHeight, + isFullscreen, + isOrientationLocked, + isVerticalSwipesEnabled, + safeAreaInset, + contentSafeAreaInset, + } = useStore() + + onViewportChanged(updateState) + + return { + expand: wrapFunction(webApp.expand, { + hooks: { + after: updateState, + }, + }), + isExpanded: readonly(isExpanded), + viewportHeight: readonly(viewportHeight), + viewportStableHeight: readonly(viewportStableHeight), + isFullscreen: readonly(isFullscreen), + isOrientationLocked: readonly(isOrientationLocked), + isVerticalSwipesEnabled: readonly(isVerticalSwipesEnabled), + safeAreaInset: readonly(safeAreaInset), + contentSafeAreaInset: readonly(contentSafeAreaInset), + onChange: onViewportChanged, + } +} + +function useViewport77() { + const { + webApp, + isVerticalSwipesEnabled, + updateState, + } = useStore() + + const enableVerticalSwipes = wrapFunction(webApp.enableVerticalSwipes, { + hooks: { + after: updateState, + }, + }) + const disableVerticalSwipes = wrapFunction(webApp.disableVerticalSwipes, { + hooks: { + after: updateState, + }, + }) + + return { + isVerticalSwipesEnabled: computed({ + get() { + return isVerticalSwipesEnabled.value + }, + set(isEnabled) { + if (isEnabled) + enableVerticalSwipes() + else + disableVerticalSwipes() + }, + }), + } +} + +function useViewport80() { + const { + webApp, + isFullscreen, + isOrientationLocked, + updateState, + } = useStore() + + const requestFullscreen = wrapFunction(webApp.requestFullscreen, { + hooks: { + after: updateState, + }, + }) + const exitFullscreen = wrapFunction(webApp.exitFullscreen, { + hooks: { + after: updateState, + }, + }) + const lockOrientation = wrapFunction(webApp.lockOrientation, { + hooks: { + after: updateState, + }, + }) + const unlockOrientation = wrapFunction(webApp.unlockOrientation, { + hooks: { + after: updateState, + }, + }) + + return { + isFullscreen: computed({ + get() { + return isFullscreen.value + }, + set(isEnabled) { + if (isEnabled) + requestFullscreen() + else + exitFullscreen() + }, + }), + isOrientationLocked: computed({ + get() { + return isOrientationLocked.value + }, + set(isEnabled) { + if (isEnabled) + lockOrientation() + else + unlockOrientation() + }, + }), + onSafeAreaChange: onSafeAreaChanged, + onContentSafeAreaChange: onContentSafeAreaChanged, + onFullscreenChange: onFullscreenChanged, + onFullscreenFail: onFullscreenFailed, + } +} + +export function useViewport( + options?: { version?: Version }, +) { + const { webApp } = useStore() + const version = options?.version ?? webApp.version + + return { + version: webApp.version, + ...useViewport60(), + ...(isVersionGreaterOrEqual(version, '7.7') && useViewport77()), + ...(isVersionGreaterOrEqual(version, '8.0') + ? useViewport80() + : { isVersionAtLeast: webApp.isVersionAtLeast }), + } as VersionedReturnType +} diff --git a/src/composables/useWebApp.ts b/src/composables/useWebApp.ts deleted file mode 100644 index f99cafc..0000000 --- a/src/composables/useWebApp.ts +++ /dev/null @@ -1,107 +0,0 @@ -import type { OnEventOptions, OnEventWithOptions } from '../types' -import { onMounted, onUnmounted, readonly, ref } from 'vue' - -const isReady = ref(false) - -const ready: typeof Telegram.WebApp.ready = (...params) => { - Telegram.WebApp.ready(...params) - isReady.value = true -} - -function isPlatform(name: - | (string & Record) - | 'unknown' - | 'android' - | 'android_x' - | 'ios' - | 'macos' - | 'tdesktop' - | 'weba' - | 'webk' - | 'unigram') { - return Telegram.WebApp.platform === name -} - -const featureSupportVersion = { - ClosingConfirmation: '6.2', - CloudStorage: '6.9', - RequestWriteAccess: '6.9', - RequestContact: '6.9', - SettingsButton: '7.0', - BiometricManager: '7.2', - DisableVerticalSwipes: '7.7', -} -function isFeatureSupported(name: keyof typeof featureSupportVersion) { - return Telegram.WebApp.isVersionAtLeast(featureSupportVersion[name]) -} - -export function useWebApp() { - const onEvent: OnEventWithOptions = ( - eventType, - eventHandler, - options = { manual: false }, - ) => { - const { manual } = options - - const on = () => { - Telegram.WebApp.onEvent( - ...([eventType, eventHandler] as Parameters< - typeof Telegram.WebApp.onEvent - >), - ) - } - const off = () => { - Telegram.WebApp.offEvent( - ...([eventType, eventHandler] as Parameters< - typeof Telegram.WebApp.offEvent - >), - ) - } - - if (manual) { - on() - } - else { - onMounted(on) - onUnmounted(off) - } - - return { - off, - } - } - - const { - initData, - initDataUnsafe, - version, - platform, - isVersionAtLeast, - sendData, - close, - } = Telegram.WebApp - - const isPlatformUnknown = isPlatform('unknown') - - const canSendData = !isPlatformUnknown && initData === '' - - return { - initData, - initDataUnsafe, - version, - platform, - isVersionAtLeast, - onEvent, - sendData, - ready, - close, - isReady: readonly(isReady), - isPlatform, - isPlatformUnknown, - isFeatureSupported, - /** - * @deprecated - */ - canSendData, - } -} diff --git a/src/composables/useWebAppBackButton.ts b/src/composables/useWebAppBackButton.ts deleted file mode 100644 index 7276ea8..0000000 --- a/src/composables/useWebAppBackButton.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { OnEventOptions } from '../types' -import { computed, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const isBackButtonVisible = ref(Telegram.WebApp.BackButton.isVisible) - - function updateState() { - isBackButtonVisible.value = Telegram.WebApp.BackButton.isVisible - } - - function showBackButton( - ...params: Parameters - ) { - Telegram.WebApp.BackButton.show(...params) - updateState() - } - - function hideBackButton( - ...params: Parameters - ) { - Telegram.WebApp.BackButton.hide(...params) - updateState() - } - - return { isBackButtonVisible, showBackButton, hideBackButton } -}) - -export function useWebAppBackButton() { - const { isBackButtonVisible, showBackButton, hideBackButton } = useStore() - - const { onEvent } = useWebApp() - - const onBackButtonClicked = ( - eventHandler: BackButtonClickedCallback, - options?: OnEventOptions, - ) => onEvent('backButtonClicked', eventHandler, options) - - return { - isBackButtonVisible: computed({ - get() { - return isBackButtonVisible.value - }, - set(isVisible) { - isVisible ? showBackButton() : hideBackButton() - }, - }), - onBackButtonClicked, - showBackButton, - hideBackButton, - } -} diff --git a/src/composables/useWebAppBiometricManager.ts b/src/composables/useWebAppBiometricManager.ts deleted file mode 100644 index d3f8fa8..0000000 --- a/src/composables/useWebAppBiometricManager.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { OnEventOptions } from '../types' -import { readonly, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const isBiometricInited = ref(Telegram.WebApp.BiometricManager.isInited) - const isBiometricAvailable = ref( - Telegram.WebApp.BiometricManager.isBiometricAvailable, - ) - const biometricType = ref(Telegram.WebApp.BiometricManager.biometricType) - const isBiometricAccessRequested = ref( - Telegram.WebApp.BiometricManager.isAccessRequested, - ) - const isBiometricAccessGranted = ref( - Telegram.WebApp.BiometricManager.isAccessGranted, - ) - const isBiometricTokenSaved = ref( - Telegram.WebApp.BiometricManager.isAccessGranted, - ) - const biometricDeviceId = ref(Telegram.WebApp.BiometricManager.deviceId) - - function updateState() { - isBiometricInited.value = Telegram.WebApp.BiometricManager.isInited - isBiometricAvailable.value - = Telegram.WebApp.BiometricManager.isBiometricAvailable - biometricType.value = Telegram.WebApp.BiometricManager.biometricType - isBiometricAccessRequested.value - = Telegram.WebApp.BiometricManager.isAccessRequested - isBiometricAccessGranted.value - = Telegram.WebApp.BiometricManager.isAccessGranted - biometricDeviceId.value = Telegram.WebApp.BiometricManager.deviceId - isBiometricTokenSaved.value - = Telegram.WebApp.BiometricManager.isBiometricTokenSaved - } - - return { - isBiometricInited, - isBiometricAvailable, - biometricType, - isBiometricAccessRequested, - isBiometricAccessGranted, - biometricDeviceId, - isBiometricTokenSaved, - updateState, - } -}) - -export function useWebAppBiometricManager() { - const { - isBiometricInited, - isBiometricAvailable, - biometricType, - isBiometricAccessRequested, - isBiometricAccessGranted, - biometricDeviceId, - isBiometricTokenSaved, - updateState, - } = useStore() - - const { onEvent } = useWebApp() - - const onBiometricManagerUpdated = ( - eventHandler: () => void, - options?: OnEventOptions, - ) => onEvent('biometricManagerUpdated', eventHandler, options) - const onBiometricAuthRequested = ( - eventHandler: BiometricAuthRequestedCallback, - options?: OnEventOptions, - ) => onEvent('biometricAuthRequested', eventHandler, options) - const onBiometricTokenUpdated = ( - eventHandler: BiometricTokenUpdatedCallback, - options?: OnEventOptions, - ) => onEvent('biometricTokenUpdated', eventHandler, options) - - onBiometricManagerUpdated(updateState) - - const { - init, - requestAccess, - authenticate, - updateBiometricToken, - openSettings, - } = Telegram.WebApp.BiometricManager - - return { - isBiometricInited: readonly(isBiometricInited), - isBiometricAvailable: readonly(isBiometricAvailable), - biometricType: readonly(biometricType), - isBiometricAccessRequested: readonly(isBiometricAccessRequested), - isBiometricAccessGranted: readonly(isBiometricAccessGranted), - isBiometricTokenSaved: readonly(isBiometricTokenSaved), - biometricDeviceId: readonly(biometricDeviceId), - initBiometric: init, - requestBiometricAccess: requestAccess, - authenticateBiometric: authenticate, - updateBiometricToken, - openBiometricSettings: openSettings, - onBiometricManagerUpdated, - onBiometricAuthRequested, - onBiometricTokenUpdated, - } -} diff --git a/src/composables/useWebAppClipboard.ts b/src/composables/useWebAppClipboard.ts deleted file mode 100644 index bf47555..0000000 --- a/src/composables/useWebAppClipboard.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' - -export function useWebAppClipboard() { - const { onEvent } = useWebApp() - - const onClipboardTextReceived = ( - eventHandler: ClipboardTextReceivedCallback, - options?: OnEventOptions, - ) => onEvent('clipboardTextReceived', eventHandler, options) - - const { readTextFromClipboard } = Telegram.WebApp - - return { - readTextFromClipboard, - onClipboardTextReceived, - } -} diff --git a/src/composables/useWebAppClosingConfirmation.ts b/src/composables/useWebAppClosingConfirmation.ts deleted file mode 100644 index 567f730..0000000 --- a/src/composables/useWebAppClosingConfirmation.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { computed, ref } from 'vue' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isClosingConfirmationEnabled = ref( - Telegram.WebApp.isClosingConfirmationEnabled, - ) - - function updateStatus() { - isClosingConfirmationEnabled.value - = Telegram.WebApp.isClosingConfirmationEnabled - } - - function enableClosingConfirmation( - ...params: Parameters - ) { - Telegram.WebApp.enableClosingConfirmation(...params) - updateStatus() - } - - function disableClosingConfirmation( - ...params: Parameters - ) { - Telegram.WebApp.disableClosingConfirmation(...params) - updateStatus() - } - - return { - isClosingConfirmationEnabled, - updateStatus, - enableClosingConfirmation, - disableClosingConfirmation, - } -}) - -export function useWebAppClosingConfirmation() { - const { - isClosingConfirmationEnabled, - enableClosingConfirmation, - disableClosingConfirmation, - } = useStore() - - return { - isClosingConfirmationEnabled: computed({ - get() { - return isClosingConfirmationEnabled.value - }, - set(isEnabled) { - isEnabled ? enableClosingConfirmation() : disableClosingConfirmation() - }, - }), - enableClosingConfirmation, - disableClosingConfirmation, - } -} diff --git a/src/composables/useWebAppCloudStorage.ts b/src/composables/useWebAppCloudStorage.ts deleted file mode 100644 index 5e8fad8..0000000 --- a/src/composables/useWebAppCloudStorage.ts +++ /dev/null @@ -1,116 +0,0 @@ -type SetItemResult = Parameters< - NonNullable< - NonNullable>[2] - > ->[1] - -function setStorageItem(key: string, value: string) { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.setItem(key, value, (error, ok) => { - if (error) - reject(error) - - resolve(ok) - }) - }) -} - -type GetItemResult = Parameters< - NonNullable< - NonNullable>[1] - > ->[1] - -function getStorageItem(key: string) { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.getItem(key, (error, value) => { - if (error) - reject(error) - - resolve(value) - }) - }) -} - -type GetItemsResult = NonNullable< - Parameters< - NonNullable< - NonNullable>[1] - > - >[1] -> - -function getStorageItems(keys: string[]) { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.getItems(keys, (error, values) => { - if (error) - reject(error) - - resolve(values as GetItemsResult) - }) - }) -} - -type RemoveItemResult = Parameters< - NonNullable< - NonNullable>[1] - > ->[1] - -function removeStorageItem(key: string) { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.removeItem(key, (error, ok) => { - if (error) - reject(error) - - resolve(ok) - }) - }) -} - -type RemoveItemsResult = Parameters< - NonNullable< - NonNullable>[1] - > ->[1] - -function removeStorageItems(keys: string[]) { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.removeItems(keys, (error, ok) => { - if (error) - reject(error) - - resolve(ok) - }) - }) -} - -type GetKeysResult = NonNullable< - Parameters< - NonNullable< - NonNullable>[0] - > - >[1] -> - -function getStorageKeys() { - return new Promise((resolve, reject) => { - Telegram.WebApp.CloudStorage.getKeys((error, values) => { - if (error) - reject(error) - - resolve(values as GetKeysResult) - }) - }) -} - -export function useWebAppCloudStorage() { - return { - setStorageItem, - getStorageItem, - getStorageItems, - removeStorageItem, - removeStorageItems, - getStorageKeys, - } -} diff --git a/src/composables/useWebAppHapticFeedback.ts b/src/composables/useWebAppHapticFeedback.ts deleted file mode 100644 index 81b7106..0000000 --- a/src/composables/useWebAppHapticFeedback.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function useWebAppHapticFeedback() { - const { impactOccurred, notificationOccurred, selectionChanged } - = Telegram.WebApp.HapticFeedback - - return { - impactOccurred, - notificationOccurred, - selectionChanged, - } -} diff --git a/src/composables/useWebAppMainButton.ts b/src/composables/useWebAppMainButton.ts deleted file mode 100644 index e5ee2ff..0000000 --- a/src/composables/useWebAppMainButton.ts +++ /dev/null @@ -1,188 +0,0 @@ -import type { OnEventOptions } from '../types' -import { computed, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const mainButtonText = ref(Telegram.WebApp.MainButton.text) - const mainButtonColor = ref(Telegram.WebApp.MainButton.color) - const mainButtonTextColor = ref(Telegram.WebApp.MainButton.textColor) - const isMainButtonVisible = ref(Telegram.WebApp.MainButton.isVisible) - const isMainButtonActive = ref(Telegram.WebApp.MainButton.isActive) - const isMainButtonProgressVisible = ref( - Telegram.WebApp.MainButton.isProgressVisible, - ) - - function updateState() { - mainButtonText.value = Telegram.WebApp.MainButton.text - mainButtonColor.value = Telegram.WebApp.MainButton.color - mainButtonTextColor.value = Telegram.WebApp.MainButton.textColor - isMainButtonVisible.value = Telegram.WebApp.MainButton.isVisible - isMainButtonActive.value = Telegram.WebApp.MainButton.isActive - isMainButtonProgressVisible.value - = Telegram.WebApp.MainButton.isProgressVisible - } - - function setMainButtonText( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.setText(...params) - updateState() - } - - function showMainButton( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.show(...params) - updateState() - } - - function hideMainButton( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.hide(...params) - updateState() - } - - function enableMainButton( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.enable(...params) - updateState() - } - - function disableMainButton( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.disable(...params) - updateState() - } - - function showMainButtonProgress( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.showProgress(...params) - updateState() - } - - function hideMainButtonProgress( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.hideProgress(...params) - updateState() - } - - function setMainButtonParams( - ...params: Parameters - ) { - Telegram.WebApp.MainButton.setParams(...params) - updateState() - } - - return { - mainButtonText, - mainButtonColor, - mainButtonTextColor, - isMainButtonVisible, - isMainButtonActive, - isMainButtonProgressVisible, - setMainButtonText, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, - } -}) - -export function useWebAppMainButton() { - const { - mainButtonText, - mainButtonColor, - mainButtonTextColor, - isMainButtonVisible, - isMainButtonActive, - isMainButtonProgressVisible, - setMainButtonText, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, - } = useStore() - - const { onEvent } = useWebApp() - - const onMainButtonClicked = ( - eventHandler: MainButtonClickedCallback, - options?: OnEventOptions, - ) => onEvent('mainButtonClicked', eventHandler, options) - - return { - mainButtonText: computed({ - get() { - return mainButtonText.value - }, - set(text) { - setMainButtonText(text) - }, - }), - mainButtonColor: computed({ - get() { - return mainButtonColor.value - }, - set(color) { - setMainButtonParams({ - color, - }) - }, - }), - mainButtonTextColor: computed({ - get() { - return mainButtonTextColor.value - }, - set(color) { - setMainButtonParams({ - text_color: color, - }) - }, - }), - isMainButtonVisible: computed({ - get() { - return isMainButtonVisible.value - }, - set(isVisible) { - isVisible ? showMainButton() : hideMainButton() - }, - }), - isMainButtonActive: computed({ - get() { - return isMainButtonActive.value - }, - set(isActive) { - isActive ? enableMainButton() : disableMainButton() - }, - }), - isMainButtonProgressVisible: computed({ - get() { - return isMainButtonProgressVisible.value - }, - set(isProgressVisible) { - isProgressVisible ? showMainButtonProgress() : hideMainButtonProgress() - }, - }), - setMainButtonText, - onMainButtonClicked, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, - } -} diff --git a/src/composables/useWebAppNavigation.ts b/src/composables/useWebAppNavigation.ts deleted file mode 100644 index e818db3..0000000 --- a/src/composables/useWebAppNavigation.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' - -export function useWebAppNavigation() { - const { onEvent } = useWebApp() - - const onInvoiceClosed = ( - eventHandler: InvoiceClosedCallback, - options?: OnEventOptions, - ) => onEvent('invoiceClosed', eventHandler, options) - - const { switchInlineQuery, openLink, openTelegramLink, openInvoice } - = Telegram.WebApp - - return { - switchInlineQuery, - openLink, - openTelegramLink, - openInvoice, - onInvoiceClosed, - } -} diff --git a/src/composables/useWebAppPopup.ts b/src/composables/useWebAppPopup.ts deleted file mode 100644 index 35bf63d..0000000 --- a/src/composables/useWebAppPopup.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' - -export function useWebAppPopup() { - const { onEvent } = useWebApp() - - const onPopupClosed = ( - eventHandler: PopupClosedCallback, - options?: OnEventOptions, - ) => onEvent('popupClosed', eventHandler, options) - - const { showPopup, showAlert, showConfirm } = Telegram.WebApp - - return { - showPopup, - showAlert, - showConfirm, - onPopupClosed, - } -} diff --git a/src/composables/useWebAppQrScanner.ts b/src/composables/useWebAppQrScanner.ts deleted file mode 100644 index 91483c6..0000000 --- a/src/composables/useWebAppQrScanner.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' - -export function useWebAppQrScanner() { - const { onEvent } = useWebApp() - - const onQrTextReceived = ( - eventHandler: QrTextReceivedCallback, - options?: OnEventOptions, - ) => onEvent('qrTextReceived', eventHandler, options) - - const onScanQrPopupClosed = ( - eventHandler: ScanQrPopupClosedCallback, - options?: OnEventOptions, - ) => onEvent('scanQrPopupClosed', eventHandler, options) - - const { showScanQrPopup, closeScanQrPopup } = Telegram.WebApp - - return { - showScanQrPopup, - closeScanQrPopup, - onQrTextReceived, - onScanQrPopupClosed, - } -} diff --git a/src/composables/useWebAppRequests.ts b/src/composables/useWebAppRequests.ts deleted file mode 100644 index 1fb921d..0000000 --- a/src/composables/useWebAppRequests.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' - -export function useWebAppRequests() { - const { onEvent } = useWebApp() - - const onWriteAccessRequested = ( - eventHandler: WriteAccessRequestedCallback, - options?: OnEventOptions, - ) => onEvent('writeAccessRequested', eventHandler, options) - - const onContactRequested = ( - eventHandler: ContactRequestedCallback, - options?: OnEventOptions, - ) => onEvent('contactRequested', eventHandler, options) - - const { requestContact, requestWriteAccess } = Telegram.WebApp - - return { - requestContact, - onContactRequested, - requestWriteAccess, - onWriteAccessRequested, - } -} diff --git a/src/composables/useWebAppSettingsButton.ts b/src/composables/useWebAppSettingsButton.ts deleted file mode 100644 index 317c796..0000000 --- a/src/composables/useWebAppSettingsButton.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { OnEventOptions } from '../types' -import { computed, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const isSettingsButtonVisible = ref(Telegram.WebApp.SettingsButton.isVisible) - - function showSettingsButton( - ...params: Parameters - ) { - Telegram.WebApp.SettingsButton.show(...params) - isSettingsButtonVisible.value = true - } - - function hideSettingsButton( - ...params: Parameters - ) { - Telegram.WebApp.SettingsButton.hide(...params) - isSettingsButtonVisible.value = false - } - - return { - isSettingsButtonVisible, - showSettingsButton, - hideSettingsButton, - } -}) - -export function useWebAppSettingsButton() { - const { isSettingsButtonVisible, showSettingsButton, hideSettingsButton } - = useStore() - - const { onEvent } = useWebApp() - - const onSettingsButtonClicked = ( - eventHandler: SettingsButtonClickedCallback, - options?: OnEventOptions, - ) => onEvent('settingsButtonClicked', eventHandler, options) - - return { - isSettingsButtonVisible: computed({ - get() { - return isSettingsButtonVisible.value - }, - set(isVisible) { - isVisible ? showSettingsButton() : hideSettingsButton() - }, - }), - onSettingsButtonClicked, - showSettingsButton, - hideSettingsButton, - } -} diff --git a/src/composables/useWebAppShare.ts b/src/composables/useWebAppShare.ts deleted file mode 100644 index 7bca780..0000000 --- a/src/composables/useWebAppShare.ts +++ /dev/null @@ -1,19 +0,0 @@ -interface StoryWidgetLink { - url: string - name?: string -} - -interface StoryShareParams { - text?: string - widgetLink?: StoryWidgetLink -} - -function shareToStory(mediaUrl: string, params?: StoryShareParams) { - Telegram.WebApp.shareToStory(mediaUrl, params) -} - -export function useWebAppShare() { - return { - shareToStory, - } -} diff --git a/src/composables/useWebAppTheme.ts b/src/composables/useWebAppTheme.ts deleted file mode 100644 index 832a7ff..0000000 --- a/src/composables/useWebAppTheme.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { OnEventOptions } from '../types' -import { computed, readonly, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const colorScheme = ref(Telegram.WebApp.colorScheme) - const themeParams = ref(Telegram.WebApp.themeParams) - const headerColor = ref(Telegram.WebApp.headerColor) - const backgroundColor = ref(Telegram.WebApp.backgroundColor) - - function updateState() { - colorScheme.value = Telegram.WebApp.colorScheme - themeParams.value = { - ...Telegram.WebApp.themeParams, - } - headerColor.value = Telegram.WebApp.headerColor - backgroundColor.value = Telegram.WebApp.backgroundColor - } - - function setHeaderColor( - ...params: Parameters - ) { - Telegram.WebApp.setHeaderColor(...params) - updateState() - } - - function setBackgroundColor( - ...params: Parameters - ) { - Telegram.WebApp.setBackgroundColor(...params) - updateState() - } - - return { - colorScheme, - themeParams, - headerColor, - backgroundColor, - updateState, - setHeaderColor, - setBackgroundColor, - } -}) - -export function useWebAppTheme() { - const { - colorScheme, - themeParams, - headerColor, - backgroundColor, - updateState, - setHeaderColor, - setBackgroundColor, - } = useStore() - - const { onEvent } = useWebApp() - - const onThemeChanged = (eventHandler: () => void, options?: OnEventOptions) => - onEvent('themeChanged', eventHandler, options) - - onThemeChanged(updateState) - - return { - colorScheme: readonly(colorScheme), - themeParams: readonly(themeParams), - headerColor: computed({ - get() { - return headerColor.value - }, - set(newValue) { - setHeaderColor(newValue) - }, - }), - backgroundColor: computed({ - get() { - return backgroundColor.value - }, - set(newValue) { - setBackgroundColor(newValue) - }, - }), - setHeaderColor, - setBackgroundColor, - onThemeChanged, - } -} diff --git a/src/composables/useWebAppViewport.ts b/src/composables/useWebAppViewport.ts deleted file mode 100644 index 5c967a1..0000000 --- a/src/composables/useWebAppViewport.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { OnEventOptions } from '../types' -import { computed, readonly, ref } from 'vue' -import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' - -const useStore = defineStore(() => { - const isExpanded = ref(Telegram.WebApp.isExpanded) - const viewportHeight = ref(Telegram.WebApp.viewportHeight) - const viewportStableHeight = ref(Telegram.WebApp.viewportStableHeight) - const isVerticalSwipesEnabled = ref(Telegram.WebApp.isVerticalSwipesEnabled) - - function updateState() { - isExpanded.value = Telegram.WebApp.isExpanded - viewportHeight.value = Telegram.WebApp.viewportHeight - viewportStableHeight.value = Telegram.WebApp.viewportStableHeight - isVerticalSwipesEnabled.value = Telegram.WebApp.isVerticalSwipesEnabled - } - - function expand(...params: Parameters) { - Telegram.WebApp.expand(...params) - updateState() - } - - const enableVerticalSwipes: typeof Telegram.WebApp.enableVerticalSwipes = ( - ...params - ) => { - Telegram.WebApp.enableVerticalSwipes(...params) - updateState() - } - - const disableVerticalSwipes: typeof Telegram.WebApp.disableVerticalSwipes = ( - ...params - ) => { - Telegram.WebApp.disableVerticalSwipes(...params) - updateState() - } - - return { - isExpanded, - viewportHeight, - viewportStableHeight, - isVerticalSwipesEnabled, - updateState, - expand, - enableVerticalSwipes, - disableVerticalSwipes, - } -}) - -export function useWebAppViewport() { - const { - isExpanded, - viewportHeight, - viewportStableHeight, - isVerticalSwipesEnabled, - updateState, - expand, - enableVerticalSwipes, - disableVerticalSwipes, - } = useStore() - - const { onEvent } = useWebApp() - - const onViewportChanged = ( - eventHandler: ViewportChangedCallback, - options?: OnEventOptions, - ) => onEvent('viewportChanged', eventHandler, options) - - onViewportChanged(updateState) - - return { - isExpanded: readonly(isExpanded), - viewportHeight: readonly(viewportHeight), - viewportStableHeight: readonly(viewportStableHeight), - expand, - onViewportChanged, - isVerticalSwipesEnabled: computed({ - get() { - return isVerticalSwipesEnabled.value - }, - set(isEnabled) { - isEnabled ? enableVerticalSwipes() : disableVerticalSwipes() - }, - }), - enableVerticalSwipes, - disableVerticalSwipes, - } -} diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..fb56b30 --- /dev/null +++ b/src/events.ts @@ -0,0 +1,206 @@ +import type { EventCallback } from './sdk' +import type { OnEventOptions, OnEventWithOptions } from './types' +import { onMounted, onUnmounted } from 'vue' +import { getWebApp } from './sdk' + +export const onEvent: OnEventWithOptions = ( + eventType, + eventHandler, + options = { manual: false }, +) => { + const { manual } = options + const webApp = getWebApp() + + const on = () => + webApp.onEvent(eventType, eventHandler) + const off = () => + webApp.offEvent(eventType, eventHandler) + + if (manual) { + on() + } + else { + onMounted(on) + onUnmounted(off) + } + + return { + off, + } +} + +export function onActivated(eventHandler: EventCallback['activated'], options?: OnEventOptions) { + return onEvent('activated', eventHandler, options) +} + +export function onDeactivated(eventHandler: EventCallback['deactivated'], options?: OnEventOptions) { + return onEvent('deactivated', eventHandler, options) +} + +export function onThemeChanged(eventHandler: EventCallback['themeChanged'], options?: OnEventOptions) { + return onEvent('themeChanged', eventHandler, options) +} + +export function onViewportChanged(eventHandler: EventCallback['viewportChanged'], options?: OnEventOptions) { + return onEvent('viewportChanged', eventHandler, options) +} + +export function onSafeAreaChanged(eventHandler: EventCallback['safeAreaChanged'], options?: OnEventOptions) { + return onEvent('safeAreaChanged', eventHandler, options) +} + +export function onContentSafeAreaChanged(eventHandler: EventCallback['contentSafeAreaChanged'], options?: OnEventOptions) { + return onEvent('contentSafeAreaChanged', eventHandler, options) +} + +export function onMainButtonClicked(eventHandler: EventCallback['mainButtonClicked'], options?: OnEventOptions) { + return onEvent('mainButtonClicked', eventHandler, options) +} + +export function onSecondaryButtonClicked(eventHandler: EventCallback['secondaryButtonClicked'], options?: OnEventOptions) { + return onEvent('secondaryButtonClicked', eventHandler, options) +} + +export function onBackButtonClicked(eventHandler: EventCallback['backButtonClicked'], options?: OnEventOptions) { + return onEvent('backButtonClicked', eventHandler, options) +} + +export function onSettingsButtonClicked(eventHandler: EventCallback['settingsButtonClicked'], options?: OnEventOptions) { + return onEvent('settingsButtonClicked', eventHandler, options) +} + +export function onInvoiceClosed(eventHandler: EventCallback['invoiceClosed'], options?: OnEventOptions) { + return onEvent('invoiceClosed', eventHandler, options) +} + +export function onPopupClosed(eventHandler: EventCallback['popupClosed'], options?: OnEventOptions) { + return onEvent('popupClosed', eventHandler, options) +} + +export function onQrTextReceived(eventHandler: EventCallback['qrTextReceived'], options?: OnEventOptions) { + return onEvent('qrTextReceived', eventHandler, options) +} + +export function onScanQrPopupClosed(eventHandler: EventCallback['scanQrPopupClosed'], options?: OnEventOptions) { + return onEvent('scanQrPopupClosed', eventHandler, options) +} + +export function onClipboardTextReceived(eventHandler: EventCallback['clipboardTextReceived'], options?: OnEventOptions) { + return onEvent('clipboardTextReceived', eventHandler, options) +} + +export function onWriteAccessRequested(eventHandler: EventCallback['writeAccessRequested'], options?: OnEventOptions) { + return onEvent('writeAccessRequested', eventHandler, options) +} + +export function onContactRequested(eventHandler: EventCallback['contactRequested'], options?: OnEventOptions) { + return onEvent('contactRequested', eventHandler, options) +} + +export function onBiometricManagerUpdated(eventHandler: EventCallback['biometricManagerUpdated'], options?: OnEventOptions) { + return onEvent('biometricManagerUpdated', eventHandler, options) +} + +export function onBiometricAuthRequested(eventHandler: EventCallback['biometricAuthRequested'], options?: OnEventOptions) { + return onEvent('biometricAuthRequested', eventHandler, options) +} + +export function onBiometricTokenUpdated(eventHandler: EventCallback['biometricTokenUpdated'], options?: OnEventOptions) { + return onEvent('biometricTokenUpdated', eventHandler, options) +} + +export function onFullscreenChanged(eventHandler: EventCallback['fullscreenChanged'], options?: OnEventOptions) { + return onEvent('fullscreenChanged', eventHandler, options) +} + +export function onFullscreenFailed(eventHandler: EventCallback['fullscreenFailed'], options?: OnEventOptions) { + return onEvent('fullscreenFailed', eventHandler, options) +} + +export function onHomeScreenAdded(eventHandler: EventCallback['homeScreenAdded'], options?: OnEventOptions) { + return onEvent('homeScreenAdded', eventHandler, options) +} + +export function onHomeScreenChecked(eventHandler: EventCallback['homeScreenChecked'], options?: OnEventOptions) { + return onEvent('homeScreenChecked', eventHandler, options) +} + +export function onAccelerometerStarted(eventHandler: EventCallback['accelerometerStarted'], options?: OnEventOptions) { + return onEvent('accelerometerStarted', eventHandler, options) +} + +export function onAccelerometerStopped(eventHandler: EventCallback['accelerometerStopped'], options?: OnEventOptions) { + return onEvent('accelerometerStopped', eventHandler, options) +} + +export function onAccelerometerChanged(eventHandler: EventCallback['accelerometerChanged'], options?: OnEventOptions) { + return onEvent('accelerometerChanged', eventHandler, options) +} + +export function onAccelerometerFailed(eventHandler: EventCallback['accelerometerFailed'], options?: OnEventOptions) { + return onEvent('accelerometerFailed', eventHandler, options) +} + +export function onDeviceOrientationStarted(eventHandler: EventCallback['deviceOrientationStarted'], options?: OnEventOptions) { + return onEvent('deviceOrientationStarted', eventHandler, options) +} + +export function onDeviceOrientationStopped(eventHandler: EventCallback['deviceOrientationStopped'], options?: OnEventOptions) { + return onEvent('deviceOrientationStopped', eventHandler, options) +} + +export function onDeviceOrientationChanged(eventHandler: EventCallback['deviceOrientationChanged'], options?: OnEventOptions) { + return onEvent('deviceOrientationChanged', eventHandler, options) +} + +export function onDeviceOrientationFailed(eventHandler: EventCallback['deviceOrientationFailed'], options?: OnEventOptions) { + return onEvent('deviceOrientationFailed', eventHandler, options) +} + +export function onGyroscopeStarted(eventHandler: EventCallback['gyroscopeStarted'], options?: OnEventOptions) { + return onEvent('gyroscopeStarted', eventHandler, options) +} + +export function onGyroscopeStopped(eventHandler: EventCallback['gyroscopeStopped'], options?: OnEventOptions) { + return onEvent('gyroscopeStopped', eventHandler, options) +} + +export function onGyroscopeChanged(eventHandler: EventCallback['gyroscopeChanged'], options?: OnEventOptions) { + return onEvent('gyroscopeChanged', eventHandler, options) +} + +export function onGyroscopeFailed(eventHandler: EventCallback['gyroscopeFailed'], options?: OnEventOptions) { + return onEvent('gyroscopeFailed', eventHandler, options) +} + +export function onLocationManagerUpdated(eventHandler: EventCallback['locationManagerUpdated'], options?: OnEventOptions) { + return onEvent('locationManagerUpdated', eventHandler, options) +} + +export function onLocationRequested(eventHandler: EventCallback['locationRequested'], options?: OnEventOptions) { + return onEvent('locationRequested', eventHandler, options) +} + +export function onShareMessageSent(eventHandler: EventCallback['shareMessageSent'], options?: OnEventOptions) { + return onEvent('shareMessageSent', eventHandler, options) +} + +export function onShareMessageFailed(eventHandler: EventCallback['shareMessageFailed'], options?: OnEventOptions) { + return onEvent('shareMessageFailed', eventHandler, options) +} + +export function onEmojiStatusSet(eventHandler: EventCallback['emojiStatusSet'], options?: OnEventOptions) { + return onEvent('emojiStatusSet', eventHandler, options) +} + +export function onEmojiStatusFailed(eventHandler: EventCallback['emojiStatusFailed'], options?: OnEventOptions) { + return onEvent('emojiStatusFailed', eventHandler, options) +} + +export function onEmojiStatusAccessRequested(eventHandler: EventCallback['emojiStatusAccessRequested'], options?: OnEventOptions) { + return onEvent('emojiStatusAccessRequested', eventHandler, options) +} + +export function onFileDownloadRequested(eventHandler: EventCallback['fileDownloadRequested'], options?: OnEventOptions) { + return onEvent('fileDownloadRequested', eventHandler, options) +} diff --git a/src/index.ts b/src/index.ts index ffddaf6..288bab0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,12 +9,41 @@ import ExpandedViewport from './components/ExpandedViewport.vue' import MainButton from './components/MainButton.vue' import Popup from './components/Popup.vue' import ScanQr from './components/ScanQr.vue' +import SecondaryButton from './components/SecondaryButton.vue' import SettingsButton from './components/SettingsButton.vue' +import { createComposablesWithVersion } from './versions/helpers' import DiscussionWidget from './widgets/DiscussionWidget.vue' import LoginWidget from './widgets/LoginWidget.vue' import PostWidget from './widgets/PostWidget.vue' import ShareWidget from './widgets/ShareWidget.vue' +export * from './composables-legacy' +export { isVersionAtLeast } from './composables/useMiniApp' +export * from './events' +export type { LoginWidgetUser } from './types' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.0') + export { Alert, BackButton, @@ -28,30 +57,11 @@ export { Popup, PostWidget, ScanQr, + SecondaryButton, SettingsButton, ShareWidget, } -export { useWebApp } from './composables/useWebApp' - -export { useWebAppBackButton } from './composables/useWebAppBackButton' -export { useWebAppBiometricManager } from './composables/useWebAppBiometricManager' -export { useWebAppClipboard } from './composables/useWebAppClipboard' -export { useWebAppClosingConfirmation } from './composables/useWebAppClosingConfirmation' -export { useWebAppCloudStorage } from './composables/useWebAppCloudStorage' -export { useWebAppHapticFeedback } from './composables/useWebAppHapticFeedback' -export { useWebAppMainButton } from './composables/useWebAppMainButton' -export { useWebAppNavigation } from './composables/useWebAppNavigation' -export { useWebAppPopup } from './composables/useWebAppPopup' -export { useWebAppQrScanner } from './composables/useWebAppQrScanner' -export { useWebAppRequests } from './composables/useWebAppRequests' -export { useWebAppSendData } from './composables/useWebAppSendData' -export { useWebAppSettingsButton } from './composables/useWebAppSettingsButton' -export { useWebAppShare } from './composables/useWebAppShare' -export { useWebAppTheme } from './composables/useWebAppTheme' -export { useWebAppViewport } from './composables/useWebAppViewport' -export type { LoginWidgetUser } from './types' - const plugin = { install(Vue: App) { Vue.component('TgAlert', Alert) @@ -63,6 +73,7 @@ const plugin = { Vue.component('TgMainButton', MainButton) Vue.component('TgPopup', Popup) Vue.component('TgScanQr', ScanQr) + Vue.component('TgSecondaryButton', SecondaryButton) Vue.component('TgSettingsButton', SettingsButton) Vue.component('TgShareWidget', ShareWidget) Vue.component('TgPostWidget', PostWidget) @@ -82,6 +93,7 @@ declare module '@vue/runtime-core' { TgMainButton: typeof MainButton TgPopup: typeof Popup TgScanQr: typeof ScanQr + TgSecondaryButton: typeof SecondaryButton TgSettingsButton: typeof SettingsButton TgShareWidget: typeof ShareWidget TgPostWidget: typeof PostWidget diff --git a/src/sdk/accelerometer.ts b/src/sdk/accelerometer.ts new file mode 100644 index 0000000..7ad9e59 --- /dev/null +++ b/src/sdk/accelerometer.ts @@ -0,0 +1,20 @@ +export type Accelerometer = { + isStarted: boolean + x: number + y: number + z: number + start: ( + params: AccelerometerStartParams, + callback?: AccelerometerCallback['start'] + ) => Accelerometer + stop: (callback?: AccelerometerCallback['stop']) => Accelerometer +} + +export type AccelerometerStartParams = { + refresh_rate?: number +} + +export type AccelerometerCallback = { + start: (success: boolean) => void + stop: (success: boolean) => void +} diff --git a/src/sdk/back-button.ts b/src/sdk/back-button.ts new file mode 100644 index 0000000..c984b48 --- /dev/null +++ b/src/sdk/back-button.ts @@ -0,0 +1,9 @@ +import type { EventCallback } from './events' + +export type BackButton = { + isVisible: boolean + onClick: (callback: EventCallback['backButtonClicked']) => BackButton + offClick: (callback: EventCallback['backButtonClicked']) => BackButton + show: () => BackButton + hide: () => BackButton +} diff --git a/src/sdk/biometric-manager.ts b/src/sdk/biometric-manager.ts new file mode 100644 index 0000000..b64409b --- /dev/null +++ b/src/sdk/biometric-manager.ts @@ -0,0 +1,38 @@ +export type BiometricManager = { + isInited: boolean + isBiometricAvailable: boolean + biometricType: 'finger' | 'face' | 'unknown' + isAccessRequested: boolean + isAccessGranted: boolean + isBiometricTokenSaved: boolean + deviceId: string + init: (callback?: BiometricManagerCallback['init']) => BiometricManager + requestAccess: ( + params: BiometricRequestAccessParams, + callback?: BiometricManagerCallback['requestAccess'] + ) => BiometricManager + authenticate: ( + params: BiometricAuthenticateParams, + callback?: BiometricManagerCallback['authenticate'] + ) => BiometricManager + updateBiometricToken: ( + token: string, + callback?: BiometricManagerCallback['updateBiometricToken'] + ) => BiometricManager + openSettings: () => BiometricManager +} + +export type BiometricManagerCallback = { + init: () => void + requestAccess: (isGranted: boolean) => void + authenticate: (isAuthenticated: boolean, token?: string) => void + updateBiometricToken: (isUpdated: boolean) => void +} + +export type BiometricRequestAccessParams = { + reason?: string +} + +export type BiometricAuthenticateParams = { + reason?: string +} diff --git a/src/sdk/bottom-button.ts b/src/sdk/bottom-button.ts new file mode 100644 index 0000000..c5ce01f --- /dev/null +++ b/src/sdk/bottom-button.ts @@ -0,0 +1,31 @@ +import type { EventCallback } from './events' + +export type BottomButton = { + readonly type: 'main' | 'secondary' + text: string + color: string + textColor: string + isVisible: boolean + isActive: boolean + hasShineEffect: boolean + position?: 'left' | 'right' | 'top' | 'bottom' + readonly isProgressVisible: boolean + setText: (text: string) => BottomButton + onClick: (callback: EventCallback['mainButtonClicked']) => BottomButton + offClick: (callback: EventCallback['mainButtonClicked']) => BottomButton + show: () => BottomButton + hide: () => BottomButton + enable: () => BottomButton + disable: () => BottomButton + showProgress: (leaveActive?: boolean) => BottomButton + hideProgress: () => BottomButton + setParams: (params: { + text?: string + color?: string + text_color?: string + has_shine_effect?: boolean + position?: 'left' | 'right' | 'top' | 'bottom' + is_active?: boolean + is_visible?: boolean + }) => BottomButton +} diff --git a/src/sdk/cloud-storage.ts b/src/sdk/cloud-storage.ts new file mode 100644 index 0000000..50d2b63 --- /dev/null +++ b/src/sdk/cloud-storage.ts @@ -0,0 +1,17 @@ +export type CloudStorage = { + setItem: (key: string, value: string, callback?: CloudStorageCallback['setItem']) => CloudStorage + getItem: (key: string, callback: CloudStorageCallback['getItem']) => CloudStorage + getItems: (keys: string[], callback: CloudStorageCallback['getItems']) => CloudStorage + removeItem: (key: string, callback?: CloudStorageCallback['removeItem']) => CloudStorage + removeItems: (keys: string[], callback?: CloudStorageCallback['removeItems']) => CloudStorage + getKeys: (callback: CloudStorageCallback['getKeys']) => CloudStorage +} + +export type CloudStorageCallback = { + setItem: (error: string | null, success: null | true) => void + getItem: (error: string | null, value: null | string) => void + getItems: (error: string | null, values: null | Record) => void + removeItem: (error: string | null, success: null | true) => void + removeItems: (error: string | null, success: null | true) => void + getKeys: (error: string | null, keys: null | string[]) => void +} diff --git a/src/sdk/device-orientation.ts b/src/sdk/device-orientation.ts new file mode 100644 index 0000000..69300e2 --- /dev/null +++ b/src/sdk/device-orientation.ts @@ -0,0 +1,22 @@ +export type DeviceOrientation = { + isStarted: boolean + absolute: boolean + alpha: number + beta: number + gamma: number + start: ( + params: DeviceOrientationStartParams, + callback?: DeviceOrientationCallback['start'] + ) => DeviceOrientation + stop: (callback?: DeviceOrientationCallback['stop']) => DeviceOrientation +} + +export type DeviceOrientationCallback = { + start: (success: boolean) => void + stop: (success: boolean) => void +} + +export type DeviceOrientationStartParams = { + refresh_rate?: number + need_absolute?: boolean +} diff --git a/src/sdk/events.ts b/src/sdk/events.ts new file mode 100644 index 0000000..2fedd70 --- /dev/null +++ b/src/sdk/events.ts @@ -0,0 +1,93 @@ +import type { LocationData } from './location-manager' + +type RequestContactResponseSent = { + status: 'sent' + response: string + responseUnsafe: { + auth_date: string + contact: { + first_name: string + last_name?: string + phone_number: string + user_id: number + } + hash: string + } +} + +type RequestContactResponseCancelled = { + status: 'cancelled' +} + +export type EventData = { + viewportChanged: { isStateStable: boolean } + invoiceClosed: { url: string, status: 'paid' | 'cancelled' | 'failed' | 'pending' } + popupClosed: { button_id: string | null } + qrTextReceived: { data: string } + clipboardTextReceived: { data: string | null } + writeAccessRequested: { status: 'allowed' | 'cancelled' } + contactRequested: RequestContactResponseSent | RequestContactResponseCancelled + biometricAuthRequested: { isAuthenticated: boolean, biometricToken?: string } + biometricTokenUpdated: { isUpdated: boolean } + fullscreenFailed: { error: 'UNSUPPORTED' | 'ALREADY_FULLSCREEN' } + homeScreenChecked: { status: 'unsupported' | 'unknown' | 'added' | 'missed' } + accelerometerFailed: { error: 'UNSUPPORTED' } + deviceOrientationFailed: { error: 'UNSUPPORTED' } + gyroscopeFailed: { error: 'UNSUPPORTED' } + locationRequested: { locationData: LocationData } + shareMessageFailed: { error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' | 'USER_DECLINED' | 'UNKNOWN_ERROR' } + emojiStatusFailed: { error: 'UNSUPPORTED' | 'SUGGESTED_EMOJI_INVALID' | 'DURATION_INVALID' | 'USER_DECLINED' | 'SERVER_ERROR' | 'UNKNOWN_ERROR' } + emojiStatusAccessRequested: { status: 'allowed' | 'cancelled' } + fileDownloadRequested: { status: 'downloading' | 'cancelled' } +} + +export type EventCallback = { + activated: () => void + deactivated: () => void + themeChanged: () => void + viewportChanged: (eventData: EventData['viewportChanged']) => void + safeAreaChanged: () => void + contentSafeAreaChanged: () => void + mainButtonClicked: () => void + secondaryButtonClicked: () => void + backButtonClicked: () => void + settingsButtonClicked: () => void + invoiceClosed: (eventData: EventData['invoiceClosed']) => void + popupClosed: (eventData: EventData['popupClosed']) => void + qrTextReceived: (eventData: EventData['qrTextReceived']) => void + scanQrPopupClosed: () => void + clipboardTextReceived: (eventData: EventData['clipboardTextReceived']) => void + writeAccessRequested: (eventData: EventData['writeAccessRequested']) => void + contactRequested: (eventData: EventData['contactRequested']) => void + biometricManagerUpdated: () => void + biometricAuthRequested: (eventData: EventData['biometricAuthRequested']) => void + biometricTokenUpdated: (eventData: EventData['biometricTokenUpdated']) => void + fullscreenChanged: () => void + fullscreenFailed: (event: EventData['fullscreenFailed']) => void + homeScreenAdded: () => void + homeScreenChecked: (event: EventData['homeScreenChecked']) => void + accelerometerStarted: () => void + accelerometerStopped: () => void + accelerometerChanged: () => void + accelerometerFailed: (event: EventData['accelerometerFailed']) => void + deviceOrientationStarted: () => void + deviceOrientationStopped: () => void + deviceOrientationChanged: () => void + deviceOrientationFailed: (event: EventData['deviceOrientationFailed']) => void + gyroscopeStarted: () => void + gyroscopeStopped: () => void + gyroscopeChanged: () => void + gyroscopeFailed: (event: EventData['gyroscopeFailed']) => void + locationManagerUpdated: () => void + locationRequested: (event: EventData['locationRequested']) => void + shareMessageSent: () => void + shareMessageFailed: (event: EventData['shareMessageFailed']) => void + emojiStatusSet: () => void + emojiStatusFailed: (event: EventData['emojiStatusFailed']) => void + emojiStatusAccessRequested: (event: EventData['emojiStatusAccessRequested']) => void + fileDownloadRequested: (event: EventData['fileDownloadRequested']) => void +} + +export type EventHandler = { + (eventType: T, eventHandler: EventCallback[T]): void +} diff --git a/src/sdk/gyroscope.ts b/src/sdk/gyroscope.ts new file mode 100644 index 0000000..24ea825 --- /dev/null +++ b/src/sdk/gyroscope.ts @@ -0,0 +1,20 @@ +export type Gyroscope = { + isStarted: boolean + x: number + y: number + z: number + start: ( + params: GyroscopeStartParams, + callback?: GyroscopeCallback['start'] + ) => Gyroscope + stop: (callback?: GyroscopeCallback['stop']) => Gyroscope +} + +export type GyroscopeCallback = { + start: (success: boolean) => void + stop: (success: boolean) => void +} + +export type GyroscopeStartParams = { + refresh_rate?: number +} diff --git a/src/sdk/haptic-feedback.ts b/src/sdk/haptic-feedback.ts new file mode 100644 index 0000000..ebd88ef --- /dev/null +++ b/src/sdk/haptic-feedback.ts @@ -0,0 +1,9 @@ +export type HapticFeedback = { + impactOccurred: ( + style: 'light' | 'medium' | 'heavy' | 'rigid' | 'soft' + ) => HapticFeedback + notificationOccurred: ( + type: 'error' | 'success' | 'warning' + ) => HapticFeedback + selectionChanged: () => HapticFeedback +} diff --git a/src/sdk/index.ts b/src/sdk/index.ts new file mode 100644 index 0000000..2476af8 --- /dev/null +++ b/src/sdk/index.ts @@ -0,0 +1,25 @@ +import type { WebApp } from './webapp' + +export * from './accelerometer' +export * from './back-button' +export * from './biometric-manager' +export * from './bottom-button' +export * from './cloud-storage' +export * from './device-orientation' +export * from './events' +export * from './gyroscope' +export * from './haptic-feedback' +export * from './location-manager' +export * from './popup' +export * from './qr-scanner' +export * from './settings-button' +export * from './theme' +export * from './viewport' +export * from './webapp' + +export function getWebApp() { + if (!('Telegram' in window)) + throw new Error('Telegram SDK not found. Make sure https://telegram.org/js/telegram-web-app.js script is installed.') + // @ts-expect-error not typed + return window?.Telegram?.WebApp as WebApp +} diff --git a/src/sdk/location-manager.ts b/src/sdk/location-manager.ts new file mode 100644 index 0000000..4f3aff5 --- /dev/null +++ b/src/sdk/location-manager.ts @@ -0,0 +1,26 @@ +export type LocationManager = { + isInited: boolean + isLocationAvailable: boolean + isAccessRequested: boolean + isAccessGranted: boolean + init: (callback?: LocationManagerCallback['init']) => LocationManager + getLocation: (callback: LocationManagerCallback['getLocation']) => LocationManager + openSettings: () => LocationManager +} + +export type LocationManagerCallback = { + init: () => void + getLocation: (data: LocationData | null) => void +} + +export type LocationData = { + latitude: number + longitude: number + altitude: number | null + course: number | null + speed: number | null + horizontal_accuracy: number | null + vertical_accuracy: number | null + course_accuracy: number | null + speed_accuracy: number | null +} diff --git a/src/sdk/popup.ts b/src/sdk/popup.ts new file mode 100644 index 0000000..15f75fc --- /dev/null +++ b/src/sdk/popup.ts @@ -0,0 +1,11 @@ +export type PopupButton = { + id?: string + type?: 'default' | 'ok' | 'close' | 'cancel' | 'destructive' + text?: string +} + +export type PopupParams = { + title?: string + message: string + buttons?: PopupButton[] +} diff --git a/src/sdk/qr-scanner.ts b/src/sdk/qr-scanner.ts new file mode 100644 index 0000000..90212cb --- /dev/null +++ b/src/sdk/qr-scanner.ts @@ -0,0 +1,3 @@ +export type ScanQrPopupParams = { + text?: string +} diff --git a/src/sdk/settings-button.ts b/src/sdk/settings-button.ts new file mode 100644 index 0000000..d91b0f8 --- /dev/null +++ b/src/sdk/settings-button.ts @@ -0,0 +1,9 @@ +import type { EventCallback } from './events' + +export type SettingsButton = { + isVisible: boolean + onClick: (callback: EventCallback['settingsButtonClicked']) => SettingsButton + offClick: (callback: EventCallback['settingsButtonClicked']) => SettingsButton + show: () => SettingsButton + hide: () => SettingsButton +} diff --git a/src/sdk/theme.ts b/src/sdk/theme.ts new file mode 100644 index 0000000..d1af3ce --- /dev/null +++ b/src/sdk/theme.ts @@ -0,0 +1,17 @@ +export type ThemeParams = { + bg_color?: string + text_color?: string + hint_color?: string + link_color?: string + button_color?: string + button_text_color?: string + secondary_bg_color?: string + header_bg_color?: string + bottom_bar_bg_color?: string + accent_text_color?: string + section_bg_color?: string + section_header_text_color?: string + section_separator_color?: string + subtitle_text_color?: string + destructive_text_color?: string +} diff --git a/src/sdk/viewport.ts b/src/sdk/viewport.ts new file mode 100644 index 0000000..161db97 --- /dev/null +++ b/src/sdk/viewport.ts @@ -0,0 +1,13 @@ +export type SafeAreaInset = { + top: number + bottom: number + left: number + right: number +} + +export type ContentSafeAreaInset = { + top: number + bottom: number + left: number + right: number +} diff --git a/src/sdk/webapp.ts b/src/sdk/webapp.ts new file mode 100644 index 0000000..cff7454 --- /dev/null +++ b/src/sdk/webapp.ts @@ -0,0 +1,161 @@ +import type { Accelerometer, AccelerometerCallback } from './accelerometer' +import type { BackButton } from './back-button' +import type { BiometricManager, BiometricManagerCallback } from './biometric-manager' +import type { BottomButton } from './bottom-button' +import type { CloudStorage, CloudStorageCallback } from './cloud-storage' +import type { DeviceOrientation, DeviceOrientationCallback } from './device-orientation' +import type { EventData, EventHandler } from './events' +import type { Gyroscope, GyroscopeCallback } from './gyroscope' +import type { HapticFeedback } from './haptic-feedback' +import type { LocationManager, LocationManagerCallback } from './location-manager' +import type { PopupParams } from './popup' +import type { ScanQrPopupParams } from './qr-scanner' +import type { SettingsButton } from './settings-button' +import type { ThemeParams } from './theme' +import type { ContentSafeAreaInset, SafeAreaInset } from './viewport' + +export type WebApp = { + initData: string + initDataUnsafe: WebAppInitData + version: string + platform: string + colorScheme: string + themeParams: ThemeParams + isActive: boolean + isExpanded: boolean + viewportHeight: number + viewportStableHeight: number + headerColor: string + backgroundColor: string + bottomBarColor: string + isClosingConfirmationEnabled: boolean + isVerticalSwipesEnabled: boolean + isFullscreen: boolean + isOrientationLocked: boolean + safeAreaInset: SafeAreaInset + contentSafeAreaInset: ContentSafeAreaInset + BackButton: BackButton + MainButton: BottomButton + SecondaryButton: BottomButton + SettingsButton: SettingsButton + HapticFeedback: HapticFeedback + CloudStorage: CloudStorage + BiometricManager: BiometricManager + Accelerometer: Accelerometer + DeviceOrientation: DeviceOrientation + Gyroscope: Gyroscope + LocationManager: LocationManager + isVersionAtLeast: (version: string) => boolean + setHeaderColor: (color: 'bg_color' | 'secondary_bg_color' | (string & {})) => void + setBackgroundColor: (color: 'bg_color' | 'secondary_bg_color' | (string & {})) => void + setBottomBarColor: (color: 'bg_color' | 'secondary_bg_color' | 'bottom_bar_bg_color' | (string & {})) => void + enableClosingConfirmation: () => void + disableClosingConfirmation: () => void + enableVerticalSwipes: () => void + disableVerticalSwipes: () => void + requestFullscreen: () => void + exitFullscreen: () => void + lockOrientation: () => void + unlockOrientation: () => void + addToHomeScreen: () => void + checkHomeScreenStatus: (callback?: WebAppCallback['checkHomeScreenStatus']) => void + onEvent: EventHandler + offEvent: EventHandler + sendData: (data: string) => void + switchInlineQuery: (query: string, choose_chat_types?: string[]) => void + openLink: (url: string, options?: { try_instant_view: boolean }) => void + openTelegramLink: (url: string) => void + openInvoice: (url: string, callback?: WebAppCallback['openInvoice']) => void + shareToStory: (media_url: string, params?: StoryShareParams) => void + shareMessage: (msg_id: string, callback?: WebAppCallback['shareMessage']) => void + setEmojiStatus: (custom_emoji_id: string, params?: EmojiStatusParams, callback?: WebAppCallback['setEmojiStatus']) => void + requestEmojiStatusAccess: (callback?: WebAppCallback['requestEmojiStatusAccess']) => void + downloadFile: (params: DownloadFileParams, callback?: WebAppCallback['downloadFile']) => void + showPopup: (params: PopupParams, callback?: WebAppCallback['showPopup']) => void + showAlert: (message: string, callback?: WebAppCallback['showAlert']) => void + showConfirm: (message: string, callback?: WebAppCallback['showConfirm']) => void + showScanQrPopup: (params: ScanQrPopupParams, callback?: WebAppCallback['showScanQrPopup']) => void + closeScanQrPopup: () => void + readTextFromClipboard: (callback?: WebAppCallback['readTextFromClipboard']) => void + requestWriteAccess: (callback?: WebAppCallback['requestWriteAccess']) => void + requestContact: (callback?: WebAppCallback['requestContact']) => void + ready: () => void + expand: () => void + close: () => void +} + +export type WebAppCallback = { + checkHomeScreenStatus: (status: EventData['homeScreenChecked']['status']) => void + openInvoice: (status: EventData['invoiceClosed']['status']) => void + shareMessage: (success: boolean) => void + setEmojiStatus: (success: boolean) => void + requestEmojiStatusAccess: (granted: boolean) => void + downloadFile: (success: boolean) => void + showPopup: (buttonId: string) => void + showAlert: () => void + showConfirm: (isConfirmed: boolean) => void + showScanQrPopup: (text: string) => void + readTextFromClipboard: (text: string) => void + requestWriteAccess: (granted: boolean) => void + requestContact: (granted: boolean) => void + BiometricManager: BiometricManagerCallback + CloudStorage: CloudStorageCallback + Accelerometer: AccelerometerCallback + DeviceOrientation: DeviceOrientationCallback + Gyroscope: GyroscopeCallback + LocationManager: LocationManagerCallback +} + +export type StoryShareParams = { + text?: string + widget_link?: StoryWidgetLink +} + +export type StoryWidgetLink = { + url: string + name?: string +} + +export type EmojiStatusParams = { + duration?: number +} + +export type DownloadFileParams = { + url: string + file_name: string +} + +export type WebAppInitData = { + query_id?: string + user?: WebAppUser + receiver?: WebAppUser + chat?: WebAppChat + chat_type?: string + chat_instance?: string + start_param?: string + can_send_after?: number + auth_date: number + hash: string + signature: string +} + +export type WebAppUser = { + id: number + is_bot?: boolean + first_name: string + last_name?: string + username?: string + language_code?: string + is_premium?: true + added_to_attachment_menu?: true + allows_write_to_pm?: true + photo_url?: string +} + +export type WebAppChat = { + id: number + type: string + title: string + username?: string + photo_url?: string +} diff --git a/src/types.ts b/src/types.ts index b9a1a04..4bdddab 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,12 +1,74 @@ +import type { EventCallback, WebAppInitData, WebAppUser } from './sdk' + +type BOT_API_VERSIONS = [ + '6.0', + '6.1', + '6.2', + '6.4', + '6.7', + '6.9', + '7.0', + '7.2', + '7.6', + '7.7', + '7.8', + '7.10', + '8.0', +] + +export type LATEST_VERSION = '8.0' + +type Reverse = T extends [infer First, ...infer Rest] + ? [...Reverse, First] + : [] + +type Equals = X extends Y ? (Y extends X ? true : false) : false + +export type Merge = Omit & U + +export type BotApiVersion = BOT_API_VERSIONS[number] + +type VersionMap = + T extends readonly [infer First extends BotApiVersion, infer Second extends BotApiVersion, ...infer Rest extends BotApiVersion[]] + ? VersionMap<[Second, ...Rest], R & { [K in First]: Second }> + : R + +type BotApiNextVersionMap = VersionMap +export type BotApiNextVersion = V extends keyof BotApiNextVersionMap + ? BotApiNextVersionMap[V] + : never + +type BotApiPrevVersionMap = VersionMap> +export type BotApiPrevVersion = V extends keyof BotApiPrevVersionMap + ? BotApiPrevVersionMap[V] + : never + +export type BotApiVersionRange = + Equals extends true + ? Start + : Start | BotApiVersionRange, End> + +export type VersionedReturnType< + Schema extends Record, + Version extends BotApiVersion, + SuggestedVersions extends BotApiVersion, +> = + & Extract }> + & (Exclude> extends never + ? object + : { + isVersionAtLeast: >>(version: V) => this is { version: BotApiVersionRange } + }) + /** * Mini Apps */ -export interface OnEventReturn { +export type OnEventReturn = { off: () => void } -export interface OnEventOptions { +export type OnEventOptions = { /** * Disables automatic subscription management; you need to call the returned function `off` to unsubscribe. * @@ -15,81 +77,11 @@ export interface OnEventOptions { manual?: boolean } -export interface OnEventWithOptions { - ( - eventType: 'themeChanged', - eventHandler: ThemeChangedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'mainButtonClicked', - eventHandler: MainButtonClickedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'backButtonClicked', - eventHandler: BackButtonClickedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'settingsButtonClicked', - eventHandler: SettingsButtonClickedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'popupClosed', - eventHandler: PopupClosedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'viewportChanged', - eventHandler: ViewportChangedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'invoiceClosed', - eventHandler: InvoiceClosedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'qrTextReceived', - eventHandler: QrTextReceivedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'scanQrPopupClosed', - eventHandler: ScanQrPopupClosedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'clipboardTextReceived', - eventHandler: ClipboardTextReceivedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'writeAccessRequested', - eventHandler: WriteAccessRequestedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'contactRequested', - eventHandler: ContactRequestedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'biometricManagerUpdated', - eventHandler: BiometricManagerUpdatedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'biometricAuthRequested', - eventHandler: BiometricAuthRequestedCallback, - options?: O, - ): OnEventReturn - ( - eventType: 'biometricTokenUpdated', - eventHandler: BiometricTokenUpdatedCallback, - options?: O, +export type OnEventWithOptions = { + ( + eventType: T, + eventHandler: EventCallback[T], + options?: O ): OnEventReturn } @@ -97,8 +89,6 @@ export interface OnEventWithOptions { * Widgets */ -export type LoginWidgetUser = Pick< - WebAppUser, - 'id' | 'first_name' | 'last_name' | 'username' | 'photo_url' -> & -Pick +export type LoginWidgetUser = + & Pick + & Pick diff --git a/src/utils/functions.ts b/src/utils/functions.ts new file mode 100644 index 0000000..276f75f --- /dev/null +++ b/src/utils/functions.ts @@ -0,0 +1,74 @@ +interface HookObject { + before?: (args: TArgs) => void + after?: (args: TArgs, result: TResult) => void +} + +export function wrapFunction< + TFunction extends (...args: any[]) => any, + TOmitReturn extends boolean = false, +>( + fn: TFunction, + options?: { + hooks?: HookObject, ReturnType> + omitReturn?: TOmitReturn + }, +): (...args: Parameters) => TOmitReturn extends true ? void : ReturnType { + return (...args: Parameters) => { + const { hooks, omitReturn } = options || {} + if (hooks?.before) + hooks.before(args) + + const result = fn(...args) + + if (hooks?.after) + hooks.after(args, result) + + if (!omitReturn) + return result + } +} + +type Callback = (data: T) => void + +export function promisify( + func: (...args: [...A, Callback]) => void, +): (...args: A) => Promise { + return (...args: A) => + new Promise(resolve => func(...args, resolve)) +} + +type CallbackWithNoData = () => void + +export function promisifyWithNoData( + func: (...args: [...A, CallbackWithNoData]) => void, +): (...args: A) => Promise { + return (...args: A) => + new Promise(resolve => func(...args, resolve)) +} + +type CallbackWithError = (err: string | null, data: T | null) => void + +export function promisifyWithError( + func: (...args: [...A, CallbackWithError]) => void, +): (...args: A) => Promise { + return (...args: A) => + new Promise((resolve, reject) => + func(...args, (err, data) => (err ? reject(err) : resolve(data as T))), + ) +} + +type CallbackWithMultipleData = (...data: T) => void + +export function promisifyWithDataObject< + T extends any[], + R extends Record, + A extends any[], +>( + func: (...args: [...A, CallbackWithMultipleData]) => void, + mapToObject: (...data: T) => R, +): (...args: A) => Promise { + return (...args: A) => + new Promise(resolve => + func(...args, (...data: T) => resolve(mapToObject(...data))), + ) +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 16c8633..f39e9b5 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1 +1,3 @@ +export * from './functions' export * from './store' +export * from './version' diff --git a/src/utils/version.ts b/src/utils/version.ts new file mode 100644 index 0000000..b13c33e --- /dev/null +++ b/src/utils/version.ts @@ -0,0 +1,18 @@ +function compareVersions(version1: string, version2: string) { + const parts1 = (version1 || '').trim().split('.').map(Number) + const parts2 = (version2 || '').trim().split('.').map(Number) + const maxLength = Math.max(parts1.length, parts2.length) + + for (let i = 0; i < maxLength; i++) { + const p1 = parts1[i] || 0 + const p2 = parts2[i] || 0 + if (p1 !== p2) + return p1 > p2 ? 1 : -1 + } + + return 0 +} + +export function isVersionGreaterOrEqual(version1: string, version2: string) { + return compareVersions(version1, version2) >= 0 +} diff --git a/src/versions/6.0.ts b/src/versions/6.0.ts new file mode 100644 index 0000000..d4f0f4d --- /dev/null +++ b/src/versions/6.0.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.0') diff --git a/src/versions/6.1.ts b/src/versions/6.1.ts new file mode 100644 index 0000000..d21b50f --- /dev/null +++ b/src/versions/6.1.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.1') diff --git a/src/versions/6.2.ts b/src/versions/6.2.ts new file mode 100644 index 0000000..cb4f657 --- /dev/null +++ b/src/versions/6.2.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.2') diff --git a/src/versions/6.4.ts b/src/versions/6.4.ts new file mode 100644 index 0000000..d88d69a --- /dev/null +++ b/src/versions/6.4.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.4') diff --git a/src/versions/6.7.ts b/src/versions/6.7.ts new file mode 100644 index 0000000..093cc98 --- /dev/null +++ b/src/versions/6.7.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.7') diff --git a/src/versions/6.9.ts b/src/versions/6.9.ts new file mode 100644 index 0000000..ba10f25 --- /dev/null +++ b/src/versions/6.9.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('6.9') diff --git a/src/versions/7.0.ts b/src/versions/7.0.ts new file mode 100644 index 0000000..b3d855e --- /dev/null +++ b/src/versions/7.0.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.0') diff --git a/src/versions/7.10.ts b/src/versions/7.10.ts new file mode 100644 index 0000000..4567d66 --- /dev/null +++ b/src/versions/7.10.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.10') diff --git a/src/versions/7.2.ts b/src/versions/7.2.ts new file mode 100644 index 0000000..9ae0e90 --- /dev/null +++ b/src/versions/7.2.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.2') diff --git a/src/versions/7.6.ts b/src/versions/7.6.ts new file mode 100644 index 0000000..ba9fccc --- /dev/null +++ b/src/versions/7.6.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.6') diff --git a/src/versions/7.7.ts b/src/versions/7.7.ts new file mode 100644 index 0000000..ce54060 --- /dev/null +++ b/src/versions/7.7.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.7') diff --git a/src/versions/7.8.ts b/src/versions/7.8.ts new file mode 100644 index 0000000..4c43648 --- /dev/null +++ b/src/versions/7.8.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('7.8') diff --git a/src/versions/8.0.ts b/src/versions/8.0.ts new file mode 100644 index 0000000..9034e04 --- /dev/null +++ b/src/versions/8.0.ts @@ -0,0 +1,23 @@ +import { createComposablesWithVersion } from './helpers' + +export const { + useAccelerometer, + useBackButton, + useBiometricManager, + useClipboard, + useCloudStorage, + useDeviceOrientation, + useEmojiStatus, + useGyroscope, + useHapticFeedback, + useHomeScreen, + useLocationManager, + useMainButton, + useMiniApp, + usePopup, + useQrScanner, + useSecondaryButton, + useSettingsButton, + useTheme, + useViewport, +} = createComposablesWithVersion('8.0') diff --git a/src/versions/helpers.ts b/src/versions/helpers.ts new file mode 100644 index 0000000..efd2f08 --- /dev/null +++ b/src/versions/helpers.ts @@ -0,0 +1,44 @@ +import type { BotApiVersion } from '../types' +import { useAccelerometer as _useAccelerometer } from '../composables/useAccelerometer' +import { useBackButton as _useBackButton } from '../composables/useBackButton' +import { useBiometricManager as _useBiometricManager } from '../composables/useBiometricManager' +import { useClipboard as _useClipboard } from '../composables/useClipboard' +import { useCloudStorage as _useCloudStorage } from '../composables/useCloudStorage' +import { useDeviceOrientation as _useDeviceOrientation } from '../composables/useDeviceOrientation' +import { useEmojiStatus as _useEmojiStatus } from '../composables/useEmojiStatus' +import { useGyroscope as _useGyroscope } from '../composables/useGyroscope' +import { useHapticFeedback as _useHapticFeedback } from '../composables/useHapticFeedback' +import { useHomeScreen as _useHomeScreen } from '../composables/useHomeScreen' +import { useLocationManager as _useLocationManager } from '../composables/useLocationManager' +import { useMainButton as _useMainButton } from '../composables/useMainButton' +import { useMiniApp as _useMiniApp } from '../composables/useMiniApp' +import { usePopup as _usePopup } from '../composables/usePopup' +import { useQrScanner as _useQrScanner } from '../composables/useQrScanner' +import { useSecondaryButton as _useSecondaryButton } from '../composables/useSecondaryButton' +import { useSettingsButton as _useSettingsButton } from '../composables/useSettingsButton' +import { useTheme as _useTheme } from '../composables/useTheme' +import { useViewport as _useViewport } from '../composables/useViewport' + +export function createComposablesWithVersion(version: T) { + return { + useAccelerometer: () => _useAccelerometer({ version }), + useBackButton: () => _useBackButton({ version }), + useBiometricManager: () => _useBiometricManager({ version }), + useClipboard: () => _useClipboard({ version }), + useCloudStorage: () => _useCloudStorage({ version }), + useDeviceOrientation: () => _useDeviceOrientation({ version }), + useEmojiStatus: () => _useEmojiStatus({ version }), + useGyroscope: () => _useGyroscope({ version }), + useHapticFeedback: () => _useHapticFeedback({ version }), + useHomeScreen: () => _useHomeScreen({ version }), + useLocationManager: () => _useLocationManager({ version }), + useMainButton: () => _useMainButton({ version }), + useMiniApp: () => _useMiniApp({ version }), + usePopup: () => _usePopup({ version }), + useQrScanner: () => _useQrScanner({ version }), + useSecondaryButton: () => _useSecondaryButton({ version }), + useSettingsButton: () => _useSettingsButton({ version }), + useTheme: () => _useTheme({ version }), + useViewport: () => _useViewport({ version }), + } +} diff --git a/src/versions/latest.ts b/src/versions/latest.ts new file mode 100644 index 0000000..a21dce1 --- /dev/null +++ b/src/versions/latest.ts @@ -0,0 +1 @@ +export * from './8.0' diff --git a/tsconfig.json b/tsconfig.json index 72fed94..c649f64 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,6 @@ "incremental": false, "target": "ESNext", "lib": ["DOM", "ESNext"], - "baseUrl": ".", "module": "ESNext", "moduleResolution": "node", "resolveJsonModule": true, diff --git a/vite.config.mts b/vite.config.mts index 0db3c39..9a61d02 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,3 +1,4 @@ +import { resolve } from 'node:path' import vue from '@vitejs/plugin-vue' import { defineConfig } from 'vite' import dts from 'vite-plugin-dts' @@ -12,9 +13,30 @@ export default defineConfig({ ], build: { lib: { - entry: './src/index.ts', + entry: [ + resolve(__dirname, 'src/index.ts'), + resolve(__dirname, 'src/versions/6.0.ts'), + resolve(__dirname, 'src/versions/6.1.ts'), + resolve(__dirname, 'src/versions/6.2.ts'), + resolve(__dirname, 'src/versions/6.4.ts'), + resolve(__dirname, 'src/versions/6.7.ts'), + resolve(__dirname, 'src/versions/6.9.ts'), + resolve(__dirname, 'src/versions/7.0.ts'), + resolve(__dirname, 'src/versions/7.2.ts'), + resolve(__dirname, 'src/versions/7.6.ts'), + resolve(__dirname, 'src/versions/7.7.ts'), + resolve(__dirname, 'src/versions/7.8.ts'), + resolve(__dirname, 'src/versions/7.10.ts'), + resolve(__dirname, 'src/versions/8.0.ts'), + resolve(__dirname, 'src/versions/latest.ts'), + ], name: pkg.name, - fileName: format => `index.${format}.js`, + fileName(format, name) { + if (format === 'es') { + return `${name}.js` + } + return `${name}.${format}` + }, }, rollupOptions: { external: ['vue'],