Skip to content

Commit ef48c27

Browse files
committed
Initial
1 parent b436b72 commit ef48c27

21 files changed

+2521
-0
lines changed

.babelrc

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"presets": [
3+
[
4+
"@babel/typescript"
5+
],
6+
[
7+
"@babel/preset-env"
8+
],
9+
[
10+
"@babel/preset-react"
11+
]
12+
],
13+
"plugins": [
14+
"@babel/plugin-proposal-class-properties",
15+
"@babel/plugin-proposal-nullish-coalescing-operator",
16+
"@babel/plugin-syntax-nullish-coalescing-operator"
17+
]
18+
}

.editorconfig

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
charset = utf-8
11+
indent_style = space
12+
indent_size = 2

.eslintrc

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"extends": [
3+
"react-app",
4+
"plugin:teactn/recommended",
5+
"airbnb-typescript"
6+
],
7+
"plugins": [
8+
"no-async-without-await",
9+
"teactn",
10+
"no-null"
11+
],
12+
"rules": {
13+
"indent": [
14+
"error",
15+
2,
16+
{
17+
"SwitchCase": 1
18+
}
19+
],
20+
"max-len": [
21+
"error",
22+
120
23+
],
24+
"array-bracket-newline": [
25+
2,
26+
"consistent"
27+
],
28+
"no-null/no-null": 2,
29+
"no-console": "error",
30+
"semi": "error",
31+
"no-implicit-coercion": "error",
32+
"react-hooks/exhaustive-deps": "error",
33+
"arrow-body-style": "off",
34+
"no-else-return": "off",
35+
"no-plusplus": "off",
36+
"no-void": "off",
37+
"default-case": "off",
38+
"no-param-reassign": "off",
39+
"no-prototype-builtins": "off",
40+
"no-await-in-loop": "off",
41+
"no-nested-ternary": "off",
42+
"import/no-extraneous-dependencies": "off",
43+
"import/prefer-default-export": "off",
44+
"import/named": "off",
45+
"import/no-webpack-loader-syntax": "off",
46+
"react/prop-types": "off",
47+
"react/jsx-one-expression-per-line": "off",
48+
"react/button-has-type": "off",
49+
"react/require-default-props": "off",
50+
// Teact feature
51+
"react/style-prop-object": "off",
52+
"jsx-a11y/click-events-have-key-events": "off",
53+
"jsx-a11y/no-static-element-interactions": "off",
54+
"jsx-a11y/label-has-associated-control": "off",
55+
"jsx-a11y/anchor-is-valid": "off",
56+
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
57+
"no-async-without-await/no-async-without-await": 1,
58+
"@typescript-eslint/no-use-before-define": [
59+
"error",
60+
{
61+
"functions": false
62+
}
63+
],
64+
"@typescript-eslint/camelcase": "off",
65+
"@typescript-eslint/member-delimiter-style": "error",
66+
"teactn/prefer-separate-component-file": "off"
67+
},
68+
"settings": {
69+
"import/resolver": "webpack"
70+
},
71+
"parserOptions": {
72+
"project": "./tsconfig.json"
73+
},
74+
"ignorePatterns": [
75+
"webpack.config.js",
76+
"jest.config.js",
77+
"src/lib/secret-sauce"
78+
]
79+
}

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Teact
2+
3+
**Teact** is a lightweight and super-performant web framework with zero dependencies implementing React paradigm.
4+
5+
It was originally developed as part of **Telegram JavaScript contest** and now powers the official [**Telegram Web**](https://github.com/Ajaxy/telegram-tt) client. This repo is an extracted version of the framework.
6+
7+
### TODO
8+
9+
Anyone is welcome to contribute.
10+
11+
- Support packaging as a library, add **npm** support with usage examples.
12+
- Add unit tests.
13+
- Consider separating Teact and TeactN.
14+
- Consider extracting `useHeaveAnimationCheck`.
15+
- Consider making `handleErrors` less verbose or configurable.

package-lock.json

+76
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "teact",
3+
"version": "1.0.0",
4+
"description": "Tiny and fast alternative for React",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/Ajaxy/teact.git"
12+
},
13+
"keywords": [
14+
"react",
15+
"jsx",
16+
"tsx",
17+
"framework"
18+
],
19+
"author": "Alexander Zinchuk (alexander@zinchuk.com)",
20+
"license": "MIT",
21+
"bugs": {
22+
"url": "https://github.com/Ajaxy/teact/issues"
23+
},
24+
"homepage": "https://github.com/Ajaxy/teact#readme",
25+
"devDependencies": {
26+
"@types/react": "^18.0.21"
27+
}
28+
}

