├── .env
├── .gitignore
├── .idea
├── .gitignore
├── inspectionProfiles
│ └── Project_Default.xml
├── jsLinters
│ └── eslint.xml
├── modules.xml
├── react-concepts.iml
└── vcs.xml
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.test.tsx
├── App.tsx
├── Theme
│ ├── ThemeReducer.ts
│ ├── global.tsx
│ └── theme.tsx
├── components
│ ├── ClickOutsideWrapper
│ │ ├── ClickOutsideWrapper.tsx
│ │ └── useClickOutside.ts
│ ├── Form
│ │ ├── FormComponent.tsx
│ │ ├── Input.tsx
│ │ ├── form.types.ts
│ │ └── hook
│ │ │ ├── useForm.tsx
│ │ │ └── useInput.ts
│ ├── Header
│ │ ├── Header.styles.tsx
│ │ └── Header.tsx
│ ├── Layout
│ │ └── ScreenLayout.tsx
│ ├── Selection
│ │ └── Selection.tsx
│ ├── TreeView
│ │ ├── TreeView.tsx
│ │ └── data.ts
│ └── styles
│ │ ├── Animations.tsx
│ │ ├── Button.tsx
│ │ ├── LinkCustom.tsx
│ │ └── Main.tsx
├── hooks
│ ├── useClickOutside.ts
│ ├── useDomRef.ts
│ ├── useTheme.ts
│ ├── useToggle.ts
│ └── useUpdateEffect.ts
├── index.tsx
├── react-app-env.d.ts
├── reportWebVitals.ts
├── routes
│ └── routes.tsx
├── screens
│ ├── ClickOutside
│ │ └── ClickOutside.tsx
│ ├── FormScreen
│ │ └── FormExampleScreen.tsx
│ ├── Home
│ │ └── HomeScreen.tsx
│ ├── Me
│ │ └── Me.tsx
│ ├── StepMachine
│ │ └── StepExample.tsx
│ └── TreeFile
│ │ └── TreeViewScreen.tsx
├── setupTests.ts
├── static
│ ├── enums.ts
│ ├── me.ts
│ └── url.ts
├── store
│ ├── StoreProvider.tsx
│ └── makeStore.tsx
└── utils
│ ├── _.ts
│ └── misc.ts
├── talk.md
├── tsconfig.json
└── yarn.lock
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_GITHUB_ACCESS_TOKEN=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
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .vercel
26 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jsLinters/eslint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/react-concepts.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will reload if you make edits.\
15 | You will also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
35 |
36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
39 |
40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-concepts",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.14.1",
7 | "@testing-library/react": "^11.2.7",
8 | "@testing-library/user-event": "^12.8.3",
9 | "graphql": "^16.6.0",
10 | "graphql-request": "^5.0.0",
11 | "react": "^16.13.1",
12 | "react-dom": "^16.13.1",
13 | "react-helmet": "^6.1.0",
14 | "react-icons": "^4.2.0",
15 | "react-query": "^3.26.0",
16 | "react-router-dom": "^6.0.0",
17 | "react-scripts": "4.0.3",
18 | "react-step-machine": "^1.0.1",
19 | "react-store-maker": "^1.0.5",
20 | "styled-components": "^5.3.0",
21 | "swr": "^1.3.0",
22 | "typescript": "^4.3.5",
23 | "web-vitals": "^1.1.2"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject"
30 | },
31 | "eslintConfig": {
32 | "extends": [
33 | "react-app",
34 | "react-app/jest"
35 | ]
36 | },
37 | "browserslist": {
38 | "production": [
39 | ">0.2%",
40 | "not dead",
41 | "not op_mini all"
42 | ],
43 | "development": [
44 | "last 1 chrome version",
45 | "last 1 firefox version",
46 | "last 1 safari version"
47 | ]
48 | },
49 | "devDependencies": {
50 | "@types/jest": "^26.0.24",
51 | "@types/node": "^12.20.17",
52 | "@types/react": "^17.0.18",
53 | "@types/react-dom": "^17.0.9",
54 | "@types/react-helmet": "^6.1.2",
55 | "@types/react-router-dom": "^5.3.2",
56 | "@types/styled-components": "^5.1.11"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adiathasan/react-concepts/c1198b519a0ecdcb99e6a7d6e0ade4560558948b/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
24 | ADIAT HASAN
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adiathasan/react-concepts/c1198b519a0ecdcb99e6a7d6e0ade4560558948b/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adiathasan/react-concepts/c1198b519a0ecdcb99e6a7d6e0ade4560558948b/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "⚛️ patterns with 💙",
3 | "name": "__PEACE__",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | render();
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled, { ThemeProvider } from 'styled-components';
3 | import { Routes, BrowserRouter, Route } from 'react-router-dom';
4 |
5 | import Header from './components/Header/Header';
6 | import { themes } from './Theme/theme';
7 | import { useTheme } from './hooks/useTheme';
8 | import { GlobalStyles } from './Theme/global';
9 |
10 | /* screens */
11 | import { routes } from './routes/routes';
12 |
13 |
14 | const App: React.FC = () => {
15 | const { theme } = useTheme();
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 | {routes.map((route, i) => (
25 |
26 | ))}
27 |
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | export default App;
35 |
36 | const AppStyled = styled.div`
37 | min-height: 80vh;
38 | display: flex;
39 | align-items: center;
40 | justify-content: center;
41 | padding: 0 14px;
42 | `;
43 |
--------------------------------------------------------------------------------
/src/Theme/ThemeReducer.ts:
--------------------------------------------------------------------------------
1 | import { Theme } from '../hooks/useTheme';
2 | import { createStore } from 'react-store-maker';
3 |
4 | export type ThemeActions =
5 | | { type: 'TOGGLE_THEME_LIGHT'; payload: 'light' }
6 | | { type: 'TOGGLE_THEME_DARK'; payload: 'dark' };
7 |
8 | export const themeReducer = (state: Theme, action: ThemeActions): Theme => {
9 | switch (action.type) {
10 | case 'TOGGLE_THEME_LIGHT':
11 | return action.payload;
12 | case 'TOGGLE_THEME_DARK':
13 | return action.payload;
14 | default:
15 | return state;
16 | }
17 | };
18 |
19 | const [AppThemeProvider, useAppThemeValue, useAppThemeDispatch] = createStore(
20 | 'dark',
21 | themeReducer
22 | );
23 |
24 | export { AppThemeProvider, useAppThemeValue, useAppThemeDispatch };
25 |
--------------------------------------------------------------------------------
/src/Theme/global.tsx:
--------------------------------------------------------------------------------
1 | import { createGlobalStyle } from 'styled-components';
2 |
3 | import { IThemes } from './theme';
4 |
5 | export const GlobalStyles = createGlobalStyle`
6 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@200&display=swap');
7 |
8 | *,
9 | ::after,
10 | ::before {
11 | margin: 0;
12 | padding: 0;
13 | box-sizing: border-box;
14 | }
15 |
16 | body {
17 | margin: 0;
18 | font-family: 'Roboto', sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | scroll-behavior: smooth;
22 | background-color: ${({theme}) => theme['bg-primary']};
23 | color: ${({theme}) => theme['text-primary']};
24 | transition: .2s ease-in-out all;
25 | overflow-x: hidden;
26 | min-height: 100vh;
27 | min-width: 100vw;
28 | }
29 |
30 | code {
31 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
32 | monospace;
33 | }
34 |
35 | a {
36 | text-decoration: none;
37 | color: hsl(222, 100%, 65%);
38 | }
39 | `;
40 |
--------------------------------------------------------------------------------
/src/Theme/theme.tsx:
--------------------------------------------------------------------------------
1 | export enum EThemes {
2 | BG_PRIMARY = 'bg-primary',
3 | BG_SECONDARY = 'bg-secondary',
4 | TEXT_PRIMARY = 'text-primary',
5 | BTN_PRIMARY = 'btn-primary',
6 | LINK_PRIMARY = 'link-primary',
7 | }
8 |
9 | export const common = {};
10 |
11 | export const themes = {
12 | light: {
13 | ...common,
14 | [EThemes.LINK_PRIMARY]: 'green',
15 | [EThemes.BTN_PRIMARY]: 'hsl(0, 0%, 10%)',
16 | [EThemes.BG_PRIMARY]: 'hsl(0, 0%,91%)',
17 | [EThemes.BG_SECONDARY]: 'hsl(0, 0%, 95%)',
18 | [EThemes.TEXT_PRIMARY]: 'hsl(0, 0%, 33%)',
19 | },
20 | dark: {
21 | ...common,
22 | [EThemes.LINK_PRIMARY]: 'limegreen',
23 | [EThemes.BTN_PRIMARY]: 'hsl(0, 0%, 90%)',
24 | [EThemes.BG_PRIMARY]: 'hsl(0, 0%, 13%)',
25 | [EThemes.BG_SECONDARY]: 'hsl(0, 0%, 18%)',
26 | [EThemes.TEXT_PRIMARY]: 'hsl(0, 0%, 80%)',
27 | },
28 | };
29 |
30 | export interface IThemes {
31 | theme: typeof themes.light;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | interface Props {
5 | isOpen: boolean;
6 | isUnmounted: boolean;
7 | }
8 |
9 | const ClickOutsideWrapper: React.FC = React.forwardRef<
10 | HTMLDivElement,
11 | Props
12 | >((props, ref) => {
13 | const { children, isOpen, isUnmounted } = props;
14 |
15 | if (!isOpen) return null;
16 |
17 | return (
18 |
19 | {children}
20 |
21 | );
22 | });
23 |
24 | export default ClickOutsideWrapper;
25 |
26 | const StyledClickWrapper = styled.div<{ done: boolean }>`
27 | z-index: 100;
28 | animation: ${({ done }) => (done ? 'unmount' : 'mount')} 0.3s ease-out
29 | forwards;
30 |
31 | @keyframes mount {
32 | 0% {
33 | opacity: 0;
34 | transform: translateY(-10px);
35 | }
36 | 100% {
37 | opacity: 1;
38 | transform: translateY(0);
39 | }
40 | }
41 |
42 | @keyframes unmount {
43 | 0% {
44 | opacity: 1;
45 | transform: translateY(0);
46 | }
47 | 100% {
48 | opacity: 0;
49 | transform: translateY(-10px);
50 | }
51 | }
52 | `;
53 |
--------------------------------------------------------------------------------
/src/components/ClickOutsideWrapper/useClickOutside.ts:
--------------------------------------------------------------------------------
1 | import { createRef, useCallback, useEffect, useRef, useState } from 'react';
2 |
3 | const TIME_UNMOUT = 400;
4 |
5 | const useClickOutside = (clickOutsideCb?: () => void) => {
6 | const [isOpen, setIsOpen] = useState(false);
7 |
8 | const [isUnmounted, setIsUnmounted] = useState(false);
9 |
10 | const toggle = useCallback(() => {
11 | let timeFn;
12 |
13 | if (timeFn) clearTimeout(timeFn);
14 |
15 | if (!isOpen) {
16 | setIsOpen(true);
17 | return;
18 | }
19 |
20 | setIsUnmounted(true);
21 |
22 | timeFn = setTimeout(() => {
23 | setIsOpen(false);
24 | setIsUnmounted(false);
25 | }, TIME_UNMOUT);
26 | }, [isOpen]);
27 |
28 | /*
29 | *logic outside click
30 | */
31 |
32 | const ref = createRef();
33 |
34 | const cbRef = useRef();
35 |
36 | cbRef.current = clickOutsideCb;
37 |
38 | useEffect(() => {
39 | const onCllickOutside = (e: MouseEvent) => {
40 | if ((e.target as Node)?.contains(ref.current) && isOpen) {
41 | cbRef.current?.();
42 | toggle();
43 | }
44 | };
45 |
46 | document.addEventListener('click', onCllickOutside, true);
47 |
48 | return () => {
49 | document.removeEventListener('click', onCllickOutside, true);
50 | };
51 | }, [ref, toggle, cbRef, isOpen]);
52 |
53 | return { ref, toggle, isOpen, register: { isOpen, isUnmounted, ref } };
54 | };
55 |
56 | export default useClickOutside;
57 |
--------------------------------------------------------------------------------
/src/components/Form/FormComponent.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { EThemes } from '../../Theme/theme';
5 | import { Api } from './form.types';
6 |
7 | interface FormProps extends React.FormHTMLAttributes {
8 | children: React.ReactNode;
9 | onSubmit?: (values: any) => void;
10 | // formProps: React.FormHTMLAttributes;
11 | }
12 |
13 | export type SForm = ((c: FormProps) => JSX.Element | null) & {
14 | api?: Api;
15 | };
16 |
17 | const FormComponent = (api: Api) => {
18 | const Form: SForm = useMemo(
19 | () =>
20 | ({ children, onSubmit, ...all }) => {
21 | if (!Form.api) return null;
22 |
23 | const { formContext, ...rest } = Form.api;
24 |
25 | return (
26 |
27 | {
30 | e.preventDefault();
31 | onSubmit?.(rest.values);
32 | }}>
33 | {children}
34 |
35 |
36 | );
37 | },
38 | []
39 | );
40 |
41 | Form.api = api;
42 |
43 | return React.memo(Form);
44 | };
45 |
46 | export default FormComponent;
47 |
48 | export const FormStyled = styled.form`
49 | background-color: ${({ theme }) => theme[EThemes.BG_SECONDARY]};
50 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
51 | display: grid;
52 | grid-template-columns: 1fr;
53 | gap: 1rem;
54 | padding: 2rem;
55 | border-radius: 6px;
56 | text-align: center;
57 | min-width: 300px;
58 | `;
59 |
--------------------------------------------------------------------------------
/src/components/Form/Input.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useMemo, useState } from 'react';
2 | import styled, { css } from 'styled-components';
3 |
4 | import useInput from './hook/useInput';
5 | import { EThemes } from '../../Theme/theme';
6 | import { useFormContext } from './hook/useForm';
7 |
8 | export interface Props {
9 | name: string;
10 | placeholder?: string;
11 | initValue?: string;
12 | type?: string;
13 | required?: boolean;
14 | validator?: {
15 | regex: RegExp;
16 | message: string;
17 | };
18 | }
19 |
20 | const Input: React.FC = (props) => {
21 | const { name, validator, placeholder, type, required, initValue } = props;
22 |
23 | const input = useInput(initValue);
24 |
25 | const { setValues } = useFormContext();
26 |
27 | const [touched, setTouched] = useState(false);
28 |
29 | const [error, setError] = useState('');
30 |
31 | const inputMethods = useMemo(
32 | () => ({
33 | onBlur: () => setValues({ [name]: input.value }),
34 |
35 | onFocus: () => {
36 | if (!touched) setTouched(true);
37 | },
38 | }),
39 | [input.value, name, setValues, touched]
40 | );
41 |
42 | useEffect(() => {
43 | if (validator && touched) {
44 | const isValid = validator.regex.test(input.value);
45 |
46 | if (!isValid) setError(validator.message);
47 | else setError('');
48 | }
49 | }, [input.value, touched, validator]);
50 |
51 | return (
52 |
53 |
62 | {error}
63 |
64 | );
65 | };
66 |
67 | export default Input;
68 |
69 | export const InputStyled = styled.input`
70 | padding: 0.5rem 0.2rem;
71 | width: 100%;
72 | border-radius: 6px;
73 | border-color: transparent;
74 | outline: none;
75 | transition: 0.3s ease;
76 | background-color: ${({ theme }) => theme[EThemes.BG_PRIMARY]};
77 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
78 | &:focus {
79 | border-color: limegreen;
80 | }
81 | `;
82 |
83 | export const Error = styled.div<{ error: string }>`
84 | color: orangered;
85 | min-width: 10px;
86 | padding: 0.1rem;
87 | text-align: start;
88 | font-size: small;
89 | letter-spacing: 0.1rem;
90 | opacity: 0;
91 | width: 0;
92 | transition: 0.2s ease;
93 |
94 | ${({ error }) =>
95 | !!error &&
96 | css`
97 | opacity: 1;
98 | width: auto;
99 | `}
100 | `;
101 |
102 | export const Wrapper = styled.div``;
103 |
--------------------------------------------------------------------------------
/src/components/Form/form.types.ts:
--------------------------------------------------------------------------------
1 | import { Dispatch, Context } from 'react';
2 |
3 | export type Values = Record;
4 |
5 | export interface InitState {
6 | values: Record;
7 | setValues: Dispatch;
8 | }
9 |
10 | export interface Api extends InitState {
11 | formContext: Context;
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/Form/hook/useForm.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useMemo, useReducer } from 'react';
2 |
3 | import { InitState, Values } from '../form.types';
4 | import FormComponent from '../FormComponent';
5 |
6 | const initState = {
7 | values: {},
8 | setValues: () => {},
9 | };
10 |
11 | const formContext = createContext(initState);
12 |
13 | export const useForm = () => {
14 | const [values, setValues] = useReducer(
15 | (state: Values, newState: Values) => ({ ...state, ...newState }),
16 | {}
17 | );
18 |
19 | const api = useMemo(
20 | () => ({
21 | values,
22 | setValues,
23 | formContext,
24 | }),
25 | [values]
26 | );
27 |
28 | const Form = FormComponent(api);
29 |
30 | return { ...api, Form };
31 | };
32 |
33 | export const useFormContext = () => useContext(formContext);
34 |
--------------------------------------------------------------------------------
/src/components/Form/hook/useInput.ts:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useState } from 'react';
2 |
3 | const useInput = (init: string = '') => {
4 | const [value, setValue] = useState(() => init);
5 |
6 | const onChange = useCallback(
7 | (e: React.ChangeEvent) => setValue(e.target.value),
8 | []
9 | );
10 |
11 | return { value, onChange };
12 | };
13 |
14 | export default useInput;
15 |
--------------------------------------------------------------------------------
/src/components/Header/Header.styles.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { IThemes } from '../../Theme/theme';
3 |
4 | export const HeaderStyled = styled.header`
5 | position: relative;
6 | padding: 1rem 1rem;
7 | border-bottom: 1px solid hsla(0, 0%, 50%, 0.432);
8 | display: flex;
9 | `;
10 |
11 | export const Nav = styled.nav`
12 | flex: 1;
13 | display: flex;
14 | `;
15 |
16 | export const NavItem = styled.div`
17 | position: relative;
18 | font-size: 1.4rem;
19 | cursor: pointer;
20 |
21 | &::before {
22 | content: '';
23 | position: absolute;
24 | top: 30px;
25 | height: 2px;
26 | width: 0;
27 | opacity: 0;
28 | transition: 0.3s ease;
29 | background: ${({ theme }) => theme['text-primary']};
30 | }
31 |
32 | &:hover {
33 | &::before {
34 | width: 146px;
35 | opacity: 1;
36 | }
37 | }
38 | `;
39 |
40 | export const ToggleButton = styled.button`
41 | position: absolute;
42 | right: 14px;
43 | top: 4px;
44 | background: transparent;
45 | display: grid;
46 | place-items: center;
47 | border: none;
48 | height: 50px;
49 | width: 50px;
50 | cursor: pointer;
51 | transition: 0.1s ease-out;
52 | opacity: 0.85;
53 | border-radius: 50%;
54 | outline: none;
55 |
56 | @media print {
57 | display: none;
58 | }
59 |
60 | &::after {
61 | content: attr(aria-label);
62 | background: ${({ theme }) => theme['text-primary']};
63 | color: ${({ theme }) => theme['bg-primary']};
64 | position: absolute;
65 | top: 10px;
66 | left: -80px;
67 | transform: scale(0);
68 | opacity: 0;
69 | width: max-content;
70 | border-radius: 6px;
71 | transition: 0.3s ease;
72 | padding: 0.5rem 1rem;
73 | }
74 |
75 | &:hover {
76 | &::after {
77 | left: -160px;
78 | opacity: 0.8;
79 | transform: scale(1);
80 | }
81 | }
82 |
83 | &:hover,
84 | &:focus {
85 | opacity: 1;
86 | background: hsla(0, 0%, 50%, 0.5);
87 | }
88 | `;
89 |
90 | export const SvgToggleDark = styled.svg`
91 | width: 33px;
92 | height: 33px;
93 |
94 | .sun,
95 | .circle {
96 | fill: ${({ theme }) => theme['text-primary']};
97 | }
98 |
99 | .sun {
100 | transform-origin: center center;
101 | transition: transform 750ms cubic-bezier(0.11, 0.14, 0.29, 1.32);
102 | }
103 |
104 | .circle {
105 | transition: 0.25s ease-out;
106 | }
107 |
108 | .sun.dark {
109 | transform: rotate(0.5turn);
110 | }
111 |
112 | .circle.dark {
113 | transform: translateX(-80px);
114 | }
115 | `;
116 |
--------------------------------------------------------------------------------
/src/components/Header/Header.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useNavigate } from 'react-router-dom';
3 |
4 | import { HeaderStyled, Nav, NavItem, SvgToggleDark, ToggleButton } from './Header.styles';
5 | import { Theme, useTheme } from '../../hooks/useTheme';
6 | import { ERoutes } from '../../static/enums';
7 |
8 | const inverseTheme = (theme: Theme) => (theme === 'light' ? 'dark' : 'light');
9 |
10 | interface Props {}
11 |
12 | export const LOGO = `ADIAT HASAN`;
13 |
14 | const Header: React.FC = () => {
15 | const navigate = useNavigate();
16 |
17 | const { theme, toggleTheme } = useTheme();
18 |
19 | return (
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | export default Header;
39 |
--------------------------------------------------------------------------------
/src/components/Layout/ScreenLayout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styled from 'styled-components';
4 | import {Helmet} from 'react-helmet';
5 |
6 | interface Props {
7 | title?: string;
8 | }
9 |
10 | const ScreenLayout: React.FC = ({title = '', children}) => {
11 | return (
12 |
13 |
14 | ADIAT HASAN {'| ' + title}
15 |
16 | {children}
17 |
18 | );
19 | };
20 |
21 | export default ScreenLayout;
22 |
23 | const ScreenLayoutStyled = styled.div`
24 | min-height: 400px;
25 | min-width: 340px;
26 | `;
27 |
--------------------------------------------------------------------------------
/src/components/Selection/Selection.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import { FaCheck } from 'react-icons/fa';
4 | import { pop } from '../styles/Animations';
5 |
6 | interface Props {
7 | selected: boolean;
8 | label: any;
9 | }
10 |
11 | const Selection: React.FC = (props) => {
12 | const { selected, label } = props;
13 |
14 | return (
15 |
16 |
17 | {selected && }
18 |
19 | {label}
20 |
21 | );
22 | };
23 |
24 | export default Selection;
25 |
26 | const SelectionContainer = styled.div`
27 | display: flex;
28 | align-items: center;
29 |
30 | .flex-1 {
31 | flex: 1;
32 | }
33 | `;
34 |
35 | const CheckBox = styled.div`
36 | padding: 1px;
37 | width: 20px;
38 | height: 20px;
39 | border-radius: 4px;
40 | border: 1px solid limegreen;
41 | margin-right: 0.5rem;
42 | `;
43 |
44 | const CheckIcon = styled(FaCheck)`
45 | border-radius: inherit;
46 |
47 | animation: ${pop} 0.3s ease forwards;
48 | `;
49 |
--------------------------------------------------------------------------------
/src/components/TreeView/TreeView.tsx:
--------------------------------------------------------------------------------
1 | import React, {HTMLAttributes} from 'react';
2 | import {useLocation, useNavigate} from 'react-router-dom';
3 | import {RiArrowRightSFill} from 'react-icons/ri';
4 | import styled from 'styled-components';
5 |
6 | import {_} from '../../utils/_';
7 | import {EUrl} from '../../static/url';
8 | import {childData, viewData} from './data';
9 | import {EThemes} from '../../Theme/theme';
10 | import {getUrlParam} from '../../utils/misc';
11 | import Selection from '../Selection/Selection';
12 |
13 | interface Props {
14 | data: typeof viewData;
15 | onToggle?: (index: number, checked: boolean) => void;
16 | }
17 |
18 | const TreeView: React.FC = (props) => {
19 | const navigate = useNavigate();
20 | const location = useLocation();
21 |
22 | const {data, onToggle} = props;
23 |
24 | /**
25 | * convert it to hook
26 | */
27 | const attributes = getUrlParam(location, EUrl.Attributes)?.split(',');
28 |
29 | const urlPusher = (name: string) => {
30 | if (!attributes) {
31 | navigate(location.pathname + `?${EUrl.Attributes}=${name}`);
32 | return;
33 | }
34 |
35 | let ref = [...attributes];
36 |
37 | if (attributes.includes(name)) {
38 | ref = ref.filter((attr) => attr !== name);
39 | } else {
40 | ref.push(name);
41 | }
42 |
43 | if (_.isArrayEmpty(ref)) {
44 | navigate(location.pathname);
45 | return;
46 | }
47 |
48 | navigate(location.pathname + `?${EUrl.Attributes}=${ref.join(',')}`);
49 | };
50 |
51 | return (
52 |
53 | {data.map((child, i) => {
54 | const {children, name, show} = child;
55 | const selected = !!attributes?.includes(name);
56 |
57 | return (
58 |
59 | {_.isArrayEmpty(children) ? (
60 |
67 | ) : (
68 |
onToggle?.(i, !child.show)}>
72 |
73 | {name}
74 |
75 | )}
76 |
77 | {show &&
78 | children.map((child, i) => {
79 | const selected = !!attributes?.includes(child.name);
80 | return (
81 |
87 | );
88 | })}
89 |
90 | );
91 | })}
92 |
93 | );
94 | };
95 |
96 | export default TreeView;
97 |
98 | interface ChildProps {
99 | child: typeof childData;
100 | selected: boolean;
101 | urlPusher: (name: string) => void;
102 | }
103 |
104 | let ChildComponent: React.FC> = (props) => {
105 | const {selected, urlPusher, child, ...rest} = props;
106 |
107 | return (
108 | urlPusher(child.name)} index={0}>
109 |
113 | {child.name}
114 | {child.value}
115 |
116 | }
117 | />
118 |
119 | );
120 | };
121 |
122 | ChildComponent = React.memo(ChildComponent)
123 |
124 | const ParentNode = styled.a<{ active: boolean }>`
125 | &::selection {
126 | color: transparent;
127 | }
128 |
129 | display: flex;
130 | align-items: center;
131 | justify-content: flex-start;
132 | font-weight: bold;
133 | letter-spacing: 0.1rem;
134 | font-size: large;
135 | margin: 0.45rem 0;
136 | cursor: pointer;
137 | padding: 0.5rem;
138 | border-radius: 6px;
139 | transition: 0.3s ease all;
140 | background-color: ${({theme}) => theme[EThemes.BG_PRIMARY]};
141 |
142 | border: 1px solid ${({active}) => (active ? 'limegreen' : 'transparent')};
143 |
144 | &:hover {
145 | filter: brightness(120%);
146 | }
147 | `;
148 |
149 | const ArrowIndicator = styled(RiArrowRightSFill)<{ active: boolean }>`
150 | margin-right: 0.25rem;
151 | transition: 0.3s ease all;
152 | transform: rotate(${({active}) => (active ? '90deg' : '0deg')});
153 | `;
154 |
155 | const Label = styled.div`
156 | display: grid;
157 | grid-template-columns: 1fr 1fr;
158 |
159 | p {
160 | &:last-child {
161 | background-color: ${({theme}) => theme[EThemes.BG_SECONDARY]};
162 | border-radius: 4px;
163 | padding: 0.1rem;
164 | text-align: center;
165 | }
166 | }
167 | `;
168 |
169 | const ChildNode = styled.div<{ index: number }>`
170 | margin: 0.25rem 0;
171 | cursor: pointer;
172 | padding: 0.25rem 0.5rem;
173 | border-radius: 4px;
174 | margin-left: 1rem;
175 | filter: brightness(100%);
176 | background-color: ${({theme}) => theme[EThemes.BG_PRIMARY]};
177 | animation: mount 0.3s ease-out forwards;
178 |
179 | &:hover {
180 | filter: brightness(120%);
181 | }
182 |
183 | @keyframes mount {
184 | 0% {
185 | transform: translateY(-10px);
186 | }
187 | 100% {
188 | transform: translateY(0);
189 | }
190 | }
191 | `;
192 |
--------------------------------------------------------------------------------
/src/components/TreeView/data.ts:
--------------------------------------------------------------------------------
1 | export const viewData = [
2 | {
3 | name: 'Main',
4 | value: null,
5 | show: false,
6 | selected: null,
7 | count: null,
8 | children: [
9 | {
10 | name: 'MotherBoard',
11 | children: [],
12 | value: 'm4 ',
13 | selected: false,
14 | count: 29,
15 | },
16 | {
17 | name: 'Cpu',
18 | children: [],
19 | value: 'm4 k4',
20 | selected: false,
21 | count: 9,
22 | },
23 | {
24 | name: 'Ram',
25 | children: [],
26 | value: 'm4 ',
27 | selected: false,
28 | count: 2,
29 | },
30 | ],
31 | },
32 | {
33 | name: 'Decode',
34 | show: false,
35 | children: [
36 | {
37 | name: 'Dope',
38 | children: [],
39 | value: 'm4 d9',
40 | selected: false,
41 | count: 101,
42 | },
43 | {
44 | name: 'Dam',
45 | children: [],
46 | value: 'socket',
47 | selected: false,
48 | count: 33,
49 | },
50 | ],
51 | },
52 | {
53 | name: 'No child',
54 | value: 'boket',
55 | show: false,
56 | selected: false,
57 | children: [],
58 | count: 89,
59 | },
60 | ];
61 |
62 | export const childData = {
63 | name: 'MotherBoard',
64 | children: [],
65 | value: 'm4 ',
66 | selected: false,
67 | };
68 |
--------------------------------------------------------------------------------
/src/components/styles/Animations.tsx:
--------------------------------------------------------------------------------
1 | import { keyframes } from 'styled-components';
2 |
3 | export const pop = keyframes`
4 | 0% {
5 | opacity: 0;
6 | transform: scale(0);
7 | }
8 | 75% {
9 | opacity: 1;
10 | transform: scale(1.1);
11 | }
12 | 100% {
13 | opacity: 1;
14 | transform: scale(1);
15 | }
16 | `;
17 |
--------------------------------------------------------------------------------
/src/components/styles/Button.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | import { EThemes } from '../../Theme/theme';
4 |
5 | export const Button = styled.button`
6 | padding: 0.5rem 0.3rem;
7 | outline: none;
8 | border-color: transparent;
9 | border-radius: 6px;
10 | width: 100%;
11 | transition: 0.3s ease;
12 | cursor: pointer;
13 | &:focus {
14 | border-color: limegreen;
15 | }
16 | `;
17 |
18 | export const ButtonPrimary = styled(Button)`
19 | background-color: ${({ theme }) => theme[EThemes.BTN_PRIMARY]};
20 | color: ${({ theme }) => theme[EThemes.BG_PRIMARY]};
21 | `;
22 |
--------------------------------------------------------------------------------
/src/components/styles/LinkCustom.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | import styled from 'styled-components';
3 | import { EThemes } from '../../Theme/theme';
4 |
5 | export const LinkCustom = styled(Link)`
6 | text-decoration: none;
7 | color: ${({ theme }) => theme[EThemes.LINK_PRIMARY]};
8 | font-size: large;
9 | font-weight: 600;
10 | `;
11 |
12 | export const LinkBlank = styled.a`
13 | text-decoration: none;
14 | color: ${({ theme }) => theme[EThemes.LINK_PRIMARY]};
15 | font-size: large;
16 | font-weight: 600;
17 | `;
18 |
--------------------------------------------------------------------------------
/src/components/styles/Main.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | import { EThemes } from '../../Theme/theme';
4 |
5 | export const MainWrapper = styled.main`
6 | position: relative;
7 | background-color: ${({ theme }) => theme[EThemes.BG_SECONDARY]};
8 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
9 | padding: 2rem;
10 | border-radius: 2px;
11 | min-width: 300px;
12 | box-shadow: 0 0 15px -2px rgba(0, 0, 0, 0.1);
13 | `;
14 |
--------------------------------------------------------------------------------
/src/hooks/useClickOutside.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export function useOnClickOutside(
4 | ref: React.MutableRefObject,
5 | handler: () => void
6 | ) {
7 | const cbRef = React.useRef(handler);
8 |
9 | React.useEffect(() => {
10 | cbRef.current = handler;
11 | });
12 |
13 | React.useEffect(
14 | () => {
15 | const listener = (event: MouseEvent | TouchEvent) => {
16 | // Do nothing if clicking ref's element or descendent elements
17 | if (!ref.current || ref.current.contains(event.target)) {
18 | return;
19 | }
20 |
21 | cbRef.current();
22 | };
23 |
24 | document.addEventListener('mousedown', listener);
25 | document.addEventListener('touchstart', listener);
26 |
27 | return () => {
28 | document.removeEventListener('mousedown', listener);
29 | document.removeEventListener('touchstart', listener);
30 | };
31 | },
32 | // Add ref and handler to effect dependencies
33 | // It's worth noting that because passed in handler is a new ...
34 | // ... function on every render that will cause this effect ...
35 | // ... callback/cleanup to run every render. It's not a big deal ...
36 | // ... but to optimize you can wrap handler in useCallback before ...
37 | // ... passing it into this hook.
38 | [ref, handler]
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/src/hooks/useDomRef.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export const useDomRef = () => {
4 | return React.useRef(null);
5 | };
6 |
--------------------------------------------------------------------------------
/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 | import { useAppThemeDispatch, useAppThemeValue } from '../Theme/ThemeReducer';
3 |
4 | export type Theme = 'light' | 'dark';
5 |
6 | export const useTheme = () => {
7 | const theme = useAppThemeValue();
8 |
9 | const themeDispatch = useAppThemeDispatch();
10 |
11 | const toggleTheme = useCallback(() => {
12 | if (theme === 'light') {
13 | themeDispatch({ type: 'TOGGLE_THEME_DARK', payload: 'dark' });
14 | return;
15 | }
16 |
17 | themeDispatch({
18 | type: 'TOGGLE_THEME_LIGHT',
19 | payload: 'light',
20 | });
21 | }, [theme, themeDispatch]);
22 |
23 | return { themeDispatch, theme, toggleTheme, isDark: theme === 'dark' };
24 | };
25 |
--------------------------------------------------------------------------------
/src/hooks/useToggle.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export const useToggle = (init = false) => {
4 | const [value, setValue] = React.useState(init);
5 |
6 | const toggleValue = (given?: boolean) =>
7 | typeof given !== 'undefined' ? setValue(given) : setValue((o) => !o);
8 |
9 | return [value, toggleValue] as const;
10 | };
11 |
--------------------------------------------------------------------------------
/src/hooks/useUpdateEffect.ts:
--------------------------------------------------------------------------------
1 | import { DependencyList, EffectCallback, useEffect, useRef } from 'react';
2 |
3 | export const useUpdateEffect = (cb: EffectCallback, deps?: DependencyList) => {
4 | const cbRef = useRef(cb);
5 |
6 | const isMounted = useRef(false);
7 |
8 | useEffect(() => {
9 | if (isMounted.current) {
10 | cbRef.current();
11 | return;
12 | }
13 |
14 | isMounted.current = true;
15 | // eslint-disable-next-line react-hooks/exhaustive-deps
16 | }, deps);
17 |
18 | return { isMounted };
19 | };
20 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 | import { AppThemeProvider } from './Theme/ThemeReducer';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
17 | // If you want to start measuring performance in your app, pass a function
18 | // to log results (for example: reportWebVitals(console.log))
19 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
20 | reportWebVitals();
21 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/routes/routes.tsx:
--------------------------------------------------------------------------------
1 | import {ERoutes} from '../static/enums';
2 |
3 | /**
4 | * Screens
5 | */
6 | import FormExampleScreen from '../screens/FormScreen/FormExampleScreen';
7 | import ClickOutside from '../screens/ClickOutside/ClickOutside';
8 | import HomeScreen from '../screens/Home/HomeScreen';
9 | import TreeFile from '../screens/TreeFile/TreeViewScreen';
10 | import StepExample from '../screens/StepMachine/StepExample';
11 | import Me from "../screens/Me/Me";
12 |
13 | export const routes = [
14 | {
15 | element: ,
16 | path: ERoutes.Home,
17 | },
18 | {
19 | element: ,
20 | path: ERoutes.Me,
21 | },
22 | {
23 | element: ,
24 | path: ERoutes.Form,
25 | },
26 | {
27 | element: ,
28 | path: ERoutes.ClickOutside,
29 | },
30 | {
31 | element: ,
32 | path: ERoutes.ReactStepMachine,
33 | },
34 | {
35 | element: ,
36 | path: ERoutes.TreeView,
37 | },
38 | ];
39 |
--------------------------------------------------------------------------------
/src/screens/ClickOutside/ClickOutside.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import { ImProfile } from 'react-icons/im';
4 | import { CgLogOut, CgProfile, CgArrowDown } from 'react-icons/cg';
5 |
6 | import { EThemes } from '../../Theme/theme';
7 | import { MainWrapper } from '../../components/styles/Main';
8 | import { ButtonPrimary } from '../../components/styles/Button';
9 | import ScreenLayout from '../../components/Layout/ScreenLayout';
10 | import useClickOutside from '../../components/ClickOutsideWrapper/useClickOutside';
11 | import ClickOutsideWrapper from '../../components/ClickOutsideWrapper/ClickOutsideWrapper';
12 |
13 | const ClickOutside: React.FC = () => {
14 | const { toggle, register } = useClickOutside();
15 |
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | -
26 |
27 |
30 |
31 | Dashboard
32 |
33 |
34 | -
35 |
36 |
39 |
40 | Logout
41 |
42 |
43 |
44 |
45 |
46 |
47 | );
48 | };
49 |
50 | export default ClickOutside;
51 |
52 | export const FloatingMenu = styled.div`
53 | position: absolute;
54 | right: 0px;
55 | top: 110%;
56 | border-radius: 6px;
57 | min-width: 100px;
58 | padding: 0.3rem;
59 | background-color: ${({ theme }) => theme[EThemes.BG_SECONDARY]};
60 | border: 1px solid ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
61 | box-shadow: 0 0 15px -2px rgba(0, 0, 0, 0.1);
62 | transform: translateY(10px);
63 | `;
64 |
65 | export const BtnRounded = styled.div`
66 | border-radius: 50%;
67 | margin-left: auto;
68 | height: 80px;
69 | width: 80px;
70 | display: flex;
71 | align-items: center;
72 | justify-content: center;
73 | cursor: pointer;
74 | background-color: ${({ theme }) => theme[EThemes.BG_PRIMARY]};
75 | `;
76 |
77 | export const BtnItem = styled(ButtonPrimary)`
78 | background-color: ${({ theme }) => theme[EThemes.BG_PRIMARY]};
79 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
80 | `;
81 |
82 | export const Item = styled.section`
83 | margin-bottom: 0.2rem;
84 | `;
85 |
86 | export const AnimArrow = styled(CgArrowDown)`
87 | transform: translateY(-10px);
88 | position: absolute;
89 | bottom: 100%;
90 | z-index: 1;
91 | right: 10%;
92 | animation: bounce 2s ease-in-out infinite alternate;
93 |
94 | @keyframes bounce {
95 | 0% {
96 | transform: translateY(-10px);
97 | }
98 | 100% {
99 | transform: translateY(20px);
100 | }
101 | }
102 | `;
103 |
--------------------------------------------------------------------------------
/src/screens/FormScreen/FormExampleScreen.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import Input from '../../components/Form/Input';
4 | import ScreenLayout from '../../components/Layout/ScreenLayout';
5 | import {useForm} from '../../components/Form/hook/useForm';
6 | import {ButtonPrimary} from '../../components/styles/Button';
7 |
8 | const FormExampleScreen: React.FC = () => {
9 | const {Form} = useForm();
10 |
11 | const handleSubmit = (values: any) => {
12 | alert(JSON.stringify(values, null, 2));
13 | };
14 |
15 | return (
16 |
17 |
38 |
39 | );
40 | };
41 |
42 | export default FormExampleScreen;
43 |
--------------------------------------------------------------------------------
/src/screens/Home/HomeScreen.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { LinkBlank, LinkCustom } from '../../components/styles/LinkCustom';
5 | import { patternLinks } from '../../static/me';
6 | import { EThemes } from '../../Theme/theme';
7 |
8 | const HomeScreen: React.FC = () => {
9 | return (
10 |
11 | {patternLinks
12 | .filter((link) => link.enabled)
13 | .map((data, i) => (
14 |
15 | {data.title}
16 |
17 | Demo!
18 |
19 | Code!
20 |
21 |
22 |
23 | ))}
24 |
25 | );
26 | };
27 |
28 | export default HomeScreen;
29 |
30 | export const LinkContainer = styled.div`
31 | display: flex;
32 | align-items: center;
33 |
34 | & > * {
35 | margin-right: 0.8rem;
36 | }
37 | `;
38 |
39 | export const H2 = styled.h2`
40 | margin-bottom: 1rem;
41 | `;
42 |
43 | export const Main = styled.main`
44 | padding: 1rem;
45 | width: 1200px;
46 | max-width: 100%;
47 | display: grid;
48 | grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
49 | gap: 2rem;
50 | perspective: 800px;
51 | `;
52 |
53 | export const Each = styled.div`
54 | background-color: ${({ theme }) => theme[EThemes.BG_SECONDARY]};
55 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
56 | padding: 2rem;
57 | border-radius: 6px;
58 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
59 | transition: 0.3s ease;
60 |
61 | &:hover {
62 | transform: scale(1.05);
63 | filter: brightness(1.3);
64 | }
65 | `;
66 |
--------------------------------------------------------------------------------
/src/screens/Me/Me.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { BiLinkExternal } from 'react-icons/bi';
3 | import { IoLogoStackoverflow } from 'react-icons/io5';
4 | import { AiFillGithub, AiFillLinkedin } from 'react-icons/ai';
5 |
6 | import { EThemes } from '../../Theme/theme';
7 | import { useTheme } from '../../hooks/useTheme';
8 | import ScreenLayout from '../../components/Layout/ScreenLayout';
9 |
10 | const Me = () => {
11 | const { isDark } = useTheme();
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
32 |
33 | Highly motivated and experienced Fullstack Software Developer with a passion for frontend engineering.
34 |
35 |
36 | My expertise mainly lies within Typescript, React.js, Node.js & Nest.js to create clean, reusable, and
37 | maintainable code. But this doesn't stop me from learning new technologies and languages and adopting them
38 | when needed.
39 |
40 |
41 | Currently I'm focusing on open source projects as it leads to a better understanding of certain concepts
42 | and also helps me to further sharpen my skills.
43 |
44 |
45 |
46 | Work Experience
47 |
48 |
49 | Senior Frontend Engineer{' '}
50 |
51 | Giraffe360
52 | {' '}
53 | (December 2023 - present)
54 |
55 |
56 | 1. Developing Video Editor with WebGL.
57 |
58 |
59 | Senior Software Engineer{' '}
60 |
61 | Blue Tech
62 | {' '}
63 | (October 2021 - November 2023)
64 |
65 |
66 | 1. Architected the frontend for bdtickets.com and a few internal apps.
67 | 2. Implemented scalable design patterns in client and server side
68 | 3. Reactive development for the type-safe data layer with React Query.
69 | 4. Adapted advanced patterns for effortless integration of api's with autogenerated type-safe hooks.{' '}
70 |
71 |
72 |
73 | Typescript
74 | React
75 | React-native
76 | Next
77 | Node
78 | Nest
79 | SSR
80 | SSG
81 | React-query
82 | Antd
83 |
84 |
85 | Frontend Engineer{' '}
86 |
87 | Xen Works
88 | {' '}
89 | (August 2021 - November 202)
90 |
91 |
92 | 1. Responsible for developing scalable UIs with solid principles.
93 | 2. Introducing effortlessly scalable type-safe integrations with material UI inputs and react-hook-form.{' '}
94 |
95 | 3. Adapting React Query while replacing redux for server-side type-safe data management through apis.{' '}
96 |
97 | 4. Introducing the pattern for autogenerated custom hooks for type-safe data fetching and mutation.
98 | 5. Providing solutions to team members for better optimization and maintainability of code.
99 | 6. Decision-making to further improvement of code quality and performance.
100 |
101 |
102 |
103 | Typescript
104 | React
105 | Redux
106 | Redux-logics
107 | React-query
108 | Tailwind
109 | Styled-components
110 |
111 |
112 | Frontend Engineer{' '}
113 |
114 | Now
115 | {' '}
116 | (January 2020 - July 2021)
117 |
118 |
119 | 1. Was in charge of developing the client side of now.com.bd from start to finish.
120 | 2. Technology used: React, Next.js, Typescript, React Query, Custom Hooks, Graphql, Sass, Tailwind.
121 | 3. Made the technical decisions by consulting with our tech lead to improve the projects.
122 |
123 | 4. Worked on Rider tracking mobile app [React Native]
124 |
125 |
126 |
127 | Typescript
128 | React
129 | React-native
130 | Next
131 | SSG
132 | React-query
133 | Graphql
134 | Parse Server
135 | Tailwind
136 | Styled-components
137 |
138 |
139 |
140 | Open Source Contributions
141 |
142 |
143 | Mui React Hook Form +
144 |
145 |
146 |
151 |
152 |
153 | The perfect recipe with material-ui 💙 TS 💙 react-hook-form &
154 | more. The complete type-safe material-ui and react-hook-form combo and beyond with simple api. Highly
155 | Customizable and supports 99% use-cases.
156 |
157 |
158 | Material ui is effective for building UI's of great UX & DX in a React project.
159 | To make it stateful, we have pay the price of sacrificing DX & sometimes lack of performance and
160 | no-scalability.{' '}
161 |
162 |
163 |
164 |
165 |
166 | React Store Maker
167 |
168 |
173 |
174 |
175 | It is a utility function for creating stores for global / local state management with the{' '}
176 | Context API approach in React.js applications. This simplifies contexts and reduces boiler
177 | plate code and has some built in optimization.
178 |
179 |
180 | While building the architecture BD tickets app I didn't want to use redux or other heavy state management
181 | library. I was using Contexts for small things and react-query for data fetching. Then I felt the
182 | necessity of writing a function that would just give the context instead of writing a lot of boiler plate
183 | code.{' '}
184 |
185 |
186 |
187 |
188 |
189 | React Step Machine
190 |
191 |
196 |
197 |
198 | A hook-based multi-step wizard library made for React.js apps with vast control over the logic of the user
199 | as per use-case. It's API is much simpler than other step wizards out there.
200 |
201 |
202 | The inspiration came form{' '}
203 |
204 | react-step-wizard
205 |
206 | . It didn't support my use-cases that I needed for my project. Hence, I built my own step wizard with
207 | recent react concepts.{' '}
208 |
209 |
210 |
211 |
212 |
213 |
214 | React Concepts
215 |
216 |
221 |
222 |
223 | Advanced concepts of react such as hooks, contexts, reusable components, custom hooks, prop getters, theme
224 | with styled-components, animations and more.
225 |
226 |
227 | When I learn a new concept in react I tend to practice it and share my work so that other developers can
228 | grasp the concepts and remain upto date with the industry standard.{' '}
229 |
230 |
231 |
232 |
233 |
234 | General Information's
235 | London 🇬🇧 United Kingdom
236 |
237 | +44 7432 113152
238 |
239 |
240 | adiathasan.me@gmail.com
241 |
242 |
243 |
244 | Skills
245 |
246 | Javascript
247 | Typescript
248 | Css
249 | Node
250 | Express
251 | Nest
252 | Parse Server
253 | Monorepo
254 | React
255 | React-native
256 | Next
257 | Svelte
258 | Solid.js
259 | React-query
260 | React-hook-form
261 | Material-ui
262 | React-testing-library
263 | Jest
264 | Redux
265 | Graphql
266 | Tailwind
267 | Antd
268 | Styled-components
269 |
270 |
271 |
272 | Related Links
273 |
274 | github.com/adiathasan
275 |
276 |
277 | linkedin.com/adiathasan
278 |
279 |
280 | leetcode.com/adiathasan
281 |
282 |
283 | stackoverflow.com/adiat-hasan
284 |
285 |
286 | adiathasan.medium.com
287 |
288 |
289 |
290 | Blogs
291 | 1.{' '}
292 |
293 | React Form made simple 🚀
294 |
295 |
296 |
297 | 2.{' '}
298 |
299 | Ditching Redux in React — Part 1 🏎️
300 |
301 |
302 |
303 | 3.{' '}
304 |
305 | Typesafe routes in Next.js 📘
306 |
307 |
308 |
309 | Education
310 | BSc in Computer Science & Engineering
311 |
312 |
313 | University of The People (2020 - present)
314 |
315 |
316 | Certifications
317 |
318 |
319 | Epic React by kent C. Dodds | Advanced React Patterns (01/2022 - Present){' '}
320 |
324 |
325 |
326 |
327 |
328 |
329 | HTML, CSS, and Javascript for Web Developers(coursera) (08/2020 - 08/2020){' '}
330 |
334 |
335 |
336 |
337 |
338 |
339 | Machine-learning(coursera) (05/2020 - 06/2020){' '}
340 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 | );
360 | };
361 |
362 | export default Me;
363 |
364 | export const Main = styled.main`
365 | width: 1400px;
366 | max-width: 100%;
367 | display: grid;
368 | grid-template-columns: repeat(12, 1fr);
369 | grid-gap: 1.4rem;
370 | min-height: 90vh;
371 | margin-top: 20px;
372 | margin-bottom: 60px;
373 |
374 | @media (max-width: 780px) {
375 | grid-template-columns: 1fr;
376 | }
377 | `;
378 |
379 | export const Each = styled.section<{ colSpan?: string; rowSpan?: string; hide?: boolean }>`
380 | background-color: ${({ theme }) => theme[EThemes.BG_SECONDARY]};
381 | color: ${({ theme }) => theme[EThemes.TEXT_PRIMARY]};
382 | padding: 1rem 1.5rem;
383 | grid-column: ${({ colSpan }) => colSpan};
384 | grid-row: ${({ rowSpan }) => rowSpan};
385 | opacity: ${({ hide }) => (hide ? 0 : 1)};
386 |
387 | @media (max-width: 780px) {
388 | grid-column: span 12;
389 | }
390 | `;
391 |
392 | export const Sides = styled.section<{ colSpan?: string; rowSpan?: string }>`
393 | grid-column: ${({ colSpan }) => colSpan};
394 | grid-row: ${({ rowSpan }) => rowSpan};
395 | display: grid;
396 | grid-template-columns: 1fr;
397 | grid-gap: 1.4rem;
398 |
399 | @media (max-width: 780px) {
400 | grid-column: span 12;
401 | grid-gap: 1rem;
402 | }
403 | `;
404 |
405 | export const Title = styled.h2`
406 | font-weight: bold;
407 | margin-bottom: 20px;
408 |
409 | @media (max-width: 780px) {
410 | font-size: 1.2rem;
411 | }
412 | `;
413 |
414 | export const ExternalIcon = styled(BiLinkExternal)`
415 | transform: translateY(5px);
416 | `;
417 |
418 | export const Chip = styled.span`
419 | border-radius: 4px;
420 | padding: 0.3rem 0.5rem;
421 | background-color: ${({ theme }) => theme[EThemes.BG_PRIMARY]};
422 | font-size: smaller;
423 | `;
424 |
425 | export const ChipContainer = styled.div`
426 | margin-top: 10px;
427 | margin-bottom: 30px;
428 | display: flex;
429 | gap: 6px;
430 | flex-wrap: wrap;
431 | `;
432 |
433 | export const Subtitle = styled.h4`
434 | font-weight: 600;
435 | margin-bottom: 14px;
436 | letter-spacing: 0.03rem;
437 | line-height: 25px;
438 |
439 | @media (max-width: 780px) {
440 | font-size: 0.9rem;
441 | }
442 | `;
443 |
444 | export const Text = styled.p`
445 | font-weight: 380;
446 | line-height: 25px;
447 | letter-spacing: 0.03rem;
448 | margin-bottom: 0.2rem;
449 |
450 | @media (max-width: 780px) {
451 | font-size: 0.9rem;
452 | }
453 | `;
454 |
--------------------------------------------------------------------------------
/src/screens/StepMachine/StepExample.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { StepMachine, Step, useStepActions, StepContainer } from 'react-step-machine';
3 |
4 | import Input from '../../components/Form/Input';
5 | import ScreenLayout from '../../components/Layout/ScreenLayout';
6 | import { useForm } from '../../components/Form/hook/useForm';
7 | import { MainWrapper } from '../../components/styles/Main';
8 | import { ButtonPrimary } from '../../components/styles/Button';
9 |
10 | interface FormValue {
11 | username: string;
12 | email: string;
13 | }
14 |
15 | const StepExample = () => {
16 | const { Form } = useForm();
17 |
18 | const handleSubmit = (values: FormValue) => {
19 | alert(JSON.stringify(values, null, 2));
20 | };
21 |
22 | return (
23 |
24 |
25 |
26 |
27 |
28 |
48 |
49 |
50 |
68 |
69 |
70 | You are awesome
71 |
72 |
73 |
74 |
75 |
76 |
77 | );
78 | };
79 |
80 | export default StepExample;
81 |
82 | export const ToggleBtn = () => {
83 | const { nextStep, previousStep } = useStepActions();
84 |
85 | return (
86 |
87 | previousStep()}>Prev
88 | nextStep()}>Next
89 |
90 | );
91 | };
92 |
--------------------------------------------------------------------------------
/src/screens/TreeFile/TreeViewScreen.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import ScreenLayout from '../../components/Layout/ScreenLayout';
5 | import TreeView from '../../components/TreeView/TreeView';
6 | import { viewData } from '../../components/TreeView/data';
7 | import { MainWrapper } from '../../components/styles/Main';
8 |
9 | const TreeViewScreen: React.FC = () => {
10 | const [state, setState] = useState(viewData);
11 |
12 | return (
13 |
14 |
15 |
18 | setState((old) => {
19 | const ref = [...old];
20 |
21 | ref[i].show = checked;
22 |
23 | return [...ref];
24 | })
25 | }
26 | />
27 |
28 |
29 | );
30 | };
31 |
32 | export default TreeViewScreen;
33 |
34 | const TreeViewContainer = styled(MainWrapper)`
35 | min-height: 38vh;
36 | `;
37 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/static/enums.ts:
--------------------------------------------------------------------------------
1 | export enum ERoutes {
2 | Home = '/',
3 | Me = '/me',
4 | Form = '/form-hook-pattern',
5 | ClickOutside = '/click-outside',
6 | TreeView = '/tree-view',
7 | ReactStepMachine = '/react-step-machine',
8 | }
9 |
10 | export enum EComponentNames {
11 | ReactStepMachine = 'react-step-machine',
12 | ClickOutside = 'click-outside',
13 | Form = 'form-hook-pattern',
14 | TreeView = 'tree-view',
15 | }
16 |
17 | export enum ECodeLinks {
18 | ReactStepMachine = 'react-step-machine',
19 | Form = 'components/Form/hook/useForm.tsx',
20 | ClickOutside = 'components/ClickOutsideWrapper',
21 | TreeView = 'components/TreeView',
22 | }
23 |
--------------------------------------------------------------------------------
/src/static/me.ts:
--------------------------------------------------------------------------------
1 | import { joinRepo } from '../utils/misc';
2 | import { ECodeLinks, EComponentNames, ERoutes } from './enums';
3 |
4 | export const GITHUB = 'https://github.com/adiathasan';
5 |
6 | export const REPO = 'https://github.com/adiathasan/react-concepts/blob/master/src';
7 |
8 | export const patternLinks = [
9 | {
10 | title: EComponentNames.Form,
11 | code: joinRepo(REPO, ECodeLinks.Form),
12 | link: ERoutes.Form,
13 | isExternal: false,
14 | enabled: true,
15 | },
16 | {
17 | title: EComponentNames.ClickOutside,
18 | code: joinRepo(REPO, ECodeLinks.ClickOutside),
19 | link: ERoutes.ClickOutside,
20 | isExternal: false,
21 | enabled: true,
22 | },
23 | {
24 | title: EComponentNames.TreeView,
25 | code: joinRepo(REPO, ECodeLinks.TreeView),
26 | link: ERoutes.TreeView,
27 | isExternal: false,
28 | enabled: true,
29 | },
30 | {
31 | title: EComponentNames.ReactStepMachine,
32 | code: joinRepo(GITHUB, ECodeLinks.ReactStepMachine),
33 | link: ERoutes.ReactStepMachine,
34 | isExternal: false,
35 | enabled: true,
36 | },
37 | {
38 | title: 'more-pattern (coming...)',
39 | code: GITHUB,
40 | link: '',
41 | isExternal: true,
42 | enabled: true,
43 | },
44 | ];
45 |
--------------------------------------------------------------------------------
/src/static/url.ts:
--------------------------------------------------------------------------------
1 | export enum EUrl {
2 | Attributes = 'attributes',
3 | }
4 |
--------------------------------------------------------------------------------
/src/store/StoreProvider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const StoreContext = React.createContext(null);
4 | const StoreDispatchContext = React.createContext(null);
5 |
6 | interface StoreProviderProps {
7 | init: S;
8 | reducer: (state: S, action: A) => S;
9 | children?: React.ReactNode;
10 | }
11 |
12 | const StoreProvider = (props: StoreProviderProps) => {
13 | const { children, init, reducer } = props;
14 |
15 | const [state, dispatch] = React.useReducer(reducer, init);
16 |
17 | return (
18 |
19 |
20 | {children}
21 |
22 |
23 | );
24 | };
25 |
26 | export default StoreProvider;
27 |
28 | export const useStore = () => {
29 | const store = React.useContext(StoreContext);
30 |
31 | if (!store) {
32 | throw new Error('StoreProvider not found');
33 | }
34 |
35 | return store;
36 | };
37 |
38 | export const useStoreDispatch = () => {
39 | const dispatch = React.useContext>(StoreDispatchContext);
40 |
41 | if (!dispatch) {
42 | throw new Error('StoreDispatchProvider not found');
43 | }
44 |
45 | return dispatch;
46 | };
47 |
--------------------------------------------------------------------------------
/src/store/makeStore.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | interface StoreProviderProps {
4 | children?: React.ReactNode;
5 | }
6 |
7 | const makeStore = (init: S, reducer: (state: S, action: A) => S) => {
8 | const StoreContext = React.createContext(null);
9 | const StoreDispatchContext = React.createContext(null);
10 |
11 | const StoreProvider = (props: StoreProviderProps) => {
12 | const { children } = props;
13 |
14 | const [state, dispatch] = React.useReducer(reducer, init);
15 |
16 | return (
17 |
18 | {children}
19 |
20 | );
21 | };
22 |
23 | const useStore = () => {
24 | const store = React.useContext(StoreContext);
25 |
26 | if (!store) {
27 | throw new Error('makestore->fn: useStore must be used within a Provider');
28 | }
29 |
30 | return store;
31 | };
32 |
33 | const useDispatch = () => {
34 | const dispatch = React.useContext>(StoreDispatchContext);
35 |
36 | if (!dispatch) {
37 | throw new Error('makestore->fn: useDispatch must be used within a Provider');
38 | }
39 |
40 | return dispatch;
41 | };
42 |
43 | return [StoreProvider, useStore, useDispatch] as const;
44 | };
45 |
46 | export default makeStore;
47 |
--------------------------------------------------------------------------------
/src/utils/_.ts:
--------------------------------------------------------------------------------
1 | const isArrayEmpty = (arr: T[]) => arr.length === 0;
2 |
3 | const isFirstItem = (_arr: T[], i: number) => i === 0;
4 |
5 | const isLastItem = (arr: T[], i: number) => arr.length - 1 === i;
6 |
7 | export const _ = { isArrayEmpty, isFirstItem, isLastItem };
8 |
--------------------------------------------------------------------------------
/src/utils/misc.ts:
--------------------------------------------------------------------------------
1 | export const joinRepo = (repo: string, file: string) => `${repo}/${file}`;
2 |
3 | export const getUrlParam = (location: any, name: string) =>
4 | new URLSearchParams(location.search).get(name);
5 |
6 | export const callAll = (...fns: Function[]) => (...values: any) => fns.map(fn => fn?.(...values))
--------------------------------------------------------------------------------
/talk.md:
--------------------------------------------------------------------------------
1 | REACT ->
2 |
3 | Provides->
4 |
5 | 0.
6 | 1. SPA -> .
7 | 2. Why FC replaces CC.
8 | 3. HOOKS are the future + awesome.
9 | 4. Why I love hooks.
10 | 5. Context API Can Replace Redux + React query.
11 | 6. Bad Idea to use CDN libraries. As react has it's own Virtual dom. Also we can't bundle the code and tree shake if we do so.
12 | 7. Modular CSS for better file structure.
13 | 8. Folder Structure [x] .
14 | 9. Why I never going back to JS -> TS is super.
15 |
16 | NEXT -> React With Superpower
17 | -> 12
18 | Provides ->
19 |
20 | 0.
21 | 1. SWC build-in.
22 | 2. Page base routing.
23 | 3. CSR -> Client -> React.
24 | 4. SSR -> Server -> React (hydrate).
25 | 5. SSG -> Static -> \*\*\* .
26 | 6. Auto Performance Optimization.
27 | 7. Ts support out of the box.
28 | 8. Server-less approach [x].
29 | 9. JAM-stack.
30 | 10. Easy deployment with Vercel.
31 |
32 | github repo -> https://github.com/adiathasan/react-concepts
33 |
34 | live demo -> https://adiathasan.vercel.app
35 |
36 | Theme -> VS.Code dark
37 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------