@tma.js/sdk 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/dist/lib/browser.js +2 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/index.cjs +2 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/types/components/BackButton/BackButton.d.ts +44 -0
- package/dist/types/components/BackButton/index.d.ts +2 -0
- package/dist/types/components/BackButton/types.d.ts +9 -0
- package/dist/types/components/ClosingBehaviour/ClosingBehaviour.d.ts +35 -0
- package/dist/types/components/ClosingBehaviour/index.d.ts +2 -0
- package/dist/types/components/ClosingBehaviour/types.d.ts +7 -0
- package/dist/types/components/CloudStorage/CloudStorage.d.ts +47 -0
- package/dist/types/components/CloudStorage/index.d.ts +1 -0
- package/dist/types/components/HapticFeedback/HapticFeedback.d.ts +37 -0
- package/dist/types/components/HapticFeedback/index.d.ts +1 -0
- package/dist/types/components/InitData/InitData.d.ts +52 -0
- package/dist/types/components/InitData/index.d.ts +1 -0
- package/dist/types/components/MainButton/MainButton.d.ts +114 -0
- package/dist/types/components/MainButton/index.d.ts +2 -0
- package/dist/types/components/MainButton/types.d.ts +15 -0
- package/dist/types/components/Popup/Popup.d.ts +44 -0
- package/dist/types/components/Popup/index.d.ts +2 -0
- package/dist/types/components/Popup/types.d.ts +60 -0
- package/dist/types/components/Popup/utils.d.ts +7 -0
- package/dist/types/components/QRScanner/QRScanner.d.ts +40 -0
- package/dist/types/components/QRScanner/index.d.ts +2 -0
- package/dist/types/components/QRScanner/types.d.ts +7 -0
- package/dist/types/components/ThemeParams/ThemeParams.d.ts +73 -0
- package/dist/types/components/ThemeParams/index.d.ts +2 -0
- package/dist/types/components/ThemeParams/types.d.ts +9 -0
- package/dist/types/components/Viewport/Viewport.d.ts +108 -0
- package/dist/types/components/Viewport/index.d.ts +2 -0
- package/dist/types/components/Viewport/types.d.ts +10 -0
- package/dist/types/components/WebApp/WebApp.d.ts +145 -0
- package/dist/types/components/WebApp/index.d.ts +2 -0
- package/dist/types/components/WebApp/types.d.ts +11 -0
- package/dist/types/components/index.d.ts +11 -0
- package/dist/types/env.d.ts +8 -0
- package/dist/types/errors/MethodNotSupportedError.d.ts +6 -0
- package/dist/types/errors/ParameterNotSupportedError.d.ts +6 -0
- package/dist/types/errors/index.d.ts +2 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/init/creators/createBackButton.d.ts +9 -0
- package/dist/types/init/creators/createClosingBehavior.d.ts +8 -0
- package/dist/types/init/creators/createMainButton.d.ts +11 -0
- package/dist/types/init/creators/createPostEvent.d.ts +7 -0
- package/dist/types/init/creators/createRequestIdGenerator.d.ts +5 -0
- package/dist/types/init/creators/createSyncedThemeParams.d.ts +7 -0
- package/dist/types/init/creators/createViewport.d.ts +10 -0
- package/dist/types/init/creators/createWebApp.d.ts +14 -0
- package/dist/types/init/creators/index.d.ts +8 -0
- package/dist/types/init/css.d.ts +57 -0
- package/dist/types/init/index.d.ts +2 -0
- package/dist/types/init/init.d.ts +6 -0
- package/dist/types/init/types.d.ts +107 -0
- package/dist/types/launch-params.d.ts +20 -0
- package/dist/types/state/State.d.ts +15 -0
- package/dist/types/state/index.d.ts +2 -0
- package/dist/types/state/types.d.ts +30 -0
- package/dist/types/storage.d.ts +48 -0
- package/dist/types/supports.d.ts +22 -0
- package/dist/types/theme-params.d.ts +18 -0
- package/dist/types/types.d.ts +14 -0
- package/dist/types/url.d.ts +7 -0
- package/package.json +67 -0
- package/src/components/BackButton/BackButton.ts +90 -0
- package/src/components/BackButton/index.ts +2 -0
- package/src/components/BackButton/types.ts +13 -0
- package/src/components/ClosingBehaviour/ClosingBehaviour.ts +62 -0
- package/src/components/ClosingBehaviour/index.ts +6 -0
- package/src/components/ClosingBehaviour/types.ts +12 -0
- package/src/components/CloudStorage/CloudStorage.ts +135 -0
- package/src/components/CloudStorage/index.ts +1 -0
- package/src/components/HapticFeedback/HapticFeedback.ts +62 -0
- package/src/components/HapticFeedback/index.ts +1 -0
- package/src/components/InitData/InitData.ts +116 -0
- package/src/components/InitData/index.ts +1 -0
- package/src/components/MainButton/MainButton.ts +243 -0
- package/src/components/MainButton/index.ts +2 -0
- package/src/components/MainButton/types.ts +20 -0
- package/src/components/Popup/Popup.ts +81 -0
- package/src/components/Popup/index.ts +8 -0
- package/src/components/Popup/types.ts +69 -0
- package/src/components/Popup/utils.ts +59 -0
- package/src/components/QRScanner/QRScanner.ts +87 -0
- package/src/components/QRScanner/index.ts +2 -0
- package/src/components/QRScanner/types.ts +11 -0
- package/src/components/ThemeParams/ThemeParams.ts +154 -0
- package/src/components/ThemeParams/index.ts +2 -0
- package/src/components/ThemeParams/types.ts +18 -0
- package/src/components/Viewport/Viewport.ts +197 -0
- package/src/components/Viewport/index.ts +2 -0
- package/src/components/Viewport/types.ts +14 -0
- package/src/components/WebApp/WebApp.ts +310 -0
- package/src/components/WebApp/index.ts +2 -0
- package/src/components/WebApp/types.ts +17 -0
- package/src/components/index.ts +11 -0
- package/src/env.ts +17 -0
- package/src/errors/MethodNotSupportedError.ts +9 -0
- package/src/errors/ParameterNotSupportedError.ts +9 -0
- package/src/errors/index.ts +2 -0
- package/src/index.ts +8 -0
- package/src/init/creators/createBackButton.ts +22 -0
- package/src/init/creators/createClosingBehavior.ts +22 -0
- package/src/init/creators/createMainButton.ts +56 -0
- package/src/init/creators/createPostEvent.ts +36 -0
- package/src/init/creators/createRequestIdGenerator.ts +13 -0
- package/src/init/creators/createSyncedThemeParams.ts +14 -0
- package/src/init/creators/createViewport.ts +50 -0
- package/src/init/creators/createWebApp.ts +49 -0
- package/src/init/creators/index.ts +8 -0
- package/src/init/css.ts +166 -0
- package/src/init/index.ts +2 -0
- package/src/init/init.ts +160 -0
- package/src/init/types.ts +133 -0
- package/src/launch-params.ts +70 -0
- package/src/state/State.ts +53 -0
- package/src/state/index.ts +2 -0
- package/src/state/types.ts +34 -0
- package/src/storage.ts +65 -0
- package/src/supports.ts +44 -0
- package/src/theme-params.ts +34 -0
- package/src/types.ts +28 -0
- package/src/url.ts +24 -0
package/src/init/css.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { RGB } from '@tma.js/colors';
|
|
2
|
+
|
|
3
|
+
import type { ThemeParams, WebApp, Viewport } from '../components/index.js';
|
|
4
|
+
import type { InitCSSVarsOption, InitCSSVarsSpecificOption } from './types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sets CSS variable.
|
|
8
|
+
* @param name - variable name.
|
|
9
|
+
* @param value - variable value.
|
|
10
|
+
*/
|
|
11
|
+
function setVariable(name: string, value: string): void {
|
|
12
|
+
document.documentElement.style.setProperty(name, value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sets new CSS color variable in case, its value is not null.
|
|
17
|
+
* @param name - variable name.
|
|
18
|
+
* @param color - variable value.
|
|
19
|
+
*/
|
|
20
|
+
function setColorVariable(name: string, color: RGB | null): void {
|
|
21
|
+
if (color === null) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
setVariable(name, color);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Sets new CSS variable which value is amount of pixels.
|
|
29
|
+
* @param name - variable name.
|
|
30
|
+
* @param size - variable value.
|
|
31
|
+
*/
|
|
32
|
+
function setSizeVariable(name: string, size: number) {
|
|
33
|
+
setVariable(name, `${size}px`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Creates CSS variables based on theme parameters.
|
|
38
|
+
* @param themeParams - ThemeParams instance.
|
|
39
|
+
*/
|
|
40
|
+
function createThemeVariables(themeParams: ThemeParams): void {
|
|
41
|
+
const {
|
|
42
|
+
backgroundColor,
|
|
43
|
+
buttonTextColor,
|
|
44
|
+
secondaryBackgroundColor,
|
|
45
|
+
hintColor,
|
|
46
|
+
buttonColor,
|
|
47
|
+
linkColor,
|
|
48
|
+
textColor,
|
|
49
|
+
} = themeParams;
|
|
50
|
+
|
|
51
|
+
setColorVariable('--tg-theme-bg-color', backgroundColor);
|
|
52
|
+
setColorVariable('--tg-theme-button-color', buttonColor);
|
|
53
|
+
setColorVariable('--tg-theme-button-text-color', buttonTextColor);
|
|
54
|
+
setColorVariable('--tg-theme-hint-color', hintColor);
|
|
55
|
+
setColorVariable('--tg-theme-link-color', linkColor);
|
|
56
|
+
setColorVariable('--tg-theme-secondary-bg-color', secondaryBackgroundColor);
|
|
57
|
+
setColorVariable('--tg-theme-text-color', textColor);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates CSS variables based on Web App background and header colors with
|
|
62
|
+
* theme parameters.
|
|
63
|
+
* @param webApp - WebApp instance.
|
|
64
|
+
* @param themeParams - theme parameters.
|
|
65
|
+
*/
|
|
66
|
+
function createWebAppVariables(webApp: WebApp, themeParams: ThemeParams): void {
|
|
67
|
+
const { backgroundColor, secondaryBackgroundColor } = themeParams;
|
|
68
|
+
const { backgroundColor: webAppBackgroundColor, headerColor } = webApp;
|
|
69
|
+
|
|
70
|
+
setColorVariable('--tg-bg-color', webAppBackgroundColor);
|
|
71
|
+
setColorVariable('--tg-header-color', headerColor === 'bg_color' ? backgroundColor : secondaryBackgroundColor);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates CSS variables connected with theme parameters.
|
|
76
|
+
*
|
|
77
|
+
* Created variables:
|
|
78
|
+
* - `--tg-theme-bg-color`
|
|
79
|
+
* - `--tg-theme-button-color`
|
|
80
|
+
* - `--tg-theme-button-text-color`
|
|
81
|
+
* - `--tg-theme-hint-color`
|
|
82
|
+
* - `--tg-theme-link-color`
|
|
83
|
+
* - `--tg-theme-secondary-bg-color`
|
|
84
|
+
* - `--tg-theme-text-color`
|
|
85
|
+
*
|
|
86
|
+
* Variables are being automatically updated in case, corresponding properties
|
|
87
|
+
* updated in passed ThemeParams instance.
|
|
88
|
+
*
|
|
89
|
+
* @param themeParams - ThemeParams instance.
|
|
90
|
+
*/
|
|
91
|
+
export function bindThemeCSSVariables(themeParams: ThemeParams): void {
|
|
92
|
+
const actualize = () => createThemeVariables(themeParams);
|
|
93
|
+
|
|
94
|
+
themeParams.on('changed', actualize);
|
|
95
|
+
|
|
96
|
+
actualize();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Creates CSS variables connected with WebApp background and header colors based on
|
|
101
|
+
* passed WebApp and ThemeParams instances.
|
|
102
|
+
*
|
|
103
|
+
* Created variables:
|
|
104
|
+
* - `--tg-bg-color`
|
|
105
|
+
* - `--tg-header-color`
|
|
106
|
+
*
|
|
107
|
+
* Variables are being automatically updated in case, corresponding properties are updating.
|
|
108
|
+
*
|
|
109
|
+
* @param webApp - WebApp instance.
|
|
110
|
+
* @param themeParams - ThemeParams instance.
|
|
111
|
+
*/
|
|
112
|
+
export function bindWebAppVariables(webApp: WebApp, themeParams: ThemeParams): void {
|
|
113
|
+
const actualize = () => createWebAppVariables(webApp, themeParams);
|
|
114
|
+
|
|
115
|
+
themeParams.on('changed', actualize);
|
|
116
|
+
webApp.on('backgroundColorChanged', actualize);
|
|
117
|
+
webApp.on('headerColorChanged', actualize);
|
|
118
|
+
|
|
119
|
+
actualize();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Accepts Viewport instance and sets CSS variables connected with viewport
|
|
124
|
+
* sizes.
|
|
125
|
+
*
|
|
126
|
+
* Be careful using this function as long as it can impact application
|
|
127
|
+
* performance. Viewport size is changing rather often, this makes CSS
|
|
128
|
+
* variables update, which leads to possible layout redraw.
|
|
129
|
+
*
|
|
130
|
+
* Variables:
|
|
131
|
+
* - `--tg-viewport-height`
|
|
132
|
+
* - `--tg-viewport-stable-height`
|
|
133
|
+
*
|
|
134
|
+
* Variables are being automatically updated in case, corresponding properties
|
|
135
|
+
* updated in passed Viewport instance.
|
|
136
|
+
*
|
|
137
|
+
* @param viewport - Viewport instance.
|
|
138
|
+
*/
|
|
139
|
+
export function bindViewportCSSVariables(viewport: Viewport): void {
|
|
140
|
+
const setHeight = () => {
|
|
141
|
+
setSizeVariable('--tg-viewport-height', viewport.height);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const setStableHeight = () => {
|
|
145
|
+
setSizeVariable('--tg-viewport-stable-height', viewport.stableHeight);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
viewport.on('heightChanged', setHeight);
|
|
149
|
+
viewport.on('stableHeightChanged', setStableHeight);
|
|
150
|
+
|
|
151
|
+
setHeight();
|
|
152
|
+
setStableHeight();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Converts init cssVars option to more narrow type.
|
|
157
|
+
* @param option - option value.
|
|
158
|
+
*/
|
|
159
|
+
export function parseCSSVarsOptions(option: InitCSSVarsOption): InitCSSVarsSpecificOption {
|
|
160
|
+
if (typeof option === 'boolean') {
|
|
161
|
+
return option
|
|
162
|
+
? { themeParams: true, viewport: true, webApp: true }
|
|
163
|
+
: {};
|
|
164
|
+
}
|
|
165
|
+
return option;
|
|
166
|
+
}
|
package/src/init/init.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isIframe,
|
|
3
|
+
setDebug,
|
|
4
|
+
setTargetOrigin,
|
|
5
|
+
on,
|
|
6
|
+
} from '@tma.js/bridge';
|
|
7
|
+
import { withTimeout } from '@tma.js/utils';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
CloudStorage,
|
|
11
|
+
HapticFeedback,
|
|
12
|
+
InitData,
|
|
13
|
+
Popup,
|
|
14
|
+
QRScanner,
|
|
15
|
+
} from '../components/index.js';
|
|
16
|
+
import { parseLaunchParams, retrieveLaunchParams, type LaunchParams } from '../launch-params.js';
|
|
17
|
+
import {
|
|
18
|
+
bindThemeCSSVariables,
|
|
19
|
+
bindViewportCSSVariables,
|
|
20
|
+
bindWebAppVariables,
|
|
21
|
+
parseCSSVarsOptions,
|
|
22
|
+
} from './css.js';
|
|
23
|
+
import {
|
|
24
|
+
createPostEvent,
|
|
25
|
+
createSyncedThemeParams,
|
|
26
|
+
createBackButton,
|
|
27
|
+
createMainButton,
|
|
28
|
+
createViewport,
|
|
29
|
+
createWebApp, createRequestIdGenerator, createClosingBehavior,
|
|
30
|
+
} from './creators/index.js';
|
|
31
|
+
|
|
32
|
+
import type { InitOptions, InitResult } from './types.js';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Represents actual init function.
|
|
36
|
+
* @param options - init options.
|
|
37
|
+
*/
|
|
38
|
+
async function actualInit(options: InitOptions = {}): Promise<InitResult> {
|
|
39
|
+
const {
|
|
40
|
+
checkCompat = true,
|
|
41
|
+
cssVars = false,
|
|
42
|
+
acceptScrollbarStyle = true,
|
|
43
|
+
acceptCustomStyles = acceptScrollbarStyle,
|
|
44
|
+
targetOrigin,
|
|
45
|
+
debug = false,
|
|
46
|
+
launchParams: launchParamsRaw,
|
|
47
|
+
} = options;
|
|
48
|
+
|
|
49
|
+
// Set global debug mode.
|
|
50
|
+
if (debug) {
|
|
51
|
+
setDebug(debug);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Set global target origin.
|
|
55
|
+
if (typeof targetOrigin === 'string') {
|
|
56
|
+
setTargetOrigin(targetOrigin);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Get Web App launch params.
|
|
60
|
+
let launchParams: LaunchParams;
|
|
61
|
+
|
|
62
|
+
if (launchParamsRaw) {
|
|
63
|
+
launchParams = launchParamsRaw instanceof URLSearchParams || typeof launchParamsRaw === 'string'
|
|
64
|
+
? parseLaunchParams(launchParamsRaw)
|
|
65
|
+
: launchParamsRaw;
|
|
66
|
+
} else {
|
|
67
|
+
launchParams = retrieveLaunchParams();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const {
|
|
71
|
+
initData,
|
|
72
|
+
initDataRaw,
|
|
73
|
+
version,
|
|
74
|
+
platform,
|
|
75
|
+
themeParams: lpThemeParams,
|
|
76
|
+
} = launchParams;
|
|
77
|
+
const {
|
|
78
|
+
backgroundColor = '#ffffff',
|
|
79
|
+
buttonColor = '#000000',
|
|
80
|
+
buttonTextColor = '#ffffff',
|
|
81
|
+
} = lpThemeParams;
|
|
82
|
+
|
|
83
|
+
const createRequestId = createRequestIdGenerator();
|
|
84
|
+
const postEvent = createPostEvent(checkCompat, version);
|
|
85
|
+
const themeParams = createSyncedThemeParams(lpThemeParams);
|
|
86
|
+
const webApp = createWebApp(backgroundColor, version, platform, createRequestId, postEvent);
|
|
87
|
+
|
|
88
|
+
const {
|
|
89
|
+
themeParams: createThemeParamsCSSVars,
|
|
90
|
+
viewport: createViewportCSSVars,
|
|
91
|
+
webApp: createWebAppCSSVars,
|
|
92
|
+
} = parseCSSVarsOptions(cssVars);
|
|
93
|
+
|
|
94
|
+
if (createWebAppCSSVars) {
|
|
95
|
+
bindWebAppVariables(webApp, themeParams);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (createThemeParamsCSSVars) {
|
|
99
|
+
bindThemeCSSVariables(themeParams);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const viewport = await createViewport(platform, postEvent);
|
|
103
|
+
|
|
104
|
+
// Apply viewport CSS variables.
|
|
105
|
+
if (createViewportCSSVars) {
|
|
106
|
+
bindViewportCSSVariables(viewport);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// In case, we are currently in iframe, it is required to listen to
|
|
110
|
+
// messages, coming from parent source to apply requested changes.
|
|
111
|
+
// The only one case, when current application was placed into iframe is
|
|
112
|
+
// web version of Telegram.
|
|
113
|
+
if (acceptCustomStyles && isIframe()) {
|
|
114
|
+
// Create special style element which is responsible for application
|
|
115
|
+
// style controlled by external app.
|
|
116
|
+
const styleElement = document.createElement('style');
|
|
117
|
+
styleElement.id = 'telegram-custom-styles';
|
|
118
|
+
document.head.appendChild(styleElement);
|
|
119
|
+
|
|
120
|
+
// Listen to custom style changes.
|
|
121
|
+
on('set_custom_style', (html) => {
|
|
122
|
+
styleElement.innerHTML = html;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Notify Telegram, iframe is ready. This will result in sending style
|
|
126
|
+
// tag html from native application.
|
|
127
|
+
postEvent('iframe_ready');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const result: InitResult = {
|
|
131
|
+
backButton: createBackButton(version, postEvent),
|
|
132
|
+
closingBehavior: createClosingBehavior(postEvent),
|
|
133
|
+
cloudStorage: new CloudStorage(version, createRequestId, postEvent),
|
|
134
|
+
haptic: new HapticFeedback(version, postEvent),
|
|
135
|
+
mainButton: createMainButton(buttonColor, buttonTextColor, postEvent),
|
|
136
|
+
popup: new Popup(version, postEvent),
|
|
137
|
+
postEvent,
|
|
138
|
+
qrScanner: new QRScanner(version, postEvent),
|
|
139
|
+
themeParams,
|
|
140
|
+
viewport,
|
|
141
|
+
webApp,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Init data could be missing in case, application was launched via InlineKeyboardButton.
|
|
145
|
+
if (initData !== undefined) {
|
|
146
|
+
const { authDate, hash, ...restInitData } = initData;
|
|
147
|
+
result.initData = new InitData(authDate, hash, restInitData);
|
|
148
|
+
result.initDataRaw = initDataRaw;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Initializes all SDK components.
|
|
156
|
+
* @param options - initialization options.
|
|
157
|
+
*/
|
|
158
|
+
export function init(options: InitOptions = {}): Promise<InitResult> {
|
|
159
|
+
return withTimeout(actualInit(options), options.timeout || 1000);
|
|
160
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { PostEvent } from '@tma.js/bridge';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
BackButton,
|
|
5
|
+
ClosingBehaviour,
|
|
6
|
+
CloudStorage,
|
|
7
|
+
HapticFeedback,
|
|
8
|
+
InitData,
|
|
9
|
+
MainButton,
|
|
10
|
+
Popup,
|
|
11
|
+
QRScanner,
|
|
12
|
+
ThemeParams,
|
|
13
|
+
Viewport,
|
|
14
|
+
WebApp,
|
|
15
|
+
} from '../components/index.js';
|
|
16
|
+
import type { LaunchParams } from '../launch-params.js';
|
|
17
|
+
|
|
18
|
+
export type InitResult = {
|
|
19
|
+
backButton: BackButton;
|
|
20
|
+
closingBehavior: ClosingBehaviour;
|
|
21
|
+
cloudStorage: CloudStorage;
|
|
22
|
+
haptic: HapticFeedback;
|
|
23
|
+
initData?: InitData;
|
|
24
|
+
initDataRaw?: string;
|
|
25
|
+
mainButton: MainButton;
|
|
26
|
+
popup: Popup;
|
|
27
|
+
postEvent: PostEvent;
|
|
28
|
+
qrScanner: QRScanner;
|
|
29
|
+
themeParams: ThemeParams;
|
|
30
|
+
viewport: Viewport;
|
|
31
|
+
webApp: WebApp;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type InitCSSVarsSpecificOption = {
|
|
35
|
+
/**
|
|
36
|
+
* Enables theme parameters CSS variables:
|
|
37
|
+
* - `--tg-theme-bg-color`
|
|
38
|
+
* - `--tg-theme-button-color`
|
|
39
|
+
* - `--tg-theme-button-text-color`
|
|
40
|
+
* - `--tg-theme-hint-color`
|
|
41
|
+
* - `--tg-theme-link-color`
|
|
42
|
+
* - `--tg-theme-secondary-bg-color`
|
|
43
|
+
* - `--tg-theme-text-color`
|
|
44
|
+
*
|
|
45
|
+
* @see bindThemeCSSVariables
|
|
46
|
+
*/
|
|
47
|
+
themeParams?: true;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Enables viewport CSS variables:
|
|
51
|
+
* - `--tg-viewport-height`
|
|
52
|
+
* - `--tg-viewport-stable-height`
|
|
53
|
+
*
|
|
54
|
+
* @see bindViewportCSSVariables
|
|
55
|
+
*/
|
|
56
|
+
viewport?: true;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Enables web app CSS variables:
|
|
60
|
+
* - `--tg-bg-color`
|
|
61
|
+
* - `--tg-header-color`
|
|
62
|
+
*
|
|
63
|
+
* @see bindWebAppVariables
|
|
64
|
+
*/
|
|
65
|
+
webApp?: true;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type InitCSSVarsOption = boolean | InitCSSVarsSpecificOption;
|
|
69
|
+
|
|
70
|
+
export interface InitOptions {
|
|
71
|
+
/**
|
|
72
|
+
* @deprecated Use acceptCustomStyles
|
|
73
|
+
*/
|
|
74
|
+
acceptScrollbarStyle?: boolean;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Should SDK accept styles sent from the Telegram web application.
|
|
78
|
+
* This option is only used in Web versions of Telegram.
|
|
79
|
+
*
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
acceptCustomStyles?: boolean;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Should SDK throw an error in case, unsupported by current version of
|
|
86
|
+
* Web App method was called. It is highly recommended not to disable this
|
|
87
|
+
* feature as long as it helps developer to find issues related to usage
|
|
88
|
+
* of unsupported methods.
|
|
89
|
+
*
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
checkCompat?: boolean;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Should SDK create global CSS variables related to current Telegram
|
|
96
|
+
* application colors.
|
|
97
|
+
*
|
|
98
|
+
* Possible values:
|
|
99
|
+
* - `false` - no CSS variables will be created.
|
|
100
|
+
* - `true` - all CSS variables will be created.
|
|
101
|
+
* - object - applies specific CSS variables.
|
|
102
|
+
*
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
cssVars?: InitCSSVarsOption;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Enable debug mode.
|
|
109
|
+
*
|
|
110
|
+
* @default false
|
|
111
|
+
*/
|
|
112
|
+
debug?: boolean;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Launch parameters presented as query parameters or already parsed
|
|
116
|
+
* object. In case, this value is not specified, init
|
|
117
|
+
* function will try to retrieve launch parameters from window.location.hash
|
|
118
|
+
* via retrieveLaunchParams function.
|
|
119
|
+
*/
|
|
120
|
+
launchParams?: string | URLSearchParams | LaunchParams;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sets new targetOrigin, used by bridge's `postEvent` function.
|
|
124
|
+
* @see setTargetOrigin
|
|
125
|
+
*/
|
|
126
|
+
targetOrigin?: string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Initialization process timeout.
|
|
130
|
+
* @default 1000
|
|
131
|
+
*/
|
|
132
|
+
timeout?: number;
|
|
133
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { searchParams, string } from '@tma.js/parsing';
|
|
2
|
+
import { initData, type InitData } from '@tma.js/init-data';
|
|
3
|
+
|
|
4
|
+
import { parseThemeParams, type ThemeParamsType } from './theme-params.js';
|
|
5
|
+
import { saveStorageValue, getStorageValue } from './storage.js';
|
|
6
|
+
|
|
7
|
+
import type { Platform } from './types.js';
|
|
8
|
+
|
|
9
|
+
export interface LaunchParams {
|
|
10
|
+
version: string;
|
|
11
|
+
initData?: InitData;
|
|
12
|
+
initDataRaw?: string;
|
|
13
|
+
platform: Platform;
|
|
14
|
+
themeParams: ThemeParamsType;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const launchParamsParser = searchParams<LaunchParams>({
|
|
18
|
+
version: { type: string(), from: 'tgWebAppVersion' },
|
|
19
|
+
initData: { type: initData.optional(), from: 'tgWebAppData' },
|
|
20
|
+
initDataRaw: { type: string().optional(), from: 'tgWebAppData' },
|
|
21
|
+
platform: { type: string(), from: 'tgWebAppPlatform' },
|
|
22
|
+
themeParams: { type: parseThemeParams, from: 'tgWebAppThemeParams' },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parses query parameters as launch parameters.
|
|
27
|
+
* @param query - query parameters presented as string or URLSearchParams
|
|
28
|
+
* instance.
|
|
29
|
+
*/
|
|
30
|
+
export function parseLaunchParams(query: string | URLSearchParams): LaunchParams {
|
|
31
|
+
return launchParamsParser.parse(query);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Extracts launch params from the current environment.
|
|
36
|
+
*/
|
|
37
|
+
export function retrieveLaunchParams(): LaunchParams {
|
|
38
|
+
const errors: string[] = [];
|
|
39
|
+
|
|
40
|
+
// Try to extract Web App data from hash. This block of code covers usual flow, when
|
|
41
|
+
// application was firstly opened by the user and its hash always contains required parameters.
|
|
42
|
+
try {
|
|
43
|
+
const launchParamsRaw = window.location.hash.slice(1);
|
|
44
|
+
const launchParamsParsed = parseLaunchParams(launchParamsRaw);
|
|
45
|
+
|
|
46
|
+
// Previous line of code worked fine. Then, we can save taken launch params raw value.
|
|
47
|
+
saveStorageValue('launch-params', launchParamsRaw);
|
|
48
|
+
|
|
49
|
+
return launchParamsParsed;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
errors.push(e instanceof Error ? e.message : 'unknown error');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Web Apps allows reloading current page. In this case, window.location.reload() will be
|
|
55
|
+
// called which means, that init will be called again. As the result, current window
|
|
56
|
+
// location will lose Web App data. To solve this problem, we are extracting launch
|
|
57
|
+
// params saved previously.
|
|
58
|
+
try {
|
|
59
|
+
const launchParamsRaw = getStorageValue('launch-params');
|
|
60
|
+
if (launchParamsRaw) {
|
|
61
|
+
return parseLaunchParams(launchParamsRaw);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
errors.push('Launch params are missing in local storage');
|
|
65
|
+
} catch (e) {
|
|
66
|
+
errors.push(e instanceof Error ? e.message : 'unknown error');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw new Error(`Unable to extract launch params. Errors: "${errors.join('", "')}"`);
|
|
70
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { EventEmitter } from '@tma.js/event-emitter';
|
|
2
|
+
|
|
3
|
+
import type { StateEvents, StringKeys } from './types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents state which is observable via passed EventEmitter.
|
|
7
|
+
*/
|
|
8
|
+
export class State<S extends object> {
|
|
9
|
+
constructor(private readonly state: S, private readonly ee?: EventEmitter<StateEvents<S>>) {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private emit(key: string, value?: unknown) {
|
|
13
|
+
if (this.ee) {
|
|
14
|
+
(this.ee as any).emit(key, value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private internalSet<K extends StringKeys<S>>(key: K, value: S[K]): boolean {
|
|
19
|
+
if (this.state[key] === value) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.state[key] = value;
|
|
24
|
+
this.emit(`${key}Changed`, value);
|
|
25
|
+
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set<K extends StringKeys<S>>(key: K, value: S[K]): void;
|
|
30
|
+
set(state: Partial<S>): void;
|
|
31
|
+
set(keyOrState: any, value?: any): void {
|
|
32
|
+
let didChange = false;
|
|
33
|
+
|
|
34
|
+
if (typeof keyOrState === 'string') {
|
|
35
|
+
didChange = this.internalSet(keyOrState as any, value);
|
|
36
|
+
} else {
|
|
37
|
+
// eslint-disable-next-line
|
|
38
|
+
for (const key in keyOrState) {
|
|
39
|
+
if (this.internalSet(key as any, keyOrState[key])) {
|
|
40
|
+
didChange = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (didChange) {
|
|
46
|
+
this.emit('changed');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get<K extends StringKeys<S>>(key: K): Readonly<S[K]> {
|
|
51
|
+
return this.state[key];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes state property changed event.
|
|
3
|
+
*/
|
|
4
|
+
export type PropChangedEvent<K extends string> = `${K}Changed`;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns object string keys.
|
|
8
|
+
*/
|
|
9
|
+
export type StringKeys<T extends object> = Extract<keyof T, string>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extracts state property type by its computed change event name.
|
|
13
|
+
*/
|
|
14
|
+
export type PropertyType<State extends object, Event extends string> = {
|
|
15
|
+
[Key in StringKeys<State>]: Event extends PropChangedEvent<Key> ? State[Key] : never;
|
|
16
|
+
}[StringKeys<State>];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates map, where key is event name which is used, when state property was changed.
|
|
20
|
+
* Value is according listener.
|
|
21
|
+
*/
|
|
22
|
+
export type PropChangedEventsMap<State extends object> = {
|
|
23
|
+
[Event in `${StringKeys<State>}Changed`]: (value: PropertyType<State, Event>) => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates map with all events emitted by state.
|
|
28
|
+
*/
|
|
29
|
+
export type StateEvents<State extends object> = PropChangedEventsMap<State> & {
|
|
30
|
+
/**
|
|
31
|
+
* Being called whenever any property was updated.
|
|
32
|
+
*/
|
|
33
|
+
changed: () => void;
|
|
34
|
+
};
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { HeaderColorKey } from '@tma.js/bridge';
|
|
2
|
+
import type { RGB } from '@tma.js/colors';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Describes storage keys and according values.
|
|
6
|
+
*/
|
|
7
|
+
interface StorageParams {
|
|
8
|
+
'back-button': {
|
|
9
|
+
isVisible: boolean
|
|
10
|
+
};
|
|
11
|
+
'closing-behavior': {
|
|
12
|
+
isConfirmationNeeded: boolean;
|
|
13
|
+
};
|
|
14
|
+
'main-button': {
|
|
15
|
+
backgroundColor: RGB;
|
|
16
|
+
isEnabled: boolean;
|
|
17
|
+
isVisible: boolean;
|
|
18
|
+
isProgressVisible: boolean;
|
|
19
|
+
text: string;
|
|
20
|
+
textColor: RGB;
|
|
21
|
+
};
|
|
22
|
+
viewport: {
|
|
23
|
+
height: number;
|
|
24
|
+
isExpanded: boolean;
|
|
25
|
+
stableHeight: number;
|
|
26
|
+
width: number;
|
|
27
|
+
};
|
|
28
|
+
'web-app': {
|
|
29
|
+
backgroundColor: RGB;
|
|
30
|
+
headerColor: HeaderColorKey | RGB;
|
|
31
|
+
};
|
|
32
|
+
'launch-params': string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Key which could be used to store data in storage.
|
|
37
|
+
*/
|
|
38
|
+
type StorageKey = keyof StorageParams;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Formats key which could be used during the communication with the storage.
|
|
42
|
+
* @param key - session storage key.
|
|
43
|
+
*/
|
|
44
|
+
function formatKey(key: StorageKey): string {
|
|
45
|
+
return `telegram-web-apps-${key}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Saves value in sessionStorage.
|
|
50
|
+
* @param key - storage key.
|
|
51
|
+
* @param value - storage value.
|
|
52
|
+
*/
|
|
53
|
+
export function saveStorageValue<K extends StorageKey>(key: K, value: StorageParams[K]): void {
|
|
54
|
+
sessionStorage.setItem(formatKey(key), JSON.stringify(value));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extracts value from the sessionStorage.
|
|
59
|
+
* @param key - storage key.
|
|
60
|
+
*/
|
|
61
|
+
export function getStorageValue<K extends StorageKey>(key: K): StorageParams[K] | null {
|
|
62
|
+
const value = sessionStorage.getItem(formatKey(key));
|
|
63
|
+
|
|
64
|
+
return value ? JSON.parse(value) : null;
|
|
65
|
+
}
|