From ff525f489e9414d6bad93b64733e05d5540cface Mon Sep 17 00:00:00 2001 From: deptyped Date: Wed, 11 Dec 2024 14:44:42 +0200 Subject: [PATCH 01/23] Export event functions on top level --- docs/mini-apps.md | 56 +++++------ .../composables/use-web-app-back-button.md | 11 +-- .../use-web-app-biometric-manager.md | 6 +- .../composables/use-web-app-clipboard.md | 7 +- .../composables/use-web-app-main-button.md | 1 - .../composables/use-web-app-navigation.md | 13 ++- .../composables/use-web-app-popup.md | 11 +-- .../composables/use-web-app-qr-scanner.md | 10 +- .../composables/use-web-app-requests.md | 10 +- .../use-web-app-settings-button.md | 11 +-- .../composables/use-web-app-theme.md | 1 - .../composables/use-web-app-viewport.md | 1 - docs/mini-apps/composables/use-web-app.md | 1 - src/composables/useWebApp.ts | 44 ++------- src/composables/useWebAppBackButton.ts | 15 +-- src/composables/useWebAppBiometricManager.ts | 27 ++---- src/composables/useWebAppClipboard.ts | 13 +-- src/composables/useWebAppMainButton.ts | 15 +-- src/composables/useWebAppNavigation.ts | 13 +-- src/composables/useWebAppPopup.ts | 13 +-- src/composables/useWebAppQrScanner.ts | 21 ++-- src/composables/useWebAppRequests.ts | 23 ++--- src/composables/useWebAppSettingsButton.ts | 15 +-- src/composables/useWebAppTheme.ts | 11 +-- src/composables/useWebAppViewport.ts | 15 +-- src/events.ts | 97 +++++++++++++++++++ src/index.ts | 2 +- tsconfig.json | 1 - 28 files changed, 225 insertions(+), 239 deletions(-) create mode 100644 src/events.ts diff --git a/docs/mini-apps.md b/docs/mini-apps.md index c9d7ef4..105c63b 100644 --- a/docs/mini-apps.md +++ b/docs/mini-apps.md @@ -35,8 +35,8 @@ outline: [2, 3] | disableClosingConfirmation | [useWebAppClosingConfirmation](#usewebappclosingconfirmation) | | enableVerticalSwipes | [useWebAppViewport](#usewebappviewport) | | disableVerticalSwipes | [useWebAppViewport](#usewebappviewport) | -| onEvent | [useWebApp](#usewebapp) | -| offEvent | [Handled automagically 🪄](#managing-event-subscriptions) | +| onEvent | [Event Handling](#event-handling) | +| offEvent | [Managing Event Subscriptions](#managing-event-subscriptions) | | sendData | [useWebApp](#usewebapp) | | switchInlineQuery | [useWebAppNavigation](#usewebappnavigation) | | openLink | [useWebAppNavigation](#usewebappnavigation) | @@ -57,12 +57,10 @@ outline: [2, 3] ### 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. +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. Generic `onEvent` is also available if you prefer it instead. ```ts -import { useWebAppTheme } from 'vue-tg' - -const { onThemeChanged } = useWebAppTheme() +import { onThemeChanged } from 'vue-tg' onThemeChanged(() => { // handle theme update @@ -71,23 +69,23 @@ onThemeChanged(() => { #### Mapping -| 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) | +| Event name | Handler | +| ----------------------- | ------------------------- | +| themeChanged | onThemeChanged | +| viewportChanged | onViewportChanged | +| mainButtonClicked | onMainButtonClicked | +| backButtonClicked | onBackButtonClicked | +| settingsButtonClicked | onSettingsButtonClicked | +| invoiceClosed | onInvoiceClosed | +| popupClosed | onPopupClosed | +| qrTextReceived | onQrTextReceived | +| scanQrPopupClosed | onScanQrPopupClosed | +| clipboardTextReceived | onClipboardTextReceived | +| writeAccessRequested | onWriteAccessRequested | +| contactRequested | onContactRequested | +| biometricManagerUpdated | onBiometricManagerUpdated | +| biometricAuthRequested | onBiometricAuthRequested | +| biometricTokenUpdated | onBiometricTokenUpdated | #### Managing event subscriptions @@ -95,10 +93,8 @@ onThemeChanged(() => { By default, event handlers are automatically unsubscribed when the component is unmounted. But you can unsubscribe before that if you need to: -```ts{9-10} -import { useWebAppTheme } from 'vue-tg' - -const { onThemeChanged } = useWebAppTheme() +```ts{7-8} +import { onThemeChanged } from 'vue-tg' const handler = onThemeChanged(() => { // handle theme update @@ -110,10 +106,8 @@ handler.off() You can also disable automatic unsubscribing completely: -```ts{9,12-13} -import { useWebAppTheme } from 'vue-tg' - -const { onThemeChanged } = useWebAppTheme() +```ts{10-11} +import { onThemeChanged } from 'vue-tg' const handler = onThemeChanged( () => { diff --git a/docs/mini-apps/composables/use-web-app-back-button.md b/docs/mini-apps/composables/use-web-app-back-button.md index e361a3e..8f3bc57 100644 --- a/docs/mini-apps/composables/use-web-app-back-button.md +++ b/docs/mini-apps/composables/use-web-app-back-button.md @@ -5,9 +5,8 @@ import { useWebAppBackButton } from 'vue-tg' ``` -| Name | Description | -| :-------------------- | :-------------------------------------------------------------------------------------------------------------------- | -| `isBackButtonVisible` |
| -| `onBackButtonClicked` | A method that sets the `backButtonClicked` [event handler](#event-handling). | -| `showBackButton` | | -| `hideBackButton` | | +| Name | Description | +| :-------------------- | :-------------------------------------------------------------------------------------------------- | +| `isBackButtonVisible` |
| +| `showBackButton` | | +| `hideBackButton` | | diff --git a/docs/mini-apps/composables/use-web-app-biometric-manager.md b/docs/mini-apps/composables/use-web-app-biometric-manager.md index dbc9708..51702de 100644 --- a/docs/mini-apps/composables/use-web-app-biometric-manager.md +++ b/docs/mini-apps/composables/use-web-app-biometric-manager.md @@ -19,6 +19,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/use-web-app-clipboard.md b/docs/mini-apps/composables/use-web-app-clipboard.md index 7271e46..ac5a55a 100644 --- a/docs/mini-apps/composables/use-web-app-clipboard.md +++ b/docs/mini-apps/composables/use-web-app-clipboard.md @@ -5,7 +5,6 @@ import { useWebAppClipboard } from 'vue-tg' ``` -| Name | Type | -| :------------------------ | :------------------------------------------------------------------------------------------------------------------------ | -| `onClipboardTextReceived` | A method that sets the `clipboardTextReceived` [event handler](#event-handling). | -| `readTextFromClipboard` | | +| Name | Type | +| :---------------------- | :------------------------------------------------------------ | +| `readTextFromClipboard` | | diff --git a/docs/mini-apps/composables/use-web-app-main-button.md b/docs/mini-apps/composables/use-web-app-main-button.md index 3749c52..3d63df0 100644 --- a/docs/mini-apps/composables/use-web-app-main-button.md +++ b/docs/mini-apps/composables/use-web-app-main-button.md @@ -14,7 +14,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/use-web-app-navigation.md b/docs/mini-apps/composables/use-web-app-navigation.md index 25153dd..882c84b 100644 --- a/docs/mini-apps/composables/use-web-app-navigation.md +++ b/docs/mini-apps/composables/use-web-app-navigation.md @@ -5,10 +5,9 @@ import { useWebAppNavigation } from 'vue-tg' ``` -| Name | Type | -| :------------------ | :---------------------------------------------------------------------------------------------------------------- | -| `onInvoiceClosed` | A method that sets the `invoiceClosed` [event handler](#event-handling). | -| `openInvoice` | | -| `openLink` | | -| `openTelegramLink` | | -| `switchInlineQuery` | | +| Name | Type | +| :------------------ | :-------------------------------------------------------- | +| `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 index 55f85fb..d2be7ba 100644 --- a/docs/mini-apps/composables/use-web-app-popup.md +++ b/docs/mini-apps/composables/use-web-app-popup.md @@ -5,9 +5,8 @@ import { useWebAppPopup } from 'vue-tg' ``` -| Name | Type | -| :-------------- | :-------------------------------------------------------------------------------------------------------------- | -| `onPopupClosed` | A method that sets the `popupClosed` [event handler](#event-handling). | -| `showAlert` | | -| `showConfirm` | | -| `showPopup` | | +| Name | Type | +| :------------ | :-------------------------------------------------- | +| `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 index e02fab1..39394c6 100644 --- a/docs/mini-apps/composables/use-web-app-qr-scanner.md +++ b/docs/mini-apps/composables/use-web-app-qr-scanner.md @@ -5,9 +5,7 @@ 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). | +| Name | Type | +| :----------------- | :------------------------------------------------------- | +| `showScanQrPopup` | | +| `closeScanQrPopup` | | diff --git a/docs/mini-apps/composables/use-web-app-requests.md b/docs/mini-apps/composables/use-web-app-requests.md index c6f328e..e7a58f0 100644 --- a/docs/mini-apps/composables/use-web-app-requests.md +++ b/docs/mini-apps/composables/use-web-app-requests.md @@ -5,9 +5,7 @@ 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` | | +| Name | Type | +| :------------------- | :--------------------------------------------------------- | +| `requestContact` | | +| `requestWriteAccess` | | diff --git a/docs/mini-apps/composables/use-web-app-settings-button.md b/docs/mini-apps/composables/use-web-app-settings-button.md index 9233207..3791766 100644 --- a/docs/mini-apps/composables/use-web-app-settings-button.md +++ b/docs/mini-apps/composables/use-web-app-settings-button.md @@ -5,9 +5,8 @@ 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-theme.md b/docs/mini-apps/composables/use-web-app-theme.md index 432288b..1ee1301 100644 --- a/docs/mini-apps/composables/use-web-app-theme.md +++ b/docs/mini-apps/composables/use-web-app-theme.md @@ -13,4 +13,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/use-web-app-viewport.md index d82a63d..b64adef 100644 --- a/docs/mini-apps/composables/use-web-app-viewport.md +++ b/docs/mini-apps/composables/use-web-app-viewport.md @@ -14,4 +14,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/use-web-app.md index fac90a1..8d22792 100644 --- a/docs/mini-apps/composables/use-web-app.md +++ b/docs/mini-apps/composables/use-web-app.md @@ -12,7 +12,6 @@ import { useWebApp } from 'vue-tg' | `version` | | | `platform` | | | `isVersionAtLeast` | | -| `onEvent` | | | `sendData` | | | `ready` | | | `close` | | diff --git a/src/composables/useWebApp.ts b/src/composables/useWebApp.ts index f99cafc..c95cc58 100644 --- a/src/composables/useWebApp.ts +++ b/src/composables/useWebApp.ts @@ -1,5 +1,5 @@ -import type { OnEventOptions, OnEventWithOptions } from '../types' -import { onMounted, onUnmounted, readonly, ref } from 'vue' +import { readonly, ref } from 'vue' +import { onEvent } from '../events' const isReady = ref(false) @@ -36,41 +36,6 @@ function isFeatureSupported(name: keyof typeof featureSupportVersion) { } 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, @@ -91,7 +56,6 @@ export function useWebApp() { version, platform, isVersionAtLeast, - onEvent, sendData, ready, close, @@ -99,6 +63,10 @@ export function useWebApp() { isPlatform, isPlatformUnknown, isFeatureSupported, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onEvent, /** * @deprecated */ diff --git a/src/composables/useWebAppBackButton.ts b/src/composables/useWebAppBackButton.ts index 7276ea8..1368810 100644 --- a/src/composables/useWebAppBackButton.ts +++ b/src/composables/useWebAppBackButton.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { computed, ref } from 'vue' +import { onBackButtonClicked } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const isBackButtonVisible = ref(Telegram.WebApp.BackButton.isVisible) @@ -30,13 +29,6 @@ const useStore = defineStore(() => { 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() { @@ -46,8 +38,11 @@ export function useWebAppBackButton() { isVisible ? showBackButton() : hideBackButton() }, }), - onBackButtonClicked, showBackButton, hideBackButton, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onBackButtonClicked, } } diff --git a/src/composables/useWebAppBiometricManager.ts b/src/composables/useWebAppBiometricManager.ts index d3f8fa8..1ff01f8 100644 --- a/src/composables/useWebAppBiometricManager.ts +++ b/src/composables/useWebAppBiometricManager.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { readonly, ref } from 'vue' +import { onBiometricAuthRequested, onBiometricManagerUpdated, onBiometricTokenUpdated } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const isBiometricInited = ref(Telegram.WebApp.BiometricManager.isInited) @@ -58,21 +57,6 @@ export function useWebAppBiometricManager() { 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 { @@ -96,8 +80,17 @@ export function useWebAppBiometricManager() { authenticateBiometric: authenticate, updateBiometricToken, 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/useWebAppClipboard.ts b/src/composables/useWebAppClipboard.ts index bf47555..139f8ad 100644 --- a/src/composables/useWebAppClipboard.ts +++ b/src/composables/useWebAppClipboard.ts @@ -1,18 +1,13 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' +import { onClipboardTextReceived } from '../events' export function useWebAppClipboard() { - const { onEvent } = useWebApp() - - const onClipboardTextReceived = ( - eventHandler: ClipboardTextReceivedCallback, - options?: OnEventOptions, - ) => onEvent('clipboardTextReceived', eventHandler, options) - const { readTextFromClipboard } = Telegram.WebApp return { readTextFromClipboard, + /** + * @deprecated import directly from `vue-tg` instead. + */ onClipboardTextReceived, } } diff --git a/src/composables/useWebAppMainButton.ts b/src/composables/useWebAppMainButton.ts index e5ee2ff..aced4db 100644 --- a/src/composables/useWebAppMainButton.ts +++ b/src/composables/useWebAppMainButton.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { computed, ref } from 'vue' +import { onMainButtonClicked } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const mainButtonText = ref(Telegram.WebApp.MainButton.text) @@ -115,13 +114,6 @@ export function useWebAppMainButton() { setMainButtonParams, } = useStore() - const { onEvent } = useWebApp() - - const onMainButtonClicked = ( - eventHandler: MainButtonClickedCallback, - options?: OnEventOptions, - ) => onEvent('mainButtonClicked', eventHandler, options) - return { mainButtonText: computed({ get() { @@ -176,7 +168,6 @@ export function useWebAppMainButton() { }, }), setMainButtonText, - onMainButtonClicked, showMainButton, hideMainButton, enableMainButton, @@ -184,5 +175,9 @@ export function useWebAppMainButton() { showMainButtonProgress, hideMainButtonProgress, setMainButtonParams, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onMainButtonClicked, } } diff --git a/src/composables/useWebAppNavigation.ts b/src/composables/useWebAppNavigation.ts index e818db3..47df552 100644 --- a/src/composables/useWebAppNavigation.ts +++ b/src/composables/useWebAppNavigation.ts @@ -1,14 +1,6 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' +import { onInvoiceClosed } from '../events' export function useWebAppNavigation() { - const { onEvent } = useWebApp() - - const onInvoiceClosed = ( - eventHandler: InvoiceClosedCallback, - options?: OnEventOptions, - ) => onEvent('invoiceClosed', eventHandler, options) - const { switchInlineQuery, openLink, openTelegramLink, openInvoice } = Telegram.WebApp @@ -17,6 +9,9 @@ export function useWebAppNavigation() { openLink, openTelegramLink, openInvoice, + /** + * @deprecated import directly from `vue-tg` instead. + */ onInvoiceClosed, } } diff --git a/src/composables/useWebAppPopup.ts b/src/composables/useWebAppPopup.ts index 35bf63d..b7eba3c 100644 --- a/src/composables/useWebAppPopup.ts +++ b/src/composables/useWebAppPopup.ts @@ -1,20 +1,15 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' +import { onPopupClosed } from '../events' 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, + /** + * @deprecated import directly from `vue-tg` instead. + */ onPopupClosed, } } diff --git a/src/composables/useWebAppQrScanner.ts b/src/composables/useWebAppQrScanner.ts index 91483c6..31d9a6b 100644 --- a/src/composables/useWebAppQrScanner.ts +++ b/src/composables/useWebAppQrScanner.ts @@ -1,25 +1,18 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' +import { onQrTextReceived, onScanQrPopupClosed } from '../events' 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, + /** + * @deprecated import directly from `vue-tg` instead. + */ onQrTextReceived, + /** + * @deprecated import directly from `vue-tg` instead. + */ onScanQrPopupClosed, } } diff --git a/src/composables/useWebAppRequests.ts b/src/composables/useWebAppRequests.ts index 1fb921d..3478723 100644 --- a/src/composables/useWebAppRequests.ts +++ b/src/composables/useWebAppRequests.ts @@ -1,25 +1,18 @@ -import type { OnEventOptions } from '../types' -import { useWebApp } from './useWebApp' +import { onContactRequested, onWriteAccessRequested } from '../events' 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, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onContactRequested, + /** + * @deprecated import directly from `vue-tg` instead. + */ onWriteAccessRequested, } } diff --git a/src/composables/useWebAppSettingsButton.ts b/src/composables/useWebAppSettingsButton.ts index 317c796..249c96e 100644 --- a/src/composables/useWebAppSettingsButton.ts +++ b/src/composables/useWebAppSettingsButton.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { computed, ref } from 'vue' +import { onSettingsButtonClicked } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const isSettingsButtonVisible = ref(Telegram.WebApp.SettingsButton.isVisible) @@ -31,13 +30,6 @@ 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() { @@ -47,8 +39,11 @@ export function useWebAppSettingsButton() { isVisible ? showSettingsButton() : hideSettingsButton() }, }), - onSettingsButtonClicked, showSettingsButton, hideSettingsButton, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onSettingsButtonClicked, } } diff --git a/src/composables/useWebAppTheme.ts b/src/composables/useWebAppTheme.ts index 832a7ff..adf673b 100644 --- a/src/composables/useWebAppTheme.ts +++ b/src/composables/useWebAppTheme.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { computed, readonly, ref } from 'vue' +import { onThemeChanged } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const colorScheme = ref(Telegram.WebApp.colorScheme) @@ -54,11 +53,6 @@ export function useWebAppTheme() { setBackgroundColor, } = useStore() - const { onEvent } = useWebApp() - - const onThemeChanged = (eventHandler: () => void, options?: OnEventOptions) => - onEvent('themeChanged', eventHandler, options) - onThemeChanged(updateState) return { @@ -82,6 +76,9 @@ export function useWebAppTheme() { }), setHeaderColor, setBackgroundColor, + /** + * @deprecated import directly from `vue-tg` instead. + */ onThemeChanged, } } diff --git a/src/composables/useWebAppViewport.ts b/src/composables/useWebAppViewport.ts index 5c967a1..1cafab2 100644 --- a/src/composables/useWebAppViewport.ts +++ b/src/composables/useWebAppViewport.ts @@ -1,7 +1,6 @@ -import type { OnEventOptions } from '../types' import { computed, readonly, ref } from 'vue' +import { onViewportChanged } from '../events' import { defineStore } from '../utils' -import { useWebApp } from './useWebApp' const useStore = defineStore(() => { const isExpanded = ref(Telegram.WebApp.isExpanded) @@ -59,13 +58,6 @@ export function useWebAppViewport() { disableVerticalSwipes, } = useStore() - const { onEvent } = useWebApp() - - const onViewportChanged = ( - eventHandler: ViewportChangedCallback, - options?: OnEventOptions, - ) => onEvent('viewportChanged', eventHandler, options) - onViewportChanged(updateState) return { @@ -73,7 +65,6 @@ export function useWebAppViewport() { viewportHeight: readonly(viewportHeight), viewportStableHeight: readonly(viewportStableHeight), expand, - onViewportChanged, isVerticalSwipesEnabled: computed({ get() { return isVerticalSwipesEnabled.value @@ -84,5 +75,9 @@ export function useWebAppViewport() { }), enableVerticalSwipes, disableVerticalSwipes, + /** + * @deprecated import directly from `vue-tg` instead. + */ + onViewportChanged, } } diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..9bb687c --- /dev/null +++ b/src/events.ts @@ -0,0 +1,97 @@ +import type { OnEventOptions, OnEventWithOptions } from './types' +import { onMounted, onUnmounted } from 'vue' + +export 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, + } +} + +export function onThemeChanged(eventHandler: () => void, options?: OnEventOptions) { + return onEvent('themeChanged', eventHandler, options) +} + +export function onViewportChanged(eventHandler: ViewportChangedCallback, options?: OnEventOptions) { + return onEvent('viewportChanged', eventHandler, options) +} + +export function onMainButtonClicked(eventHandler: MainButtonClickedCallback, options?: OnEventOptions) { + return onEvent('mainButtonClicked', eventHandler, options) +} + +export function onBackButtonClicked(eventHandler: BackButtonClickedCallback, options?: OnEventOptions) { + return onEvent('backButtonClicked', eventHandler, options) +} + +export function onSettingsButtonClicked(eventHandler: SettingsButtonClickedCallback, options?: OnEventOptions) { + return onEvent('settingsButtonClicked', eventHandler, options) +} + +export function onInvoiceClosed(eventHandler: InvoiceClosedCallback, options?: OnEventOptions) { + return onEvent('invoiceClosed', eventHandler, options) +} + +export function onPopupClosed(eventHandler: PopupClosedCallback, options?: OnEventOptions) { + return onEvent('popupClosed', eventHandler, options) +} + +export function onQrTextReceived(eventHandler: QrTextReceivedCallback, options?: OnEventOptions) { + return onEvent('qrTextReceived', eventHandler, options) +} + +export function onScanQrPopupClosed(eventHandler: ScanQrPopupClosedCallback, options?: OnEventOptions) { + return onEvent('scanQrPopupClosed', eventHandler, options) +} + +export function onClipboardTextReceived(eventHandler: ClipboardTextReceivedCallback, options?: OnEventOptions) { + return onEvent('clipboardTextReceived', eventHandler, options) +} + +export function onWriteAccessRequested(eventHandler: WriteAccessRequestedCallback, options?: OnEventOptions) { + return onEvent('writeAccessRequested', eventHandler, options) +} + +export function onContactRequested(eventHandler: ContactRequestedCallback, options?: OnEventOptions) { + return onEvent('contactRequested', eventHandler, options) +} + +export function onBiometricManagerUpdated(eventHandler: () => void, options?: OnEventOptions) { + return onEvent('biometricManagerUpdated', eventHandler, options) +} + +export function onBiometricAuthRequested(eventHandler: BiometricAuthRequestedCallback, options?: OnEventOptions) { + return onEvent('biometricAuthRequested', eventHandler, options) +} + +export function onBiometricTokenUpdated(eventHandler: BiometricTokenUpdatedCallback, options?: OnEventOptions) { + return onEvent('biometricTokenUpdated', eventHandler, options) +} diff --git a/src/index.ts b/src/index.ts index ffddaf6..3f6bb4e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,7 +33,6 @@ export { } export { useWebApp } from './composables/useWebApp' - export { useWebAppBackButton } from './composables/useWebAppBackButton' export { useWebAppBiometricManager } from './composables/useWebAppBiometricManager' export { useWebAppClipboard } from './composables/useWebAppClipboard' @@ -50,6 +49,7 @@ export { useWebAppSettingsButton } from './composables/useWebAppSettingsButton' export { useWebAppShare } from './composables/useWebAppShare' export { useWebAppTheme } from './composables/useWebAppTheme' export { useWebAppViewport } from './composables/useWebAppViewport' +export * from './events' export type { LoginWidgetUser } from './types' const plugin = { 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, From d126831d2921050824628380c4aae4ce0951b4bf Mon Sep 17 00:00:00 2001 From: deptyped Date: Thu, 12 Dec 2024 00:53:40 +0200 Subject: [PATCH 02/23] Deprecate composables --- docs/mini-apps.md | 34 +++++++++---------- .../use-web-app-back-button.md | 6 +++- .../use-web-app-biometric-manager.md | 6 +++- .../use-web-app-clipboard.md | 6 +++- .../use-web-app-closing-confirmation.md | 6 +++- .../use-web-app-cloud-storage.md | 6 +++- .../use-web-app-haptic-feedback.md | 6 +++- .../use-web-app-main-button.md | 6 +++- .../use-web-app-navigation.md | 6 +++- .../use-web-app-popup.md | 6 +++- .../use-web-app-qr-scanner.md | 6 +++- .../use-web-app-requests.md | 6 +++- .../use-web-app-settings-button.md | 6 +++- .../use-web-app-share.md | 6 +++- .../use-web-app-theme.md | 6 +++- .../use-web-app-viewport.md | 6 +++- .../use-web-app.md | 6 +++- .../useWebApp.ts | 3 ++ .../useWebAppBackButton.ts | 3 ++ .../useWebAppBiometricManager.ts | 3 ++ .../useWebAppClipboard.ts | 3 ++ .../useWebAppClosingConfirmation.ts | 3 ++ .../useWebAppCloudStorage.ts | 3 ++ .../useWebAppHapticFeedback.ts | 3 ++ .../useWebAppMainButton.ts | 3 ++ .../useWebAppNavigation.ts | 3 ++ .../useWebAppPopup.ts | 3 ++ .../useWebAppQrScanner.ts | 3 ++ .../useWebAppRequests.ts | 3 ++ .../useWebAppSendData.ts | 0 .../useWebAppSettingsButton.ts | 3 ++ .../useWebAppShare.ts | 3 ++ .../useWebAppTheme.ts | 3 ++ .../useWebAppViewport.ts | 3 ++ src/index.ts | 34 +++++++++---------- 35 files changed, 162 insertions(+), 50 deletions(-) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-back-button.md (88%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-biometric-manager.md (96%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-clipboard.md (79%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-closing-confirmation.md (89%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-cloud-storage.md (87%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-haptic-feedback.md (83%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-main-button.md (96%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-navigation.md (86%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-popup.md (83%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-qr-scanner.md (81%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-requests.md (82%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-settings-button.md (87%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-share.md (77%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-theme.md (93%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app-viewport.md (93%) rename docs/mini-apps/{composables => composables-legacy}/use-web-app.md (96%) rename src/{composables => composables-legacy}/useWebApp.ts (93%) rename src/{composables => composables-legacy}/useWebAppBackButton.ts (91%) rename src/{composables => composables-legacy}/useWebAppBiometricManager.ts (96%) rename src/{composables => composables-legacy}/useWebAppClipboard.ts (72%) rename src/{composables => composables-legacy}/useWebAppClosingConfirmation.ts (91%) rename src/{composables => composables-legacy}/useWebAppCloudStorage.ts (95%) rename src/{composables => composables-legacy}/useWebAppHapticFeedback.ts (66%) rename src/{composables => composables-legacy}/useWebAppMainButton.ts (97%) rename src/{composables => composables-legacy}/useWebAppNavigation.ts (77%) rename src/{composables => composables-legacy}/useWebAppPopup.ts (74%) rename src/{composables => composables-legacy}/useWebAppQrScanner.ts (79%) rename src/{composables => composables-legacy}/useWebAppRequests.ts (80%) rename src/{composables => composables-legacy}/useWebAppSendData.ts (100%) rename src/{composables => composables-legacy}/useWebAppSettingsButton.ts (91%) rename src/{composables => composables-legacy}/useWebAppShare.ts (75%) rename src/{composables => composables-legacy}/useWebAppTheme.ts (95%) rename src/{composables => composables-legacy}/useWebAppViewport.ts (95%) diff --git a/docs/mini-apps.md b/docs/mini-apps.md index 105c63b..335e81d 100644 --- a/docs/mini-apps.md +++ b/docs/mini-apps.md @@ -147,36 +147,36 @@ If subscription is not managed properly, it can lead to memory leaks and other i -## Composables +## Composables (Legacy) - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/docs/mini-apps/composables/use-web-app-back-button.md b/docs/mini-apps/composables-legacy/use-web-app-back-button.md similarity index 88% rename from docs/mini-apps/composables/use-web-app-back-button.md rename to docs/mini-apps/composables-legacy/use-web-app-back-button.md index 8f3bc57..f3f3d2b 100644 --- a/docs/mini-apps/composables/use-web-app-back-button.md +++ b/docs/mini-apps/composables-legacy/use-web-app-back-button.md @@ -1,4 +1,8 @@ -### useWebAppBackButton +### ~~useWebAppBackButton~~ + +::: danger Deprecated +Use [useBackButton](#usebackbutton) instead. +::: ```ts twoslash // Hover to inspect type 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 96% 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 51702de..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 diff --git a/docs/mini-apps/composables/use-web-app-clipboard.md b/docs/mini-apps/composables-legacy/use-web-app-clipboard.md similarity index 79% rename from docs/mini-apps/composables/use-web-app-clipboard.md rename to docs/mini-apps/composables-legacy/use-web-app-clipboard.md index ac5a55a..506c0ef 100644 --- a/docs/mini-apps/composables/use-web-app-clipboard.md +++ b/docs/mini-apps/composables-legacy/use-web-app-clipboard.md @@ -1,4 +1,8 @@ -### useWebAppClipboard +### ~~useWebAppClipboard~~ + +::: danger Deprecated +Use [useClipboard](#useclipboard) instead. +::: ```ts twoslash // Hover to inspect type 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 96% 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 3d63df0..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 diff --git a/docs/mini-apps/composables/use-web-app-navigation.md b/docs/mini-apps/composables-legacy/use-web-app-navigation.md similarity index 86% rename from docs/mini-apps/composables/use-web-app-navigation.md rename to docs/mini-apps/composables-legacy/use-web-app-navigation.md index 882c84b..8b66b3e 100644 --- a/docs/mini-apps/composables/use-web-app-navigation.md +++ b/docs/mini-apps/composables-legacy/use-web-app-navigation.md @@ -1,4 +1,8 @@ -### useWebAppNavigation +### ~~useWebAppNavigation~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-popup.md b/docs/mini-apps/composables-legacy/use-web-app-popup.md similarity index 83% rename from docs/mini-apps/composables/use-web-app-popup.md rename to docs/mini-apps/composables-legacy/use-web-app-popup.md index d2be7ba..bf05d35 100644 --- a/docs/mini-apps/composables/use-web-app-popup.md +++ b/docs/mini-apps/composables-legacy/use-web-app-popup.md @@ -1,4 +1,8 @@ -### useWebAppPopup +### ~~useWebAppPopup~~ + +::: danger Deprecated +Use [usePopup](#usepopup) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-qr-scanner.md b/docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md similarity index 81% rename from docs/mini-apps/composables/use-web-app-qr-scanner.md rename to docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md index 39394c6..13b2861 100644 --- a/docs/mini-apps/composables/use-web-app-qr-scanner.md +++ b/docs/mini-apps/composables-legacy/use-web-app-qr-scanner.md @@ -1,4 +1,8 @@ -### useWebAppQrScanner +### ~~useWebAppQrScanner~~ + +::: danger Deprecated +Use [useQrScanner](#useqrscanner) instead. +::: ```ts twoslash // Hover to inspect type diff --git a/docs/mini-apps/composables/use-web-app-requests.md b/docs/mini-apps/composables-legacy/use-web-app-requests.md similarity index 82% rename from docs/mini-apps/composables/use-web-app-requests.md rename to docs/mini-apps/composables-legacy/use-web-app-requests.md index e7a58f0..da81847 100644 --- a/docs/mini-apps/composables/use-web-app-requests.md +++ b/docs/mini-apps/composables-legacy/use-web-app-requests.md @@ -1,4 +1,8 @@ -### useWebAppRequests +### ~~useWebAppRequests~~ + +::: danger Deprecated +Use [useMiniApp](#useminiapp) instead. +::: ```ts twoslash // Hover to inspect type 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 87% 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 3791766..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,4 +1,8 @@ -### useWebAppSettingsButton +### ~~useWebAppSettingsButton~~ + +::: danger Deprecated +Use [useSettingsButton](#usesettingsbutton) instead. +::: ```ts twoslash // Hover to inspect type 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 77% 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..7c50b8b 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 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 93% rename from docs/mini-apps/composables/use-web-app-theme.md rename to docs/mini-apps/composables-legacy/use-web-app-theme.md index 1ee1301..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 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 93% rename from docs/mini-apps/composables/use-web-app-viewport.md rename to docs/mini-apps/composables-legacy/use-web-app-viewport.md index b64adef..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 diff --git a/docs/mini-apps/composables/use-web-app.md b/docs/mini-apps/composables-legacy/use-web-app.md similarity index 96% rename from docs/mini-apps/composables/use-web-app.md rename to docs/mini-apps/composables-legacy/use-web-app.md index 8d22792..76ebc9d 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 diff --git a/src/composables/useWebApp.ts b/src/composables-legacy/useWebApp.ts similarity index 93% rename from src/composables/useWebApp.ts rename to src/composables-legacy/useWebApp.ts index c95cc58..5eab27f 100644 --- a/src/composables/useWebApp.ts +++ b/src/composables-legacy/useWebApp.ts @@ -35,6 +35,9 @@ function isFeatureSupported(name: keyof typeof featureSupportVersion) { return Telegram.WebApp.isVersionAtLeast(featureSupportVersion[name]) } +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ export function useWebApp() { const { initData, diff --git a/src/composables/useWebAppBackButton.ts b/src/composables-legacy/useWebAppBackButton.ts similarity index 91% rename from src/composables/useWebAppBackButton.ts rename to src/composables-legacy/useWebAppBackButton.ts index 1368810..31205e0 100644 --- a/src/composables/useWebAppBackButton.ts +++ b/src/composables-legacy/useWebAppBackButton.ts @@ -26,6 +26,9 @@ const useStore = defineStore(() => { return { isBackButtonVisible, showBackButton, hideBackButton } }) +/** + * @deprecated Use [`useBackButton`](https://vue-tg.deptyped.com/mini-apps.html#usebackbutton) instead + */ export function useWebAppBackButton() { const { isBackButtonVisible, showBackButton, hideBackButton } = useStore() diff --git a/src/composables/useWebAppBiometricManager.ts b/src/composables-legacy/useWebAppBiometricManager.ts similarity index 96% rename from src/composables/useWebAppBiometricManager.ts rename to src/composables-legacy/useWebAppBiometricManager.ts index 1ff01f8..61f1a45 100644 --- a/src/composables/useWebAppBiometricManager.ts +++ b/src/composables-legacy/useWebAppBiometricManager.ts @@ -45,6 +45,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useBiometricManager`](https://vue-tg.deptyped.com/mini-apps.html#usebiometricmanager) instead + */ export function useWebAppBiometricManager() { const { isBiometricInited, diff --git a/src/composables/useWebAppClipboard.ts b/src/composables-legacy/useWebAppClipboard.ts similarity index 72% rename from src/composables/useWebAppClipboard.ts rename to src/composables-legacy/useWebAppClipboard.ts index 139f8ad..40a7b54 100644 --- a/src/composables/useWebAppClipboard.ts +++ b/src/composables-legacy/useWebAppClipboard.ts @@ -1,5 +1,8 @@ import { onClipboardTextReceived } from '../events' +/** + * @deprecated Use [`useClipboard`](https://vue-tg.deptyped.com/mini-apps.html#useclipboard) instead + */ export function useWebAppClipboard() { const { readTextFromClipboard } = Telegram.WebApp diff --git a/src/composables/useWebAppClosingConfirmation.ts b/src/composables-legacy/useWebAppClosingConfirmation.ts similarity index 91% rename from src/composables/useWebAppClosingConfirmation.ts rename to src/composables-legacy/useWebAppClosingConfirmation.ts index 567f730..57b897a 100644 --- a/src/composables/useWebAppClosingConfirmation.ts +++ b/src/composables-legacy/useWebAppClosingConfirmation.ts @@ -33,6 +33,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useClosingConfirmation`](https://vue-tg.deptyped.com/mini-apps.html#useclosingconfirmation) instead + */ export function useWebAppClosingConfirmation() { const { isClosingConfirmationEnabled, diff --git a/src/composables/useWebAppCloudStorage.ts b/src/composables-legacy/useWebAppCloudStorage.ts similarity index 95% rename from src/composables/useWebAppCloudStorage.ts rename to src/composables-legacy/useWebAppCloudStorage.ts index 5e8fad8..470ecc9 100644 --- a/src/composables/useWebAppCloudStorage.ts +++ b/src/composables-legacy/useWebAppCloudStorage.ts @@ -104,6 +104,9 @@ function getStorageKeys() { }) } +/** + * @deprecated Use [`useCloudStorage`](https://vue-tg.deptyped.com/mini-apps.html#usecloudstorage) instead + */ export function useWebAppCloudStorage() { return { setStorageItem, diff --git a/src/composables/useWebAppHapticFeedback.ts b/src/composables-legacy/useWebAppHapticFeedback.ts similarity index 66% rename from src/composables/useWebAppHapticFeedback.ts rename to src/composables-legacy/useWebAppHapticFeedback.ts index 81b7106..1efaf79 100644 --- a/src/composables/useWebAppHapticFeedback.ts +++ b/src/composables-legacy/useWebAppHapticFeedback.ts @@ -1,3 +1,6 @@ +/** + * @deprecated Use [`useHapticFeedback`](https://vue-tg.deptyped.com/mini-apps.html#usehapticfeedback) instead + */ export function useWebAppHapticFeedback() { const { impactOccurred, notificationOccurred, selectionChanged } = Telegram.WebApp.HapticFeedback diff --git a/src/composables/useWebAppMainButton.ts b/src/composables-legacy/useWebAppMainButton.ts similarity index 97% rename from src/composables/useWebAppMainButton.ts rename to src/composables-legacy/useWebAppMainButton.ts index aced4db..a4622c3 100644 --- a/src/composables/useWebAppMainButton.ts +++ b/src/composables-legacy/useWebAppMainButton.ts @@ -96,6 +96,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useMainButton`](https://vue-tg.deptyped.com/mini-apps.html#usemainbutton) instead + */ export function useWebAppMainButton() { const { mainButtonText, diff --git a/src/composables/useWebAppNavigation.ts b/src/composables-legacy/useWebAppNavigation.ts similarity index 77% rename from src/composables/useWebAppNavigation.ts rename to src/composables-legacy/useWebAppNavigation.ts index 47df552..bbbe7d9 100644 --- a/src/composables/useWebAppNavigation.ts +++ b/src/composables-legacy/useWebAppNavigation.ts @@ -1,5 +1,8 @@ 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 } = Telegram.WebApp diff --git a/src/composables/useWebAppPopup.ts b/src/composables-legacy/useWebAppPopup.ts similarity index 74% rename from src/composables/useWebAppPopup.ts rename to src/composables-legacy/useWebAppPopup.ts index b7eba3c..70686bb 100644 --- a/src/composables/useWebAppPopup.ts +++ b/src/composables-legacy/useWebAppPopup.ts @@ -1,5 +1,8 @@ import { onPopupClosed } from '../events' +/** + * @deprecated Use [`usePopup`](https://vue-tg.deptyped.com/mini-apps.html#usepopup) instead + */ export function useWebAppPopup() { const { showPopup, showAlert, showConfirm } = Telegram.WebApp diff --git a/src/composables/useWebAppQrScanner.ts b/src/composables-legacy/useWebAppQrScanner.ts similarity index 79% rename from src/composables/useWebAppQrScanner.ts rename to src/composables-legacy/useWebAppQrScanner.ts index 31d9a6b..fedd547 100644 --- a/src/composables/useWebAppQrScanner.ts +++ b/src/composables-legacy/useWebAppQrScanner.ts @@ -1,5 +1,8 @@ import { onQrTextReceived, onScanQrPopupClosed } from '../events' +/** + * @deprecated Use [`useQrScanner`](https://vue-tg.deptyped.com/mini-apps.html#useqrscanner) instead + */ export function useWebAppQrScanner() { const { showScanQrPopup, closeScanQrPopup } = Telegram.WebApp diff --git a/src/composables/useWebAppRequests.ts b/src/composables-legacy/useWebAppRequests.ts similarity index 80% rename from src/composables/useWebAppRequests.ts rename to src/composables-legacy/useWebAppRequests.ts index 3478723..e310ad6 100644 --- a/src/composables/useWebAppRequests.ts +++ b/src/composables-legacy/useWebAppRequests.ts @@ -1,5 +1,8 @@ import { onContactRequested, onWriteAccessRequested } from '../events' +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ export function useWebAppRequests() { const { requestContact, requestWriteAccess } = Telegram.WebApp diff --git a/src/composables/useWebAppSendData.ts b/src/composables-legacy/useWebAppSendData.ts similarity index 100% rename from src/composables/useWebAppSendData.ts rename to src/composables-legacy/useWebAppSendData.ts diff --git a/src/composables/useWebAppSettingsButton.ts b/src/composables-legacy/useWebAppSettingsButton.ts similarity index 91% rename from src/composables/useWebAppSettingsButton.ts rename to src/composables-legacy/useWebAppSettingsButton.ts index 249c96e..55e0da6 100644 --- a/src/composables/useWebAppSettingsButton.ts +++ b/src/composables-legacy/useWebAppSettingsButton.ts @@ -26,6 +26,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useSettingsButton`](https://vue-tg.deptyped.com/mini-apps.html#usesettingsbutton) instead + */ export function useWebAppSettingsButton() { const { isSettingsButtonVisible, showSettingsButton, hideSettingsButton } = useStore() diff --git a/src/composables/useWebAppShare.ts b/src/composables-legacy/useWebAppShare.ts similarity index 75% rename from src/composables/useWebAppShare.ts rename to src/composables-legacy/useWebAppShare.ts index 7bca780..215897a 100644 --- a/src/composables/useWebAppShare.ts +++ b/src/composables-legacy/useWebAppShare.ts @@ -12,6 +12,9 @@ function shareToStory(mediaUrl: string, params?: StoryShareParams) { Telegram.WebApp.shareToStory(mediaUrl, params) } +/** + * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead + */ export function useWebAppShare() { return { shareToStory, diff --git a/src/composables/useWebAppTheme.ts b/src/composables-legacy/useWebAppTheme.ts similarity index 95% rename from src/composables/useWebAppTheme.ts rename to src/composables-legacy/useWebAppTheme.ts index adf673b..d57745c 100644 --- a/src/composables/useWebAppTheme.ts +++ b/src/composables-legacy/useWebAppTheme.ts @@ -42,6 +42,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useTheme`](https://vue-tg.deptyped.com/mini-apps.html#usetheme) instead + */ export function useWebAppTheme() { const { colorScheme, diff --git a/src/composables/useWebAppViewport.ts b/src/composables-legacy/useWebAppViewport.ts similarity index 95% rename from src/composables/useWebAppViewport.ts rename to src/composables-legacy/useWebAppViewport.ts index 1cafab2..30bd627 100644 --- a/src/composables/useWebAppViewport.ts +++ b/src/composables-legacy/useWebAppViewport.ts @@ -46,6 +46,9 @@ const useStore = defineStore(() => { } }) +/** + * @deprecated Use [`useViewport`](https://vue-tg.deptyped.com/mini-apps.html#useviewport) instead + */ export function useWebAppViewport() { const { isExpanded, diff --git a/src/index.ts b/src/index.ts index 3f6bb4e..0f90783 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,23 +32,23 @@ export { 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 { useWebApp } from './composables-legacy/useWebApp' +export { useWebAppBackButton } from './composables-legacy/useWebAppBackButton' +export { useWebAppBiometricManager } from './composables-legacy/useWebAppBiometricManager' +export { useWebAppClipboard } from './composables-legacy/useWebAppClipboard' +export { useWebAppClosingConfirmation } from './composables-legacy/useWebAppClosingConfirmation' +export { useWebAppCloudStorage } from './composables-legacy/useWebAppCloudStorage' +export { useWebAppHapticFeedback } from './composables-legacy/useWebAppHapticFeedback' +export { useWebAppMainButton } from './composables-legacy/useWebAppMainButton' +export { useWebAppNavigation } from './composables-legacy/useWebAppNavigation' +export { useWebAppPopup } from './composables-legacy/useWebAppPopup' +export { useWebAppQrScanner } from './composables-legacy/useWebAppQrScanner' +export { useWebAppRequests } from './composables-legacy/useWebAppRequests' +export { useWebAppSendData } from './composables-legacy/useWebAppSendData' +export { useWebAppSettingsButton } from './composables-legacy/useWebAppSettingsButton' +export { useWebAppShare } from './composables-legacy/useWebAppShare' +export { useWebAppTheme } from './composables-legacy/useWebAppTheme' +export { useWebAppViewport } from './composables-legacy/useWebAppViewport' export * from './events' export type { LoginWidgetUser } from './types' From 3e29f76084a96a40d95006fbeab687cfc1f342ef Mon Sep 17 00:00:00 2001 From: deptyped Date: Sat, 14 Dec 2024 01:46:29 +0200 Subject: [PATCH 03/23] Add types for SDK --- eslint.config.mjs | 1 + package-lock.json | 9 - package.json | 3 - src/components/Popup.vue | 1 + src/composables-legacy/useWebApp.ts | 11 +- src/composables-legacy/useWebAppBackButton.ts | 13 +- .../useWebAppBiometricManager.ts | 31 ++-- src/composables-legacy/useWebAppClipboard.ts | 3 +- .../useWebAppClosingConfirmation.ts | 16 +- .../useWebAppCloudStorage.ts | 26 +-- .../useWebAppHapticFeedback.ts | 4 +- src/composables-legacy/useWebAppMainButton.ts | 57 +++--- src/composables-legacy/useWebAppNavigation.ts | 3 +- src/composables-legacy/useWebAppPopup.ts | 3 +- src/composables-legacy/useWebAppQrScanner.ts | 3 +- src/composables-legacy/useWebAppRequests.ts | 3 +- .../useWebAppSettingsButton.ts | 11 +- src/composables-legacy/useWebAppShare.ts | 16 +- src/composables-legacy/useWebAppTheme.ts | 25 +-- src/composables-legacy/useWebAppViewport.ts | 29 +-- src/events.ts | 166 +++++++++++++++--- src/sdk/accelerometer.ts | 20 +++ src/sdk/back-button.ts | 9 + src/sdk/biometric-manager.ts | 38 ++++ src/sdk/bottom-button.ts | 31 ++++ src/sdk/cloud-storage.ts | 17 ++ src/sdk/device-orientation.ts | 22 +++ src/sdk/events.ts | 93 ++++++++++ src/sdk/gyroscope.ts | 20 +++ src/sdk/haptic-feedback.ts | 9 + src/sdk/index.ts | 25 +++ src/sdk/location-manager.ts | 26 +++ src/sdk/popup.ts | 11 ++ src/sdk/qr-scanner.ts | 3 + src/sdk/settings-button.ts | 9 + src/sdk/theme.ts | 17 ++ src/sdk/viewport.ts | 13 ++ src/sdk/webapp.ts | 161 +++++++++++++++++ src/types.ts | 94 ++-------- 39 files changed, 804 insertions(+), 248 deletions(-) create mode 100644 src/sdk/accelerometer.ts create mode 100644 src/sdk/back-button.ts create mode 100644 src/sdk/biometric-manager.ts create mode 100644 src/sdk/bottom-button.ts create mode 100644 src/sdk/cloud-storage.ts create mode 100644 src/sdk/device-orientation.ts create mode 100644 src/sdk/events.ts create mode 100644 src/sdk/gyroscope.ts create mode 100644 src/sdk/haptic-feedback.ts create mode 100644 src/sdk/index.ts create mode 100644 src/sdk/location-manager.ts create mode 100644 src/sdk/popup.ts create mode 100644 src/sdk/qr-scanner.ts create mode 100644 src/sdk/settings-button.ts create mode 100644 src/sdk/theme.ts create mode 100644 src/sdk/viewport.ts create mode 100644 src/sdk/webapp.ts 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/src/components/Popup.vue b/src/components/Popup.vue index 63da9f8..07c2545 100644 --- a/src/components/Popup.vue +++ b/src/components/Popup.vue @@ -2,6 +2,7 @@ ``` @@ -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 335e81d..d3efcd4 100644 --- a/docs/mini-apps.md +++ b/docs/mini-apps.md @@ -11,53 +11,149 @@ 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) | +| 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 | [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. Generic `onEvent` is also available if you prefer it instead. +| 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 +} +``` + +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: + +```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' @@ -67,31 +163,71 @@ onThemeChanged(() => { }) ``` -#### Mapping +You can also use composables for event handling: -| Event name | Handler | -| ----------------------- | ------------------------- | -| themeChanged | onThemeChanged | -| viewportChanged | onViewportChanged | -| mainButtonClicked | onMainButtonClicked | -| backButtonClicked | onBackButtonClicked | -| settingsButtonClicked | onSettingsButtonClicked | -| invoiceClosed | onInvoiceClosed | -| popupClosed | onPopupClosed | -| qrTextReceived | onQrTextReceived | -| scanQrPopupClosed | onScanQrPopupClosed | -| clipboardTextReceived | onClipboardTextReceived | -| writeAccessRequested | onWriteAccessRequested | -| contactRequested | onContactRequested | -| biometricManagerUpdated | onBiometricManagerUpdated | -| biometricAuthRequested | onBiometricAuthRequested | -| biometricTokenUpdated | onBiometricTokenUpdated | +```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 + +Event handlers automatically unsubscribe when the component unmounts. +However, you can unsubscribe earlier if needed: ```ts{7-8} import { onThemeChanged } from 'vue-tg' @@ -104,9 +240,9 @@ const handler = onThemeChanged(() => { handler.off() ``` -You can also disable automatic unsubscribing completely: +To disable automatic unsubscribing, set manual mode: -```ts{10-11} +```ts import { onThemeChanged } from 'vue-tg' const handler = onThemeChanged( @@ -121,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 @@ -147,6 +283,46 @@ If subscription is not managed properly, it can lead to memory leaks and other i +## Composables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Composables (Legacy) diff --git a/docs/mini-apps/composables-legacy/use-web-app-share.md b/docs/mini-apps/composables-legacy/use-web-app-share.md index 7c50b8b..e9c52e2 100644 --- a/docs/mini-apps/composables-legacy/use-web-app-share.md +++ b/docs/mini-apps/composables-legacy/use-web-app-share.md @@ -11,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-legacy/use-web-app.md b/docs/mini-apps/composables-legacy/use-web-app.md index 76ebc9d..317b2ee 100644 --- a/docs/mini-apps/composables-legacy/use-web-app.md +++ b/docs/mini-apps/composables-legacy/use-web-app.md @@ -1,4 +1,4 @@ -### ~~useWebApp~~ +### ~~useWebApp~~ ::: danger Deprecated Use [useMiniApp](#useminiapp) instead. 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/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/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 index cdd5af9..409fdee 100644 --- a/src/composables-legacy/useWebApp.ts +++ b/src/composables-legacy/useWebApp.ts @@ -1,27 +1,6 @@ -import { readonly, ref } from 'vue' +import { useMiniApp } from '../composables/useMiniApp' import { onEvent } from '../events' -import { WebApp } from '../sdk' - -const isReady = ref(false) - -const ready: typeof WebApp.ready = (...params) => { - WebApp.ready(...params) - isReady.value = true -} - -function isPlatform(name: - | (string & Record) - | 'unknown' - | 'android' - | 'android_x' - | 'ios' - | 'macos' - | 'tdesktop' - | 'weba' - | 'webk' - | 'unigram') { - return WebApp.platform === name -} +import { getWebApp } from '../sdk' const featureSupportVersion = { ClosingConfirmation: '6.2', @@ -33,22 +12,25 @@ const featureSupportVersion = { DisableVerticalSwipes: '7.7', } function isFeatureSupported(name: keyof typeof featureSupportVersion) { - return WebApp.isVersionAtLeast(featureSupportVersion[name]) + 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, - isVersionAtLeast, + isPlatform, sendData, + ready, close, - } = WebApp + } = useMiniApp({ version: '8.0' }) const isPlatformUnknown = isPlatform('unknown') @@ -59,11 +41,11 @@ export function useWebApp() { initDataUnsafe, version, platform, - isVersionAtLeast, + isVersionAtLeast: webApp.isVersionAtLeast, sendData, ready, close, - isReady: readonly(isReady), + isReady, isPlatform, isPlatformUnknown, isFeatureSupported, diff --git a/src/composables-legacy/useWebAppClosingConfirmation.ts b/src/composables-legacy/useWebAppClosingConfirmation.ts index 2d7f906..56b02f0 100644 --- a/src/composables-legacy/useWebAppClosingConfirmation.ts +++ b/src/composables-legacy/useWebAppClosingConfirmation.ts @@ -1,56 +1,18 @@ -import { computed, ref } from 'vue' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isClosingConfirmationEnabled = ref(WebApp.isClosingConfirmationEnabled) - - function updateStatus() { - isClosingConfirmationEnabled.value = WebApp.isClosingConfirmationEnabled - } - - function enableClosingConfirmation( - ...params: Parameters - ) { - WebApp.enableClosingConfirmation(...params) - updateStatus() - } - - function disableClosingConfirmation( - ...params: Parameters - ) { - WebApp.disableClosingConfirmation(...params) - updateStatus() - } - - return { - isClosingConfirmationEnabled, - updateStatus, - enableClosingConfirmation, - disableClosingConfirmation, - } -}) +import { useMiniApp } from '../composables/useMiniApp' /** * @deprecated Use [`useClosingConfirmation`](https://vue-tg.deptyped.com/mini-apps.html#useclosingconfirmation) instead */ export function useWebAppClosingConfirmation() { - const { - isClosingConfirmationEnabled, - enableClosingConfirmation, - disableClosingConfirmation, - } = useStore() + const { isClosingConfirmationEnabled } = useMiniApp({ version: '8.0' }) return { - isClosingConfirmationEnabled: computed({ - get() { - return isClosingConfirmationEnabled.value - }, - set(isEnabled) { - isEnabled ? enableClosingConfirmation() : disableClosingConfirmation() - }, - }), - enableClosingConfirmation, - disableClosingConfirmation, + isClosingConfirmationEnabled, + enableClosingConfirmation() { + isClosingConfirmationEnabled.value = true + }, + disableClosingConfirmation() { + isClosingConfirmationEnabled.value = false + }, } } diff --git a/src/composables-legacy/useWebAppNavigation.ts b/src/composables-legacy/useWebAppNavigation.ts index 71e5cf1..2a3a107 100644 --- a/src/composables-legacy/useWebAppNavigation.ts +++ b/src/composables-legacy/useWebAppNavigation.ts @@ -1,12 +1,11 @@ +import { useMiniApp } from '../composables/useMiniApp' import { onInvoiceClosed } from '../events' -import { WebApp } from '../sdk' /** * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead */ export function useWebAppNavigation() { - const { switchInlineQuery, openLink, openTelegramLink, openInvoice } - = WebApp + const { switchInlineQuery, openLink, openTelegramLink, openInvoice } = useMiniApp({ version: '8.0' }) return { switchInlineQuery, diff --git a/src/composables-legacy/useWebAppRequests.ts b/src/composables-legacy/useWebAppRequests.ts index f6f3b6d..c5c44e6 100644 --- a/src/composables-legacy/useWebAppRequests.ts +++ b/src/composables-legacy/useWebAppRequests.ts @@ -1,11 +1,11 @@ +import { useMiniApp } from '../composables/useMiniApp' import { onContactRequested, onWriteAccessRequested } from '../events' -import { WebApp } from '../sdk' /** * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead */ export function useWebAppRequests() { - const { requestContact, requestWriteAccess } = WebApp + const { requestContact, requestWriteAccess } = useMiniApp({ version: '8.0' }) return { requestContact, diff --git a/src/composables-legacy/useWebAppSendData.ts b/src/composables-legacy/useWebAppSendData.ts index bd2f279..c81cc8d 100644 --- a/src/composables-legacy/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/useWebAppShare.ts b/src/composables-legacy/useWebAppShare.ts index d3bd997..cc5b82f 100644 --- a/src/composables-legacy/useWebAppShare.ts +++ b/src/composables-legacy/useWebAppShare.ts @@ -1,10 +1,10 @@ -import { WebApp } from '../sdk' +import { useMiniApp } from '../composables/useMiniApp' /** * @deprecated Use [`useMiniApp`](https://vue-tg.deptyped.com/mini-apps.html#useminiapp) instead */ export function useWebAppShare() { - const { shareToStory } = WebApp + const { shareToStory } = useMiniApp({ version: '8.0' }) return { shareToStory, 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/events.ts b/src/events.ts index 071fcd7..fb56b30 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,7 +1,7 @@ import type { EventCallback } from './sdk' import type { OnEventOptions, OnEventWithOptions } from './types' import { onMounted, onUnmounted } from 'vue' -import { WebApp } from './sdk' +import { getWebApp } from './sdk' export const onEvent: OnEventWithOptions = ( eventType, @@ -9,11 +9,12 @@ export const onEvent: OnEventWithOptions = ( options = { manual: false }, ) => { const { manual } = options + const webApp = getWebApp() const on = () => - WebApp.onEvent(eventType, eventHandler) + webApp.onEvent(eventType, eventHandler) const off = () => - WebApp.offEvent(eventType, eventHandler) + webApp.offEvent(eventType, eventHandler) if (manual) { on() diff --git a/src/index.ts b/src/index.ts index 0f90783..723c969 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,11 +10,39 @@ import MainButton from './components/MainButton.vue' import Popup from './components/Popup.vue' import ScanQr from './components/ScanQr.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, @@ -32,26 +60,6 @@ export { ShareWidget, } -export { useWebApp } from './composables-legacy/useWebApp' -export { useWebAppBackButton } from './composables-legacy/useWebAppBackButton' -export { useWebAppBiometricManager } from './composables-legacy/useWebAppBiometricManager' -export { useWebAppClipboard } from './composables-legacy/useWebAppClipboard' -export { useWebAppClosingConfirmation } from './composables-legacy/useWebAppClosingConfirmation' -export { useWebAppCloudStorage } from './composables-legacy/useWebAppCloudStorage' -export { useWebAppHapticFeedback } from './composables-legacy/useWebAppHapticFeedback' -export { useWebAppMainButton } from './composables-legacy/useWebAppMainButton' -export { useWebAppNavigation } from './composables-legacy/useWebAppNavigation' -export { useWebAppPopup } from './composables-legacy/useWebAppPopup' -export { useWebAppQrScanner } from './composables-legacy/useWebAppQrScanner' -export { useWebAppRequests } from './composables-legacy/useWebAppRequests' -export { useWebAppSendData } from './composables-legacy/useWebAppSendData' -export { useWebAppSettingsButton } from './composables-legacy/useWebAppSettingsButton' -export { useWebAppShare } from './composables-legacy/useWebAppShare' -export { useWebAppTheme } from './composables-legacy/useWebAppTheme' -export { useWebAppViewport } from './composables-legacy/useWebAppViewport' -export * from './events' -export type { LoginWidgetUser } from './types' - const plugin = { install(Vue: App) { Vue.component('TgAlert', Alert) diff --git a/src/types.ts b/src/types.ts index 20eddc1..4bdddab 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,65 @@ 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 */ 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/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'], From ad538e58459f7c6b19b4d7c8c4e561ddd7ecd6ff Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:19:25 +0200 Subject: [PATCH 05/23] Implement useBackButton --- docs/mini-apps/composables/use-back-button.md | 16 +++ src/composables-legacy/useWebAppBackButton.ts | 43 +------ src/composables/useBackButton.ts | 106 ++++++++++++++++++ 3 files changed, 127 insertions(+), 38 deletions(-) create mode 100644 docs/mini-apps/composables/use-back-button.md create mode 100644 src/composables/useBackButton.ts 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/src/composables-legacy/useWebAppBackButton.ts b/src/composables-legacy/useWebAppBackButton.ts index 62c343e..a694a99 100644 --- a/src/composables-legacy/useWebAppBackButton.ts +++ b/src/composables-legacy/useWebAppBackButton.ts @@ -1,49 +1,16 @@ -import { computed, ref } from 'vue' +import { useBackButton } from '../composables/useBackButton' import { onBackButtonClicked } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isBackButtonVisible = ref(WebApp.BackButton.isVisible) - - function updateState() { - isBackButtonVisible.value = WebApp.BackButton.isVisible - } - - function showBackButton( - ...params: Parameters - ) { - WebApp.BackButton.show(...params) - updateState() - } - - function hideBackButton( - ...params: Parameters - ) { - WebApp.BackButton.hide(...params) - updateState() - } - - return { isBackButtonVisible, showBackButton, hideBackButton } -}) /** * @deprecated Use [`useBackButton`](https://vue-tg.deptyped.com/mini-apps.html#usebackbutton) instead */ export function useWebAppBackButton() { - const { isBackButtonVisible, showBackButton, hideBackButton } = useStore() + const backButton = useBackButton({ version: '8.0' }) return { - isBackButtonVisible: computed({ - get() { - return isBackButtonVisible.value - }, - set(isVisible) { - isVisible ? showBackButton() : hideBackButton() - }, - }), - showBackButton, - hideBackButton, + isBackButtonVisible: backButton.isVisible, + showBackButton: backButton.show, + hideBackButton: backButton.hide, /** * @deprecated import directly from `vue-tg` instead. */ 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 +} From d6557c47eebef325e532fbd36ced7af0c955f095 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:19:57 +0200 Subject: [PATCH 06/23] Implement useBiometricManager --- .../composables/use-biometric-manager.md | 27 +++ .../useWebAppBiometricManager.ts | 83 ++------- src/composables/useBiometricManager.ts | 171 ++++++++++++++++++ 3 files changed, 214 insertions(+), 67 deletions(-) create mode 100644 docs/mini-apps/composables/use-biometric-manager.md create mode 100644 src/composables/useBiometricManager.ts 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/src/composables-legacy/useWebAppBiometricManager.ts b/src/composables-legacy/useWebAppBiometricManager.ts index 9b82ef0..bac1251 100644 --- a/src/composables-legacy/useWebAppBiometricManager.ts +++ b/src/composables-legacy/useWebAppBiometricManager.ts @@ -1,88 +1,37 @@ -import { readonly, ref } from 'vue' +import { useBiometricManager } from '../composables/useBiometricManager' import { onBiometricAuthRequested, onBiometricManagerUpdated, onBiometricTokenUpdated } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isBiometricInited = ref(WebApp.BiometricManager.isInited) - const isBiometricAvailable = ref( - WebApp.BiometricManager.isBiometricAvailable, - ) - const biometricType = ref(WebApp.BiometricManager.biometricType) - const isBiometricAccessRequested = ref( - WebApp.BiometricManager.isAccessRequested, - ) - const isBiometricAccessGranted = ref( - WebApp.BiometricManager.isAccessGranted, - ) - const isBiometricTokenSaved = ref( - WebApp.BiometricManager.isAccessGranted, - ) - const biometricDeviceId = ref(WebApp.BiometricManager.deviceId) - - function updateState() { - isBiometricInited.value = WebApp.BiometricManager.isInited - isBiometricAvailable.value - = WebApp.BiometricManager.isBiometricAvailable - biometricType.value = WebApp.BiometricManager.biometricType - isBiometricAccessRequested.value - = WebApp.BiometricManager.isAccessRequested - isBiometricAccessGranted.value - = WebApp.BiometricManager.isAccessGranted - biometricDeviceId.value = WebApp.BiometricManager.deviceId - isBiometricTokenSaved.value - = WebApp.BiometricManager.isBiometricTokenSaved - } - - return { - isBiometricInited, - isBiometricAvailable, - biometricType, - isBiometricAccessRequested, - isBiometricAccessGranted, - biometricDeviceId, - isBiometricTokenSaved, - updateState, - } -}) /** * @deprecated Use [`useBiometricManager`](https://vue-tg.deptyped.com/mini-apps.html#usebiometricmanager) instead */ export function useWebAppBiometricManager() { const { - isBiometricInited, + isInited, isBiometricAvailable, biometricType, - isBiometricAccessRequested, - isBiometricAccessGranted, - biometricDeviceId, + isAccessRequested, + isAccessGranted, + deviceId, isBiometricTokenSaved, - updateState, - } = useStore() - - onBiometricManagerUpdated(updateState) - - const { init, - requestAccess, authenticate, - updateBiometricToken, + requestAccess, openSettings, - } = WebApp.BiometricManager + updateToken, + } = useBiometricManager({ version: '8.0' }) return { - isBiometricInited: readonly(isBiometricInited), - isBiometricAvailable: readonly(isBiometricAvailable), - biometricType: readonly(biometricType), - isBiometricAccessRequested: readonly(isBiometricAccessRequested), - isBiometricAccessGranted: readonly(isBiometricAccessGranted), - isBiometricTokenSaved: readonly(isBiometricTokenSaved), - biometricDeviceId: readonly(biometricDeviceId), + isBiometricInited: isInited, + isBiometricAvailable, + biometricType, + isBiometricAccessRequested: isAccessRequested, + isBiometricAccessGranted: isAccessGranted, + isBiometricTokenSaved, + biometricDeviceId: deviceId, initBiometric: init, requestBiometricAccess: requestAccess, authenticateBiometric: authenticate, - updateBiometricToken, + updateBiometricToken: updateToken, openBiometricSettings: openSettings, /** * @deprecated import directly from `vue-tg` instead. 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 +} From d336e512f7c6fd9d13ebaeaa44478c1d04cecf55 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:20:45 +0200 Subject: [PATCH 07/23] Implement useClipboard --- docs/mini-apps/composables/use-clipboard.md | 14 ++++ src/composables-legacy/useWebAppClipboard.ts | 6 +- src/composables/useClipboard.ts | 71 ++++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 docs/mini-apps/composables/use-clipboard.md create mode 100644 src/composables/useClipboard.ts 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/src/composables-legacy/useWebAppClipboard.ts b/src/composables-legacy/useWebAppClipboard.ts index cdbc6e1..bab2f40 100644 --- a/src/composables-legacy/useWebAppClipboard.ts +++ b/src/composables-legacy/useWebAppClipboard.ts @@ -1,14 +1,14 @@ +import { useClipboard } from '../composables/useClipboard' import { onClipboardTextReceived } from '../events' -import { WebApp } from '../sdk' /** * @deprecated Use [`useClipboard`](https://vue-tg.deptyped.com/mini-apps.html#useclipboard) instead */ export function useWebAppClipboard() { - const { readTextFromClipboard } = WebApp + const { readText } = useClipboard({ version: '8.0' }) return { - readTextFromClipboard, + readTextFromClipboard: readText, /** * @deprecated import directly from `vue-tg` instead. */ 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 +} From 2a755e961c0b525660c9ed5364429e81c8f52edf Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:21:03 +0200 Subject: [PATCH 08/23] Implement useCloudStorage --- .../composables/use-cloud-storage.md | 18 +++ .../useWebAppCloudStorage.ts | 122 ++--------------- src/composables/useCloudStorage.ts | 129 ++++++++++++++++++ 3 files changed, 156 insertions(+), 113 deletions(-) create mode 100644 docs/mini-apps/composables/use-cloud-storage.md create mode 100644 src/composables/useCloudStorage.ts 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/src/composables-legacy/useWebAppCloudStorage.ts b/src/composables-legacy/useWebAppCloudStorage.ts index c66ff09..04f2019 100644 --- a/src/composables-legacy/useWebAppCloudStorage.ts +++ b/src/composables-legacy/useWebAppCloudStorage.ts @@ -1,121 +1,17 @@ -import { WebApp } from '../sdk' - -type SetItemResult = Parameters< - NonNullable< - NonNullable>[2] - > ->[1] - -function setStorageItem(key: string, value: string) { - return new Promise((resolve, reject) => { - 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) => { - 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) => { - 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) => { - 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) => { - 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) => { - WebApp.CloudStorage.getKeys((error, values) => { - if (error) - reject(error) - - resolve(values as GetKeysResult) - }) - }) -} +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, - getStorageItem, - getStorageItems, - removeStorageItem, - removeStorageItems, - getStorageKeys, + setStorageItem: cloudStorage.setItem, + getStorageItem: cloudStorage.getItem, + getStorageItems: cloudStorage.getItems, + removeStorageItem: cloudStorage.removeItem, + removeStorageItems: cloudStorage.removeItems, + getStorageKeys: cloudStorage.getKeys, } } 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 +} From e576597e85ce01de0935b48dd940c5edbb99e17c Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:21:20 +0200 Subject: [PATCH 09/23] Implement useHapticFeedback --- .../composables/use-haptic-feedback.md | 15 ++++ .../useWebAppHapticFeedback.ts | 5 +- src/composables/useHapticFeedback.ts | 69 +++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 docs/mini-apps/composables/use-haptic-feedback.md create mode 100644 src/composables/useHapticFeedback.ts 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/src/composables-legacy/useWebAppHapticFeedback.ts b/src/composables-legacy/useWebAppHapticFeedback.ts index 6c4ea16..4f4dceb 100644 --- a/src/composables-legacy/useWebAppHapticFeedback.ts +++ b/src/composables-legacy/useWebAppHapticFeedback.ts @@ -1,11 +1,10 @@ -import { WebApp } from '../sdk' +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 } - = WebApp.HapticFeedback + const { impactOccurred, notificationOccurred, selectionChanged } = useHapticFeedback({ version: '8.0' }) return { impactOccurred, 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 +} From 42367316b36f23a8ec1f1e0db9f69a3831e310b3 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:21:33 +0200 Subject: [PATCH 10/23] Implement useMainButton --- docs/mini-apps/composables/use-main-button.md | 27 +++ src/composables-legacy/useWebAppMainButton.ts | 192 ++------------- src/composables/useMainButton.ts | 225 ++++++++++++++++++ 3 files changed, 271 insertions(+), 173 deletions(-) create mode 100644 docs/mini-apps/composables/use-main-button.md create mode 100644 src/composables/useMainButton.ts 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/src/composables-legacy/useWebAppMainButton.ts b/src/composables-legacy/useWebAppMainButton.ts index 6418a6e..f1359b8 100644 --- a/src/composables-legacy/useWebAppMainButton.ts +++ b/src/composables-legacy/useWebAppMainButton.ts @@ -1,184 +1,30 @@ -import { computed, ref } from 'vue' +import type { WebApp } from '../sdk' +import { useMainButton } from '../composables/useMainButton' import { onMainButtonClicked } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const mainButtonText = ref(WebApp.MainButton.text) - const mainButtonColor = ref(WebApp.MainButton.color) - const mainButtonTextColor = ref(WebApp.MainButton.textColor) - const isMainButtonVisible = ref(WebApp.MainButton.isVisible) - const isMainButtonActive = ref(WebApp.MainButton.isActive) - const isMainButtonProgressVisible = ref( - WebApp.MainButton.isProgressVisible, - ) - - function updateState() { - mainButtonText.value = WebApp.MainButton.text - mainButtonColor.value = WebApp.MainButton.color - mainButtonTextColor.value = WebApp.MainButton.textColor - isMainButtonVisible.value = WebApp.MainButton.isVisible - isMainButtonActive.value = WebApp.MainButton.isActive - isMainButtonProgressVisible.value - = WebApp.MainButton.isProgressVisible - } - - function setMainButtonText( - ...params: Parameters - ) { - WebApp.MainButton.setText(...params) - updateState() - } - - function showMainButton( - ...params: Parameters - ) { - WebApp.MainButton.show(...params) - updateState() - } - - function hideMainButton( - ...params: Parameters - ) { - WebApp.MainButton.hide(...params) - updateState() - } - - function enableMainButton( - ...params: Parameters - ) { - WebApp.MainButton.enable(...params) - updateState() - } - - function disableMainButton( - ...params: Parameters - ) { - WebApp.MainButton.disable(...params) - updateState() - } - - function showMainButtonProgress( - ...params: Parameters - ) { - WebApp.MainButton.showProgress(...params) - updateState() - } - - function hideMainButtonProgress( - ...params: Parameters - ) { - WebApp.MainButton.hideProgress(...params) - updateState() - } - - function setMainButtonParams( - ...params: Parameters - ) { - WebApp.MainButton.setParams(...params) - updateState() - } - - return { - mainButtonText, - mainButtonColor, - mainButtonTextColor, - isMainButtonVisible, - isMainButtonActive, - isMainButtonProgressVisible, - setMainButtonText, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, - } -}) /** * @deprecated Use [`useMainButton`](https://vue-tg.deptyped.com/mini-apps.html#usemainbutton) instead */ export function useWebAppMainButton() { - const { - mainButtonText, - mainButtonColor, - mainButtonTextColor, - isMainButtonVisible, - isMainButtonActive, - isMainButtonProgressVisible, - setMainButtonText, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, - } = useStore() + const mainButton = useMainButton({ version: '8.0' }) 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, - showMainButton, - hideMainButton, - enableMainButton, - disableMainButton, - showMainButtonProgress, - hideMainButtonProgress, - setMainButtonParams, + 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. */ 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 +} From 5e0d769b8882d43cba4ea35629ffe8ba3358785f Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:21:45 +0200 Subject: [PATCH 11/23] Implement usePopup --- docs/mini-apps/composables/use-popup.md | 16 ++++ src/composables-legacy/useWebAppPopup.ts | 4 +- src/composables/usePopup.ts | 98 ++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 docs/mini-apps/composables/use-popup.md create mode 100644 src/composables/usePopup.ts 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/src/composables-legacy/useWebAppPopup.ts b/src/composables-legacy/useWebAppPopup.ts index a5e4f71..0a98447 100644 --- a/src/composables-legacy/useWebAppPopup.ts +++ b/src/composables-legacy/useWebAppPopup.ts @@ -1,11 +1,11 @@ +import { usePopup } from '../composables/usePopup' import { onPopupClosed } from '../events' -import { WebApp } from '../sdk' /** * @deprecated Use [`usePopup`](https://vue-tg.deptyped.com/mini-apps.html#usepopup) instead */ export function useWebAppPopup() { - const { showPopup, showAlert, showConfirm } = WebApp + const { showPopup, showAlert, showConfirm } = usePopup({ version: '8.0' }) return { showPopup, 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 +} From e4e4431eb3b5cc856580b2d0803409579104b709 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:22:01 +0200 Subject: [PATCH 12/23] Implement useQrScanner --- docs/mini-apps/composables/use-qr-scanner.md | 16 +++++ src/composables-legacy/useWebAppQrScanner.ts | 8 +-- src/composables/useQrScanner.ts | 73 ++++++++++++++++++++ 3 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 docs/mini-apps/composables/use-qr-scanner.md create mode 100644 src/composables/useQrScanner.ts 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/src/composables-legacy/useWebAppQrScanner.ts b/src/composables-legacy/useWebAppQrScanner.ts index a186dff..ea827f6 100644 --- a/src/composables-legacy/useWebAppQrScanner.ts +++ b/src/composables-legacy/useWebAppQrScanner.ts @@ -1,15 +1,15 @@ +import { useQrScanner } from '../composables/useQrScanner' import { onQrTextReceived, onScanQrPopupClosed } from '../events' -import { WebApp } from '../sdk' /** * @deprecated Use [`useQrScanner`](https://vue-tg.deptyped.com/mini-apps.html#useqrscanner) instead */ export function useWebAppQrScanner() { - const { showScanQrPopup, closeScanQrPopup } = WebApp + const qrScanner = useQrScanner({ version: '8.0' }) return { - showScanQrPopup, - closeScanQrPopup, + showScanQrPopup: qrScanner.show, + closeScanQrPopup: qrScanner.close, /** * @deprecated import directly from `vue-tg` instead. */ 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 +} From d9142f9556e3ce75ace6dbeee7ac1f9ce86f81fc Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:22:19 +0200 Subject: [PATCH 13/23] Implement useSettingsButton --- .../composables/use-settings-button.md | 16 +++ .../useWebAppSettingsButton.ts | 44 +------ src/composables/useSettingsButton.ts | 111 ++++++++++++++++++ 3 files changed, 132 insertions(+), 39 deletions(-) create mode 100644 docs/mini-apps/composables/use-settings-button.md create mode 100644 src/composables/useSettingsButton.ts 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/src/composables-legacy/useWebAppSettingsButton.ts b/src/composables-legacy/useWebAppSettingsButton.ts index 21d8f9e..a66f443 100644 --- a/src/composables-legacy/useWebAppSettingsButton.ts +++ b/src/composables-legacy/useWebAppSettingsButton.ts @@ -1,50 +1,16 @@ -import { computed, ref } from 'vue' +import { useSettingsButton } from '../composables/useSettingsButton' import { onSettingsButtonClicked } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isSettingsButtonVisible = ref(WebApp.SettingsButton.isVisible) - - function showSettingsButton( - ...params: Parameters - ) { - WebApp.SettingsButton.show(...params) - isSettingsButtonVisible.value = true - } - - function hideSettingsButton( - ...params: Parameters - ) { - WebApp.SettingsButton.hide(...params) - isSettingsButtonVisible.value = false - } - - return { - isSettingsButtonVisible, - showSettingsButton, - hideSettingsButton, - } -}) /** * @deprecated Use [`useSettingsButton`](https://vue-tg.deptyped.com/mini-apps.html#usesettingsbutton) instead */ export function useWebAppSettingsButton() { - const { isSettingsButtonVisible, showSettingsButton, hideSettingsButton } - = useStore() + const settingsButton = useSettingsButton({ version: '8.0' }) return { - isSettingsButtonVisible: computed({ - get() { - return isSettingsButtonVisible.value - }, - set(isVisible) { - isVisible ? showSettingsButton() : hideSettingsButton() - }, - }), - showSettingsButton, - hideSettingsButton, + isSettingsButtonVisible: settingsButton.isVisible, + showSettingsButton: settingsButton.show, + hideSettingsButton: settingsButton.hide, /** * @deprecated import directly from `vue-tg` instead. */ 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 +} From 1c4cb8097acd39fbe14074c44c7555f9e2fd7b08 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:22:32 +0200 Subject: [PATCH 14/23] Implement useTheme --- docs/mini-apps/composables/use-theme.md | 18 +++ src/composables-legacy/useWebAppTheme.ts | 82 ++--------- src/composables/useTheme.ts | 166 +++++++++++++++++++++++ 3 files changed, 197 insertions(+), 69 deletions(-) create mode 100644 docs/mini-apps/composables/use-theme.md create mode 100644 src/composables/useTheme.ts 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/src/composables-legacy/useWebAppTheme.ts b/src/composables-legacy/useWebAppTheme.ts index fbdae9f..77b7ddb 100644 --- a/src/composables-legacy/useWebAppTheme.ts +++ b/src/composables-legacy/useWebAppTheme.ts @@ -1,47 +1,6 @@ -import { computed, readonly, ref } from 'vue' +import type { WebApp } from '../sdk' +import { useTheme } from '../composables/useTheme' import { onThemeChanged } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const colorScheme = ref(WebApp.colorScheme) - const themeParams = ref(WebApp.themeParams) - const headerColor = ref(WebApp.headerColor) - const backgroundColor = ref(WebApp.backgroundColor) - - function updateState() { - colorScheme.value = WebApp.colorScheme - themeParams.value = { - ...WebApp.themeParams, - } - headerColor.value = WebApp.headerColor - backgroundColor.value = WebApp.backgroundColor - } - - function setHeaderColor( - ...params: Parameters - ) { - WebApp.setHeaderColor(...params) - updateState() - } - - function setBackgroundColor( - ...params: Parameters - ) { - WebApp.setBackgroundColor(...params) - updateState() - } - - return { - colorScheme, - themeParams, - headerColor, - backgroundColor, - updateState, - setHeaderColor, - setBackgroundColor, - } -}) /** * @deprecated Use [`useTheme`](https://vue-tg.deptyped.com/mini-apps.html#usetheme) instead @@ -52,34 +11,19 @@ export function useWebAppTheme() { themeParams, headerColor, backgroundColor, - updateState, - setHeaderColor, - setBackgroundColor, - } = useStore() - - onThemeChanged(updateState) + } = useTheme({ version: '8.0' }) 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, + 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. */ 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 +} From 7795eeaddcdec0878dc087f3a3eb2eb0e9d97ea3 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:22:40 +0200 Subject: [PATCH 15/23] Implement useViewport --- docs/mini-apps/composables/use-viewport.md | 26 +++ src/composables-legacy/useWebAppViewport.ts | 80 ++----- src/composables/useViewport.ts | 218 ++++++++++++++++++++ 3 files changed, 257 insertions(+), 67 deletions(-) create mode 100644 docs/mini-apps/composables/use-viewport.md create mode 100644 src/composables/useViewport.ts 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/src/composables-legacy/useWebAppViewport.ts b/src/composables-legacy/useWebAppViewport.ts index 2be6740..c49a0a0 100644 --- a/src/composables-legacy/useWebAppViewport.ts +++ b/src/composables-legacy/useWebAppViewport.ts @@ -1,51 +1,5 @@ -import { computed, readonly, ref } from 'vue' +import { useViewport } from '../composables/useViewport' import { onViewportChanged } from '../events' -import { WebApp } from '../sdk' -import { defineStore } from '../utils' - -const useStore = defineStore(() => { - const isExpanded = ref(WebApp.isExpanded) - const viewportHeight = ref(WebApp.viewportHeight) - const viewportStableHeight = ref(WebApp.viewportStableHeight) - const isVerticalSwipesEnabled = ref(WebApp.isVerticalSwipesEnabled) - - function updateState() { - isExpanded.value = WebApp.isExpanded - viewportHeight.value = WebApp.viewportHeight - viewportStableHeight.value = WebApp.viewportStableHeight - isVerticalSwipesEnabled.value = WebApp.isVerticalSwipesEnabled - } - - function expand(...params: Parameters) { - WebApp.expand(...params) - updateState() - } - - const enableVerticalSwipes: typeof WebApp.enableVerticalSwipes = ( - ...params - ) => { - WebApp.enableVerticalSwipes(...params) - updateState() - } - - const disableVerticalSwipes: typeof WebApp.disableVerticalSwipes = ( - ...params - ) => { - WebApp.disableVerticalSwipes(...params) - updateState() - } - - return { - isExpanded, - viewportHeight, - viewportStableHeight, - isVerticalSwipesEnabled, - updateState, - expand, - enableVerticalSwipes, - disableVerticalSwipes, - } -}) /** * @deprecated Use [`useViewport`](https://vue-tg.deptyped.com/mini-apps.html#useviewport) instead @@ -53,32 +7,24 @@ const useStore = defineStore(() => { export function useWebAppViewport() { const { isExpanded, + expand, viewportHeight, viewportStableHeight, isVerticalSwipesEnabled, - updateState, - expand, - enableVerticalSwipes, - disableVerticalSwipes, - } = useStore() - - onViewportChanged(updateState) + } = useViewport({ version: '8.0' }) return { - isExpanded: readonly(isExpanded), - viewportHeight: readonly(viewportHeight), - viewportStableHeight: readonly(viewportStableHeight), + isExpanded, + viewportHeight, + viewportStableHeight, expand, - isVerticalSwipesEnabled: computed({ - get() { - return isVerticalSwipesEnabled.value - }, - set(isEnabled) { - isEnabled ? enableVerticalSwipes() : disableVerticalSwipes() - }, - }), - enableVerticalSwipes, - disableVerticalSwipes, + isVerticalSwipesEnabled, + enableVerticalSwipes() { + isVerticalSwipesEnabled.value = true + }, + disableVerticalSwipes() { + isVerticalSwipesEnabled.value = false + }, /** * @deprecated import directly from `vue-tg` instead. */ 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 +} From 057d8eb98c64a05b2633aff0bc84f757a95e2da8 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:22:58 +0200 Subject: [PATCH 16/23] Implement useAccelerometer --- .../composables/use-accelerometer.md | 22 +++ src/composables/useAccelerometer.ts | 126 ++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 docs/mini-apps/composables/use-accelerometer.md create mode 100644 src/composables/useAccelerometer.ts 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/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 +} From 65d6f606c56d778fc39320bd1590ab1121539e7a Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:23:18 +0200 Subject: [PATCH 17/23] Implement useDeviceOrientation --- .../composables/use-device-orientation.md | 23 +++ src/composables/useDeviceOrientation.ts | 138 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 docs/mini-apps/composables/use-device-orientation.md create mode 100644 src/composables/useDeviceOrientation.ts 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/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 +} From c51a0c87dd2cbc2fdc0c3d39c69a8849f1d17d55 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:23:33 +0200 Subject: [PATCH 18/23] Implement useEmojiStatus --- .../mini-apps/composables/use-emoji-status.md | 17 ++++ src/composables/useEmojiStatus.ts | 92 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 docs/mini-apps/composables/use-emoji-status.md create mode 100644 src/composables/useEmojiStatus.ts 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/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 +} From 02b2c6cc0463aa60e83539da2be5bd0e53826a22 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:23:44 +0200 Subject: [PATCH 19/23] Implement useGyroscope --- docs/mini-apps/composables/use-gyroscope.md | 22 ++++ src/composables/useGyroscope.ts | 126 ++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 docs/mini-apps/composables/use-gyroscope.md create mode 100644 src/composables/useGyroscope.ts 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/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 +} From 1ad68e5cfcebae5f1a8ee48721790ecab7476d86 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:24:14 +0200 Subject: [PATCH 20/23] Implement useHomeScreen --- docs/mini-apps/composables/use-home-screen.md | 16 ++++ src/composables/useHomeScreen.ts | 78 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 docs/mini-apps/composables/use-home-screen.md create mode 100644 src/composables/useHomeScreen.ts 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/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 +} From 151cb7e8ae38cd1c3f4e6dc1a8503be3fdf6e194 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:24:26 +0200 Subject: [PATCH 21/23] Implement useLocationManager --- .../composables/use-location-manager.md | 21 +++ src/composables/useLocationManager.ts | 134 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 docs/mini-apps/composables/use-location-manager.md create mode 100644 src/composables/useLocationManager.ts 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/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 +} From 0404a4c9586ce75b3a62bff890e9c15cbce68bd1 Mon Sep 17 00:00:00 2001 From: deptyped Date: Fri, 27 Dec 2024 21:24:38 +0200 Subject: [PATCH 22/23] Implement useSecondaryButton --- .../composables/use-secondary-button.md | 28 +++ src/composables/useSecondaryButton.ts | 233 ++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 docs/mini-apps/composables/use-secondary-button.md create mode 100644 src/composables/useSecondaryButton.ts 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/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 +} From b6780c0b75d08ecf3bab7f6c6e418c1aac059346 Mon Sep 17 00:00:00 2001 From: deptyped Date: Sat, 28 Dec 2024 08:30:02 +0200 Subject: [PATCH 23/23] Update components --- docs/mini-apps.md | 2 + docs/mini-apps/components/main-button.md | 17 +-- docs/mini-apps/components/secondary-button.md | 36 ++++++ src/components/Alert.vue | 10 +- src/components/BackButton.vue | 28 +++-- src/components/BiometricManager.vue | 8 +- src/components/ClosingConfirmation.vue | 15 ++- src/components/Confirm.vue | 8 +- src/components/ExpandedViewport.vue | 17 ++- src/components/MainButton.vue | 49 +++++--- src/components/Popup.vue | 26 ++-- src/components/ScanQr.vue | 26 ++-- src/components/SecondaryButton.vue | 118 ++++++++++++++++++ src/components/SettingsButton.vue | 41 +++--- src/index.ts | 4 + 15 files changed, 304 insertions(+), 101 deletions(-) create mode 100644 docs/mini-apps/components/secondary-button.md create mode 100644 src/components/SecondaryButton.vue diff --git a/docs/mini-apps.md b/docs/mini-apps.md index d3efcd4..1472f8c 100644 --- a/docs/mini-apps.md +++ b/docs/mini-apps.md @@ -281,6 +281,8 @@ Improper management may lead to memory leaks or other issues. + + ## Composables 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/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 07c2545..a953718 100644 --- a/src/components/Popup.vue +++ b/src/components/Popup.vue @@ -4,7 +4,7 @@ import type { PropType } from 'vue' import type { PopupButton } from '../sdk' import { onMounted } from 'vue' -import { useWebAppPopup } from '..' +import { usePopup } from '../composables/usePopup' const props = defineProps({ title: { type: String }, @@ -15,16 +15,18 @@ const emit = defineEmits<{ (eventName: 'close', buttonId: string): void }>() -const { showPopup } = useWebAppPopup() +const popup = usePopup({ version: '6.0' }) -onMounted(() => - showPopup( - { - title: props.title, - message: props.message, - buttons: props.buttons, - }, - buttonId => emit('close', buttonId), - ), -) +if (popup.isVersionAtLeast('6.2')) { + onMounted(() => + popup.showPopup( + { + title: props.title, + message: props.message, + buttons: props.buttons, + }, + buttonId => emit('close', buttonId), + ), + ) +} 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/index.ts b/src/index.ts index 723c969..288bab0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ 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' @@ -56,6 +57,7 @@ export { Popup, PostWidget, ScanQr, + SecondaryButton, SettingsButton, ShareWidget, } @@ -71,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) @@ -90,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