src/@types/global.d.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
declare const process: NodeJS.Process;
2+
3+
declare namespace React {
4+
interface HTMLAttributes {
5+
// Optimization for DOM nodes prepends and inserts
6+
teactFastList?: boolean;
7+
}
8+
9+
interface Attributes {
10+
// Optimization for DOM nodes reordering. Requires `teactFastList` for parent
11+
teactOrderKey?: number;
12+
}
13+
14+
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
15+
loading?: 'auto' | 'eager' | 'lazy';
16+
}
17+
18+
interface VideoHTMLAttributes {
19+
srcObject?: MediaStream;
20+
}
21+
22+
interface MouseEvent {
23+
offsetX: number;
24+
offsetY: number;
25+
}
26+
}
27+
28+
type AnyLiteral = Record<string, any>;
29+
type AnyFunction = (...args: any[]) => any;
30+
type AnyToVoidFunction = (...args: any[]) => void;
31+
type NoneToVoidFunction = () => void;
32+
33+
interface HTMLElement {
34+
mozRequestFullScreen?: () => Promise<void>;
35+
webkitEnterFullscreen?: () => Promise<void>;
36+
webkitRequestFullscreen?: () => Promise<void>;
37+
}

src/@types/teact.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare namespace JSX {
2+
type Element = VirtualElement;
3+
}

src/config.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const DEBUG = true;
2+
export const DEBUG_MORE = false;
3+
export const DEBUG_ALERT_MSG = 'Shoot!\nSomething went wrong, please see the error details in Dev Tools Console.';

src/hooks/useForceUpdate.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { useCallback, useState } from '../teact/teact';
2+
3+
export default () => {
4+
const [, setTrigger] = useState<boolean>(false);
5+
6+
return useCallback(() => {
7+
setTrigger((trigger) => !trigger);
8+
}, []);
9+
};

src/hooks/useHeavyAnimationCheck.ts

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { useEffect } from '../teact/teact';
2+
3+
const ANIMATION_START_EVENT = 'tt-event-heavy-animation-start';
4+
const ANIMATION_END_EVENT = 'tt-event-heavy-animation-end';
5+
6+
let timeout: number | undefined;
7+
let isAnimating = false;
8+
9+
// Make sure to end even if end callback was not called (which was some hardly-reproducible bug)
10+
const AUTO_END_TIMEOUT = 1000;
11+
12+
const useHeavyAnimationCheck = (
13+
handleAnimationStart: AnyToVoidFunction,
14+
handleAnimationEnd: AnyToVoidFunction,
15+
isDisabled = false,
16+
) => {
17+
useEffect(() => {
18+
if (isDisabled) {
19+
return undefined;
20+
}
21+
22+
if (isAnimating) {
23+
handleAnimationStart();
24+
}
25+
26+
document.addEventListener(ANIMATION_START_EVENT, handleAnimationStart);
27+
document.addEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
28+
29+
return () => {
30+
document.removeEventListener(ANIMATION_END_EVENT, handleAnimationEnd);
31+
document.removeEventListener(ANIMATION_START_EVENT, handleAnimationStart);
32+
};
33+
}, [isDisabled, handleAnimationEnd, handleAnimationStart]);
34+
};
35+
36+
export function isHeavyAnimating() {
37+
return isAnimating;
38+
}
39+
40+
export function dispatchHeavyAnimationEvent(duration = AUTO_END_TIMEOUT) {
41+
if (!isAnimating) {
42+
isAnimating = true;
43+
document.dispatchEvent(new Event(ANIMATION_START_EVENT));
44+
}
45+
46+
if (timeout) {
47+
clearTimeout(timeout);
48+
timeout = undefined;
49+
}
50+
51+
// Race condition may happen if another `dispatchHeavyAnimationEvent` is called before `onEnd`
52+
function onEnd() {
53+
if (timeout) {
54+
clearTimeout(timeout);
55+
timeout = undefined;
56+
}
57+
58+
isAnimating = false;
59+
document.dispatchEvent(new Event(ANIMATION_END_EVENT));
60+
}
61+
62+
timeout = window.setTimeout(onEnd, duration);
63+
64+
return onEnd;
65+
}
66+
67+
export default useHeavyAnimationCheck;

0 commit comments

Comments
 (0)