├── .DS_Store ├── .gitignore ├── algo ├── animate-right.html ├── common-ancestor.html ├── dom-store.html ├── fibonacci-using-closure.js ├── find-node-in-another-similar-tree.html ├── mirror-dom.js └── print-dom.html ├── browser ├── check-user-activity-on-page │ ├── focus.html │ └── visibility.html ├── cookies │ ├── client-credentials-grant.png │ ├── cookies-local-session.md │ ├── cookies-session.md │ └── security.md ├── dom-properties-methods │ └── readme.md ├── dom │ └── readme.md ├── event-delegation │ ├── bubble-up.png │ ├── event-bubbling.gif │ ├── event-capturing-bubbling.png │ └── readme.md ├── js │ └── security.md ├── oauth │ └── readme.md ├── render │ ├── browser.png │ ├── cssom-timeline.png │ ├── dom-timeline.png │ ├── gecko.jpg │ ├── layout-viewport.png │ ├── readme.md │ ├── render-cssom.png │ ├── render-dom.png │ ├── render.png │ └── webkit.png ├── scroll │ ├── infinite.html │ ├── nested.html │ ├── readme.md │ └── simple.html ├── tcp-handshake │ └── readme.md └── what-happens-when │ └── readme.md ├── css ├── box-model │ ├── box-model.png │ └── readme.md ├── flex-box │ └── readme.md └── priority │ ├── css-priority.jpg │ └── readme.md ├── implementation ├── LWWElementSet │ ├── index.js │ ├── index.test.js │ ├── package.json │ └── yarn.lock ├── array │ ├── filter.js │ ├── flatten.js │ ├── forEach.js │ ├── map.js │ └── reduce.js ├── binary-indexed-tree │ └── index.js ├── bind │ └── index.js ├── clearAllTimeouts │ └── index.js ├── debounce-vs-throttle │ ├── debouncing-vs-throttling.gif │ ├── index.html │ └── index.js ├── event-emitter │ ├── advanced.js │ ├── advanced.ts │ ├── basic.js │ ├── event.jpg │ ├── readme.md │ ├── simple-subclass.js │ └── standard.js ├── fetch-timeout │ └── index.js ├── fetch │ ├── index.html │ └── index.js ├── heap │ └── index.js ├── lfu-cache │ └── index.js ├── lru-cache │ ├── use_linked_list_hashtable.js │ └── use_map.js ├── min-queue │ ├── advanced.js │ └── easy.js ├── objects-merge │ └── index.js ├── observable │ └── simple.js ├── promise.all │ └── index.js ├── promise.pool │ └── index.js ├── promise │ └── simple.js ├── promisify │ └── index.js ├── pubsub-vs-observer │ ├── observer.png │ ├── pubsub.gif │ ├── readme.md │ └── vs.jpeg ├── pubsub │ └── index.js ├── server-sent-events │ ├── client │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── logo192.png │ │ │ ├── logo512.png │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ ├── src │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── index.css │ │ │ ├── index.js │ │ │ ├── logo.svg │ │ │ ├── reportWebVitals.js │ │ │ └── setupTests.js │ │ └── yarn.lock │ ├── demo.png │ ├── readme.md │ └── server │ │ ├── package.json │ │ └── server.js ├── sleep │ └── index.js └── virtual-dom │ ├── .DS_Store │ └── prototype │ ├── main.html │ └── main.js ├── js-knowledge ├── .DS_Store ├── amd-vs-common-es │ └── readme.md ├── apply-call-bind │ ├── apply.js │ ├── bind.js │ └── call.js ├── call-stack-overflow │ └── index.js ├── callback-promise-generator-asyncwait │ ├── async-await.js │ ├── generator.js │ ├── promise.js │ └── readme.md ├── child-process │ ├── child.js │ ├── parent.js │ └── readme.md ├── chrome-profile-template │ ├── index.html │ └── script.js ├── class-vs-prototype │ ├── class.js │ └── prototype.js ├── closure │ └── index.js ├── const-let-var │ └── readme.md ├── currying │ ├── index.js │ └── readme.md ├── equal │ └── index.js ├── event-loop │ ├── event-loop.png │ └── readme.md ├── hoist │ └── index.js ├── memory-object-life │ └── index.js ├── memory-profile-on-web │ ├── .DS_Store │ ├── 1a.png │ ├── 1b.png │ ├── index.html │ ├── js-memory-management.md │ └── script.js ├── middleware │ └── readme.md ├── mixins │ └── readme.md ├── node-cluster │ └── index.js ├── prototype │ ├── basic.js │ └── chain.js ├── react │ └── readme.md ├── referencing │ ├── array.js │ ├── object.js │ ├── primitive.js │ └── readme.md ├── self-invoking │ └── index.js ├── singleton │ ├── God.js │ └── index.js └── this │ ├── 1_constructor.js │ ├── 2_apply_call_bind.js │ ├── 3_method.js │ ├── 4_global.js │ ├── 6_arrow.js │ └── sample_quesiton.js ├── optimization ├── backend.md └── frontend.md ├── react-widgets-implementation ├── books-paginated-search │ ├── .gitignore │ ├── README.md │ ├── jsconfig.json │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.js │ │ ├── App.module.css │ │ ├── App.test.js │ │ ├── api.js │ │ ├── components │ │ │ └── BookList │ │ │ │ └── index.js │ │ ├── hooks │ │ │ └── useDebounce.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reducers │ │ │ └── appReducer.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock ├── context-counter │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── components │ │ │ └── Coordinate.js │ │ ├── contexts │ │ │ └── AppContext.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock ├── credit-card │ ├── README.md │ ├── Screenshot 2023-04-26 at 15.53.49.png │ ├── Screenshot 2023-04-26 at 15.54.01.png │ ├── Screenshot 2023-04-29 at 01.06.18.png │ ├── Screenshot 2023-04-29 at 01.06.23.png │ ├── Screenshot 2023-04-29 at 01.06.34.png │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ ├── robots.txt │ │ └── visa_logo.png │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── debounced-pokemon-search │ ├── .eslintrc.json │ ├── README.md │ ├── app │ │ ├── api │ │ │ └── pokemon │ │ │ │ └── route.js │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.js │ │ ├── page.js │ │ └── page.module.css │ ├── components │ │ ├── PokemonList │ │ │ └── index.js │ │ └── SearchInput │ │ │ └── index.js │ ├── hooks │ │ └── useDebounce.js │ ├── jsconfig.json │ ├── mock-db │ │ └── index.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ └── public │ │ ├── next.svg │ │ └── vercel.svg ├── debounced-search │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── components │ │ └── NewsCell │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── index.css │ │ ├── index.js │ │ ├── reportWebVitals.js │ │ ├── setupTests.js │ │ └── utils │ │ └── useDebounce.js ├── game-of-life │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── pokemon-search │ ├── .gitignore │ ├── CODEOWNERS │ ├── README.md │ ├── example.png │ ├── lerna.json │ ├── package.json │ ├── packages │ │ ├── poke-search-js │ │ │ ├── .eslintrc.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── components │ │ │ │ └── PokeCard │ │ │ │ │ └── index.js │ │ │ ├── next.config.js │ │ │ ├── package.json │ │ │ ├── pages │ │ │ │ ├── _app.js │ │ │ │ └── index.js │ │ │ ├── public │ │ │ │ ├── favicon.ico │ │ │ │ └── pokeapi.png │ │ │ ├── styles │ │ │ │ ├── Card.modue.css │ │ │ │ ├── Home.module.css │ │ │ │ └── globals.css │ │ │ └── yarn.lock │ │ └── poke-search-ts │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── next-env.d.ts │ │ │ ├── next.config.js │ │ │ ├── package.json │ │ │ ├── pages │ │ │ ├── _app.tsx │ │ │ └── index.tsx │ │ │ ├── public │ │ │ ├── favicon.ico │ │ │ └── pokeapi.png │ │ │ ├── styles │ │ │ ├── Home.module.css │ │ │ └── globals.css │ │ │ └── tsconfig.json │ └── yarn.lock ├── question-list │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── result.png │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── mock_questions.json │ │ ├── mock_submissions.json │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── random-users │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jsconfig.json │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ └── src │ │ ├── app │ │ ├── globals.css │ │ ├── layout.js │ │ ├── page.js │ │ └── page.module.css │ │ ├── components │ │ └── UserCell │ │ │ └── index.js │ │ └── utils │ │ ├── debounceFn.js │ │ └── useDebounce.js ├── react-debounce-vs-throttle │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── hooks │ │ ├── useDebounce.js │ │ └── useThrottle.js │ │ ├── index.css │ │ ├── index.js │ │ ├── react-debounce-vs-throttle.gif │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── react-fetch-hook │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── hooks │ │ ├── useFetch.js │ │ └── useFeteches.js │ │ ├── index.css │ │ ├── index.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── react-reducer │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── reducers │ │ └── countReducer.js │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── recent-trades │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js ├── stock-prices │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── jsconfig.json │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ └── src │ │ ├── app │ │ ├── StockList │ │ │ ├── index.js │ │ │ └── index.module.css │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.js │ │ ├── page.js │ │ └── page.module.css │ │ └── hooks │ │ └── useFetch.js ├── suspense-playground │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── components │ │ ├── LoadingIndicator.js │ │ └── Posts.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ ├── setupTests.js │ │ └── utils │ │ └── genFetch.js ├── tip-calculator │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js └── todo-list │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js ├── readme.md └── vanilla-widgets-implementation ├── 2048 ├── index.html ├── index.js └── style.css ├── DOMRenderer ├── index.html └── index.js ├── accordion ├── index.html └── src │ ├── index.js │ └── styles.css ├── analog-clock ├── index.html ├── index.js └── style.css ├── carousel ├── index.html └── src │ ├── index.js │ └── styles.css ├── csv-viewer ├── index.html ├── src │ ├── index.js │ └── styles.css └── test.csv ├── debounce-and-throttle ├── debouncing-vs-throttling.gif ├── index.html └── index.js ├── debounced-searchbar ├── index.html └── src │ ├── index.js │ └── styles.css ├── draggable-box ├── draggable.js ├── index.html └── style.css ├── game-of-life ├── index.html ├── index.js └── styles.css ├── images-at-corners ├── images │ ├── 0.png │ ├── 1.png │ ├── 2.png │ └── 3.png ├── index.html └── src │ ├── index.js │ └── styles.css ├── instagram-create-poll ├── index.html └── src │ ├── index.js │ └── styles.css ├── query ├── index.html └── src │ └── index.js ├── simple-sudoku ├── README.md ├── index.html ├── widget.css └── widget.js ├── snake-game ├── index.html ├── index.js └── style.css ├── stock-prices ├── index.html └── src │ ├── index.js │ └── styles.css ├── tableview ├── index.html └── src │ ├── index.js │ └── styles.css └── tic-tac-toe ├── index.html ├── index.js └── styles.css /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .DS_Store 3 | node_modules/ 4 | .next/ -------------------------------------------------------------------------------- /algo/animate-right.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
target
6 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /algo/print-dom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
a 7 |
b 8 |
c 9 |
d
10 |
11 |
e
12 |
f
13 |
14 |
15 | 16 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /browser/check-user-activity-on-page/focus.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | focus 10 | 11 | 12 | 13 | 14 |

Hi

15 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /browser/check-user-activity-on-page/visibility.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | visible 6 | 7 | 8 | 9 | 10 |

Hi

11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /browser/cookies/client-credentials-grant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/cookies/client-credentials-grant.png -------------------------------------------------------------------------------- /browser/cookies/cookies-local-session.md: -------------------------------------------------------------------------------- 1 | Cookies vs LocalStorage vs SessionStorage 2 | === 3 | Cookies 4 | - stays until the expiry date set by the server. But if the server doesn't set the expiry date, the cookies will be pruned once the user leaves the website 5 | - can be made secure by setting the httpOnly=true. This prevents client-side access to that cookie 6 | - 4kb 7 | 8 | LocalStorage 9 | - stays on a browser forever unless be cleaned explicitly 10 | - 5Mb 11 | - use case: shopping cart/ads BUT browsers cannot share localStorage!!! 12 | 13 | SessionStorage 14 | - stays on a browser until a user leaves the website 15 | - 5Mb -------------------------------------------------------------------------------- /browser/cookies/cookies-session.md: -------------------------------------------------------------------------------- 1 | Cookies & Sessions 2 | === 3 | 4 | 1 sentence: 5 | --- 6 | Cookies & Sessions are used to create a stateful experience/interaction. They are commonly used to check if the user is logged-on 7 | 8 | Cookies 9 | - stored on client-side 10 | - keeps your identification(like an identification card) 11 | - 4 kb 12 | - stays until the expiry date set by the server. But if the server doesn't set the expiry date, the cookies will be pruned once the user leaves the website 13 | 14 | Sessions 15 | - (usually) stored on server-side 16 | - work with cookies, the server uses your identification(cookies from client-side) to find your sessions on the server such that the server can provide your information in previous visits 17 | - store sessions of all users 18 | 19 | More..., please read [Cookies vs LocalStorage vs SessionStorage](./cookies-local-session.md) -------------------------------------------------------------------------------- /browser/event-delegation/bubble-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/event-delegation/bubble-up.png -------------------------------------------------------------------------------- /browser/event-delegation/event-bubbling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/event-delegation/event-bubbling.gif -------------------------------------------------------------------------------- /browser/event-delegation/event-capturing-bubbling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/event-delegation/event-capturing-bubbling.png -------------------------------------------------------------------------------- /browser/render/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/browser.png -------------------------------------------------------------------------------- /browser/render/cssom-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/cssom-timeline.png -------------------------------------------------------------------------------- /browser/render/dom-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/dom-timeline.png -------------------------------------------------------------------------------- /browser/render/gecko.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/gecko.jpg -------------------------------------------------------------------------------- /browser/render/layout-viewport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/layout-viewport.png -------------------------------------------------------------------------------- /browser/render/render-cssom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/render-cssom.png -------------------------------------------------------------------------------- /browser/render/render-dom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/render-dom.png -------------------------------------------------------------------------------- /browser/render/render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/render.png -------------------------------------------------------------------------------- /browser/render/webkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/browser/render/webkit.png -------------------------------------------------------------------------------- /browser/scroll/readme.md: -------------------------------------------------------------------------------- 1 | # Scroll Event 2 | 3 | - [Simple Full Page Scrolling](./simple.html) 4 | - [Nested Div Scrolling](./nested.html) 5 | - [Infinite Scroll](./infinite.html) 6 | -------------------------------------------------------------------------------- /browser/tcp-handshake/readme.md: -------------------------------------------------------------------------------- 1 | TCP handshake 2 | === 3 | - the browser sends a `SYN` to the server 4 | - the server sends back a `ACK` to the browser 5 | - the browser sends again the `SYN` and `ACK` to the server 6 | 7 | therefore, both sides have sent/received to each other, an then a TCP connection is established -------------------------------------------------------------------------------- /css/box-model/box-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/css/box-model/box-model.png -------------------------------------------------------------------------------- /css/flex-box/readme.md: -------------------------------------------------------------------------------- 1 | What is Flex Box 2 | === 3 | When working with flexbox you need to think in terms of two axes — the main axis and the cross axis. 4 | - The main axis is defined by the flex-direction property 5 | - The cross axis runs perpendicular to it 6 | Everything we do with flexbox refers back to these axes, so it is worth understanding how they work from the outset. 7 | 8 | Before the Flexbox Layout module, there were four layout modes: 9 | - Block, for sections in a webpage 10 | - Inline, for text 11 | - Table, for two-dimensional table data 12 | - Positioned, for explicit position of an element 13 | The Flexible Box Layout Module, makes it easier to design flexible responsive layout structure without using float or positioning. 14 | 15 | Reference: 16 | - https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox 17 | - https://www.w3schools.com/css/css3_flexbox.asp -------------------------------------------------------------------------------- /css/priority/css-priority.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/css/priority/css-priority.jpg -------------------------------------------------------------------------------- /css/priority/readme.md: -------------------------------------------------------------------------------- 1 | CSS Priority 2 | === 3 | 4 | ![idea](./css-priority.jpg) 5 | 6 | 7 | Example1 8 | --- 9 | ```css 10 | /* score: 00030 */ 11 | .a .b .c 12 | { 13 | color: green; 14 | } 15 | 16 | /* score: 00020 */ 17 | .a .b 18 | { 19 | color: red; 20 | } 21 | ``` 22 | The result color of the `
` is green because the score is higher 23 | 24 | Example2 25 | --- 26 | ```css 27 | /*00020*/ 28 | .a .b 29 | { 30 | color: red; 31 | } 32 | 33 | /*00010*/ 34 | .b 35 | { 36 | /*now becomes 10010*/ 37 | color: yellow !important; 38 | } 39 | ``` 40 | 41 | Example3 42 | --- 43 | ```html 44 | // supposed: green, result: green 45 |
Hello
46 | 47 | // supposed: red, result: green 48 |
Hello
49 | ``` 50 | ```css 51 | .red 52 | { 53 | color: red; 54 | } 55 | 56 | .green 57 | { 58 | color: green; 59 | } 60 | ``` 61 | The result of `
Hello
` is GREEN, why? 62 | - class attribute in your HTML doesn't care about order of classes 63 | - BUT the order of declaration of your CSS classess in your CSS files 64 | 65 | ref: 66 | https://teamtreehouse.com/community/priority-of-a-class-when-there-are-two-classes-in-the-same-element -------------------------------------------------------------------------------- /implementation/LWWElementSet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LWWElementSet", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "calvinchankf", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "jest": "^26.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /implementation/array/filter.js: -------------------------------------------------------------------------------- 1 | /* 2 | classic interivew question 3 | Implementation the Array Filter 4 | here is my least implementation to extend the Array class using protoype 5 | */ 6 | if (!Array.prototype.myFilter) { 7 | Array.prototype.myFilter = function (callback) { 8 | if (typeof callback !== "function") { 9 | throw new Error(callback + " is not a function"); 10 | } 11 | const result = []; 12 | let i = 0; 13 | for (i; i < this.length; i++) { 14 | const temp = callback(this[i], i); 15 | if (typeof temp !== "boolean") { 16 | throw new Error(callback + " is not a boolean"); 17 | } 18 | if (temp == true) { 19 | result.push(this[i]); 20 | } 21 | } 22 | return result; 23 | }; 24 | } 25 | 26 | const a = [1, 2, 3, 4]; 27 | const result = a.myFilter((item, idx) => { 28 | return item % 2 == 0; 29 | }); 30 | 31 | console.log(result); 32 | -------------------------------------------------------------------------------- /implementation/array/flatten.js: -------------------------------------------------------------------------------- 1 | /* 2 | Classic interivew question: implement `flatten` 3 | */ 4 | 5 | // 1st: recursion 6 | Array.prototype.flatten1 = function() { 7 | const res = []; 8 | for (let x of this) { 9 | if (Array.isArray(x)) { 10 | res.push(...x.flatten1()) 11 | } else { 12 | res.push(x) 13 | } 14 | } 15 | return res 16 | } 17 | 18 | let a = [ 19 | 1, 20 | [2, 3, 4], 21 | [ 22 | [5, 6], 23 | [7, 8], 24 | ], 25 | 9, 26 | ]; 27 | console.log(a.flatten1()); 28 | console.log("---"); 29 | 30 | // 2nd: iterative 31 | Array.prototype.flatten2 = function() { 32 | const res = []; 33 | let q = [this]; 34 | while (q.length > 0) { 35 | const head = q.shift(); 36 | if (Array.isArray(head)) { 37 | q = [...head, ...q]; 38 | } else { 39 | res.push(head); 40 | } 41 | } 42 | return res; 43 | } 44 | 45 | a = [ 46 | 1, 47 | [2, 3, 4], 48 | [ 49 | [5, 6], 50 | [7, 8], 51 | ], 52 | 9, 53 | ]; 54 | console.log(a.flatten2()); 55 | 56 | /* 57 | followup: object 58 | */ 59 | -------------------------------------------------------------------------------- /implementation/array/forEach.js: -------------------------------------------------------------------------------- 1 | /* 2 | classic interivew question 3 | Implementation the Array Map 4 | here is my least implementation to extend the Array class using protoype 5 | */ 6 | if (!Array.prototype.myForEach) { 7 | Array.prototype.myForEach = function (callback) { 8 | if (typeof callback !== "function") { 9 | throw new Error(callback + " is not a function"); 10 | } 11 | for (let i = 0; i < this.length; i++) { 12 | callback(this[i], i); 13 | } 14 | }; 15 | } 16 | 17 | const a = [1, 2, 3]; 18 | a.myForEach((item, idx) => { 19 | console.log(item, idx); 20 | }); 21 | -------------------------------------------------------------------------------- /implementation/array/map.js: -------------------------------------------------------------------------------- 1 | /* 2 | classic interivew question 3 | Implementation the Array Map 4 | here is my least implementation to extend the Array class using protoype 5 | */ 6 | if (!Array.prototype.myMap) { 7 | Array.prototype.myMap = function (callback) { 8 | if (typeof callback !== "function") { 9 | throw new Error(callback + " is not a function"); 10 | } 11 | const result = []; 12 | for (let i = 0; i < this.length; i++) { 13 | const temp = callback(this[i], i); 14 | result.push(temp); 15 | } 16 | return result; 17 | }; 18 | } 19 | 20 | const a = [1, 2, 3]; 21 | const result = a.myMap((item, idx) => { 22 | return item * 2; 23 | }); 24 | 25 | console.log(result); 26 | -------------------------------------------------------------------------------- /implementation/bind/index.js: -------------------------------------------------------------------------------- 1 | Function.prototype.bindPolyfill = function(obj) { 2 | const context = this; 3 | return function(...args){ 4 | return context.call(obj, ...args) 5 | } 6 | } -------------------------------------------------------------------------------- /implementation/debounce-vs-throttle/debouncing-vs-throttling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/debounce-vs-throttle/debouncing-vs-throttling.gif -------------------------------------------------------------------------------- /implementation/debounce-vs-throttle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 | Default: 14 | 15 |
16 |
17 | Debounce: 18 | 19 |
20 |
21 | Throttle: 22 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /implementation/event-emitter/basic.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require("events"); 2 | 3 | // init an emitter object 4 | const myEmitter = new EventEmitter(); 5 | 6 | // event listener 7 | myEmitter.on("event", () => { 8 | console.log("an event occurred!"); 9 | }); 10 | 11 | // emit an event 12 | myEmitter.emit("event"); 13 | -------------------------------------------------------------------------------- /implementation/event-emitter/event.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/event-emitter/event.jpg -------------------------------------------------------------------------------- /implementation/event-emitter/simple-subclass.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require("events"); 2 | 3 | // extend the class 4 | class MyEmitter extends EventEmitter {} 5 | 6 | // init an emitter object 7 | const myEmitter = new MyEmitter(); 8 | 9 | // event listener 10 | myEmitter.on("event", () => { 11 | console.log("an event occurred!"); 12 | }); 13 | 14 | // emit an event 15 | myEmitter.emit("event"); 16 | -------------------------------------------------------------------------------- /implementation/fetch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Browser Fetch Implementation 5 | 6 | 7 | 8 | 9 |
10 |
Here is an implementation of Browser fetch from scatch
11 |
12 | 13 | 14 |
15 |
16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /implementation/lru-cache/use_map.js: -------------------------------------------------------------------------------- 1 | // leetcode146 2 | class DLLNode { 3 | constructor(key = -1, val = -1) { 4 | this.key = key 5 | this.val = val 6 | this.prev = null 7 | this.next = null 8 | } 9 | } 10 | class LRUCache { 11 | constructor(capacity) { 12 | this.cap = capacity 13 | this.map = new Map() 14 | } 15 | get(key) { 16 | if (this.map.has(key) === false) { 17 | return -1 18 | } 19 | const value = this.map.get(key) 20 | this.map.delete(key) 21 | this.map.set(key, value) 22 | return value 23 | } 24 | put(key, value) { 25 | if (this.map.has(key)) { 26 | this.map.delete(key) 27 | } 28 | this.map.set(key, value) 29 | if (this.map.size > this.cap) { 30 | const oldest = this.map.keys().next().value 31 | this.map.delete(oldest) 32 | } 33 | } 34 | } 35 | 36 | const c = new LRUCache(2) 37 | c.put("c", 123) 38 | c.put("a", 456) 39 | c.put("b", 789) 40 | console.log(c.get("c")) 41 | console.log(c.get("a")) 42 | c.put("d", 123) 43 | console.log(c.get("c")) 44 | console.log(c.get("a")) 45 | console.log(c.get("d")) -------------------------------------------------------------------------------- /implementation/promise.all/index.js: -------------------------------------------------------------------------------- 1 | var promiseAll = async function(functions) { 2 | const n = functions.length 3 | const res = Array(n).fill(null) 4 | let cnt = 0 5 | return new Promise((resolve, reject) => { 6 | for (let i = 0; i < n; i++) { 7 | const f = functions[i] 8 | f().then(val => { 9 | res[i] = val 10 | cnt += 1 11 | 12 | if (cnt === n) { 13 | resolve(res) 14 | } 15 | }).catch(error => reject(error)) 16 | } 17 | }); 18 | }; 19 | 20 | const promise = promiseAll([ 21 | () => new Promise(res => res(42)), 22 | () => new Promise(res => res(1)), 23 | () => new Promise(res => res(2)), 24 | ]) 25 | promise.then(console.log); // [42, 1, 2] -------------------------------------------------------------------------------- /implementation/promise.pool/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var promisePool = async function(functions, n) { 4 | const res = [] 5 | const worker = async () => { 6 | if (functions.length === 0) { 7 | return 8 | } 9 | const fn = functions.shift() 10 | const temp = await fn() 11 | res.push(temp) 12 | await worker() 13 | } 14 | const nPromises = [] 15 | for (let i = 0; i < n; i++) { 16 | nPromises.push(worker()) 17 | } 18 | await Promise.all(nPromises) 19 | return res 20 | }; 21 | 22 | const start = performance.now() 23 | 24 | promisePool([ 25 | () => new Promise((resolve, _rej) => setTimeout(() => resolve(1), 3000)), 26 | () => new Promise((resolve, _rej) => setTimeout(() => resolve(2), 200)), 27 | () => new Promise((resolve, _rej) => setTimeout(() => resolve(3), 3000)), 28 | ], 2).then((data) => { 29 | const end = performance.now() 30 | console.log(`Executed functions and return ${JSON.stringify(data)} within ${end - start}ms`) 31 | }) 32 | // Executed functions and return [2,1,3] within 3207.1921259984374ms -------------------------------------------------------------------------------- /implementation/promisify/index.js: -------------------------------------------------------------------------------- 1 | const promisify = fn => { 2 | return async function(...args) { 3 | return new Promise((resolve, reject) => { 4 | 5 | const callback = (value, error) => { 6 | if (error) { 7 | reject(error) 8 | } else { 9 | resolve(value) 10 | } 11 | } 12 | 13 | fn(...args, callback) 14 | }) 15 | } 16 | }; 17 | 18 | // test 19 | function do_something(...args) { 20 | const callback = args.pop() 21 | if (args.filter(x => typeof x === 'number').length !== args.length) { 22 | const err = new Error('every input must be a number'); 23 | callback(null, err); 24 | } else { 25 | const total = args.reduce((acc, cur) => acc + cur, 0) // my do_something is to sum all inputs 26 | callback(total); 27 | } 28 | } 29 | 30 | const promisified_do_something = promisify(do_something) 31 | 32 | promisified_do_something(100, 99).then((res) => console.log(res)) 33 | 34 | promisified_do_something(1,10,100,1000,10000).then((res) => console.log(res)) 35 | 36 | promisified_do_something('a',10,100,1000,10000).then((res) => console.log(res)) -------------------------------------------------------------------------------- /implementation/pubsub-vs-observer/observer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/pubsub-vs-observer/observer.png -------------------------------------------------------------------------------- /implementation/pubsub-vs-observer/pubsub.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/pubsub-vs-observer/pubsub.gif -------------------------------------------------------------------------------- /implementation/pubsub-vs-observer/vs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/pubsub-vs-observer/vs.jpeg -------------------------------------------------------------------------------- /implementation/server-sent-events/client/.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 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "react": "^17.0.1", 10 | "react-dom": "^17.0.1", 11 | "react-scripts": "4.0.2", 12 | "web-vitals": "^1.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/server-sent-events/client/public/favicon.ico -------------------------------------------------------------------------------- /implementation/server-sent-events/client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/server-sent-events/client/public/logo192.png -------------------------------------------------------------------------------- /implementation/server-sent-events/client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/server-sent-events/client/public/logo512.png -------------------------------------------------------------------------------- /implementation/server-sent-events/client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | font-size: xx-large; 4 | } 5 | 6 | .App-logo { 7 | height: 40vmin; 8 | pointer-events: none; 9 | } 10 | 11 | @media (prefers-reduced-motion: no-preference) { 12 | .App-logo { 13 | animation: App-logo-spin infinite 20s linear; 14 | } 15 | } 16 | 17 | .App-link { 18 | color: #61dafb; 19 | } 20 | 21 | @keyframes App-logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /implementation/server-sent-events/client/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /implementation/server-sent-events/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/server-sent-events/demo.png -------------------------------------------------------------------------------- /implementation/server-sent-events/readme.md: -------------------------------------------------------------------------------- 1 | # Hello World to Server-Sent Events 2 | 3 | Run the server 4 | 5 | ``` 6 | cd ./server 7 | node server.js 8 | ``` 9 | 10 | Run the client 11 | 12 | ``` 13 | cd ./client 14 | yarn start 15 | ``` 16 | 17 | Then you would see the RBG numbers and color of text being update for every 2 seconds 18 | 19 | ![](./demo.png) 20 | 21 | Don't forget to npm install in both folders 22 | -------------------------------------------------------------------------------- /implementation/server-sent-events/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world-to-sse", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /implementation/sleep/index.js: -------------------------------------------------------------------------------- 1 | const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); 2 | module.exports = sleep; 3 | -------------------------------------------------------------------------------- /implementation/virtual-dom/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/implementation/virtual-dom/.DS_Store -------------------------------------------------------------------------------- /implementation/virtual-dom/prototype/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Virtual DOM Prototype 4 | 5 | 6 | 7 |
8 | Let's build a simple Virtual DOM from scratch with vanilla 9 | Javascript 10 |
11 |
12 | 13 |
14 | 👆🏻the gif doesnt reload even random number is being reloaded, our 15 | virtual dom works 🎉 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /js-knowledge/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/js-knowledge/.DS_Store -------------------------------------------------------------------------------- /js-knowledge/apply-call-bind/apply.js: -------------------------------------------------------------------------------- 1 | // apply: call the function with an array(u can put arguments into it) 2 | 3 | let customer1 = { 4 | name: 'Leo', 5 | email: 'leo@gmail.com' 6 | }; 7 | let customer2 = { 8 | name: 'Nat', 9 | email: 'nat@hotmail.com' 10 | }; 11 | 12 | function greeting(text, text2) { 13 | console.log(`${text} ${this.name}, ${text2}`); 14 | } 15 | greeting.apply(customer1, ['Hello', 'How are you?']); // Hello Leo, How are you? 16 | greeting.apply(customer2, ['Hello', 'How are you?']); // Hello Natm How are you? 17 | 18 | greeting.apply(customer1, []); // undefined Leo, undefined 19 | greeting.apply(customer1, 'Hello'); // this will crash because only an array is allowed to be passed as an argument -------------------------------------------------------------------------------- /js-knowledge/apply-call-bind/call.js: -------------------------------------------------------------------------------- 1 | // call: call the function with arguments 2 | 3 | let customer1 = { 4 | name: 'Leo', 5 | email: 'leo@gmail.com' 6 | }; 7 | let customer2 = { 8 | name: 'Nat', 9 | email: 'nat@hotmail.com' 10 | }; 11 | 12 | function greeting(text) { 13 | console.log(`${text} ${this.name}`); 14 | } 15 | 16 | greeting.call(customer1, 'Hello'); // Hello Leo 17 | greeting.call(customer2, 'Hello'); // Hello Nat 18 | 19 | // greeting() just is just declared with one argument, only Hello will be printed 20 | greeting.call(customer1, 'Hello', 'How are you?'); // Hello Leo 21 | 22 | greeting.call(customer1, ['Hello', 'How are you?']); // Hello,How are you? Leo 23 | 24 | greeting.call(customer1, { 25 | a: 1, 26 | b: 2 27 | }); // [object Object] Leo -------------------------------------------------------------------------------- /js-knowledge/call-stack-overflow/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | RangeError: Maximum call stack size exceeded 3 | 9136 4 | */ 5 | const f = (num) => { 6 | try { 7 | f(num+1) 8 | } catch (error) { 9 | console.log(error) 10 | console.log(num) 11 | } 12 | } 13 | f(0) -------------------------------------------------------------------------------- /js-knowledge/callback-promise-generator-asyncwait/async-await.js: -------------------------------------------------------------------------------- 1 | const fetchData = () => { 2 | 3 | // e.g. 1 4 | // return Promise.resolve('hi, i am from promise') 5 | 6 | // e.g. 2 7 | return new Promise((resolve, reject) => { 8 | setTimeout(() => { 9 | resolve("hi, i am from promise"); 10 | }, 250); 11 | }); 12 | } 13 | 14 | const runit = async () => { 15 | try { 16 | const result = await fetchData() 17 | console.log(result) 18 | } catch (error) { 19 | console.error(error) 20 | } 21 | } 22 | 23 | runit() -------------------------------------------------------------------------------- /js-knowledge/callback-promise-generator-asyncwait/generator.js: -------------------------------------------------------------------------------- 1 | function* gen(param) { 2 | for (let i = 0; i < 3; i++) { 3 | yield (i + 1) * param 4 | } 5 | return 4 * param 6 | } 7 | 8 | var g = gen(2); // "Generator { }" 9 | console.log(g.next()) // 2 false 10 | console.log(g.next()) // 4 false 11 | console.log(g.next()) // 6 false 12 | console.log(g.next()) // 8 true -------------------------------------------------------------------------------- /js-knowledge/callback-promise-generator-asyncwait/promise.js: -------------------------------------------------------------------------------- 1 | let p = new Promise((resolve, reject) => { 2 | // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed. 3 | // In this example, we use setTimeout(...) to simulate async code. 4 | // In reality, you will probably be using something like XHR or an HTML5 API. 5 | setTimeout(function () { 6 | resolve("Success!"); // Yay! Everything went well! 7 | }, 250); 8 | }); 9 | 10 | p.then((successMessage) => { 11 | // successMessage is whatever we passed in the resolve(...) function above. 12 | // It doesn't have to be a string, but if it is only a succeed message, it probably will be. 13 | console.log("Yay! " + successMessage); 14 | }, (errorMessage) => { 15 | console.log("OH... " + errorMessage); 16 | }); 17 | 18 | console.log(p); -------------------------------------------------------------------------------- /js-knowledge/child-process/child.js: -------------------------------------------------------------------------------- 1 | process.on('message', function (m) { 2 | console.log('message from parent: ' + JSON.stringify(m)); 3 | }); 4 | 5 | process.send({ 6 | from: 'child' 7 | }); -------------------------------------------------------------------------------- /js-knowledge/child-process/parent.js: -------------------------------------------------------------------------------- 1 | var child_process = require('child_process'); 2 | 3 | var child = child_process.fork('./child.js'); 4 | 5 | child.on('message', function (m) { 6 | console.log('message from child: ' + JSON.stringify(m)); 7 | }); 8 | 9 | child.send({ 10 | from: 'parent' 11 | }); -------------------------------------------------------------------------------- /js-knowledge/child-process/readme.md: -------------------------------------------------------------------------------- 1 | Child Prcocess 2 | === 3 | Node is single-threaded. If we want to work on tasks parallelly, we can try to use child_process. Which helps us to 'spawn' a new process in our machine, and the processes can communicate through IPC(Inter Process Communication) 4 | 5 | Some commands 6 | --- 7 | create an instance of node with IPC support 8 | ``` 9 | child_process.fork() 10 | ``` 11 | 12 | run any command and creat IPC channel 13 | ``` 14 | child_process.spawn() 15 | ``` 16 | 17 | run any command in the child process 18 | ``` 19 | child_process.exec() 20 | ``` 21 | 22 | ...i am no gonna include all 23 | 24 | example 25 | --- 26 | ``` 27 | node parent.js 28 | ``` -------------------------------------------------------------------------------- /js-knowledge/chrome-profile-template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Demo: Get Started Debugging JavaScript with Chrome DevTools 7 | 8 | 30 | 31 | 32 | 33 |

Demo: Get Started Debugging JavaScript with Chrome DevTools

34 | 35 | 36 | 37 | 38 | 39 |

40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /js-knowledge/chrome-profile-template/script.js: -------------------------------------------------------------------------------- 1 | function onClick() { 2 | if (inputsAreEmpty()) { 3 | label.textContent = 'Error: one or both inputs are empty.'; 4 | return; 5 | } 6 | updateLabel(); 7 | } 8 | 9 | function inputsAreEmpty() { 10 | if (getNumber1() === '' || getNumber2() === '') { 11 | return true; 12 | } else { 13 | return false; 14 | } 15 | } 16 | 17 | function updateLabel() { 18 | var addend1 = getNumber1(); 19 | var addend2 = getNumber2(); 20 | var sum = addend1 + addend2; 21 | label.textContent = addend1 + ' + ' + addend2 + ' = ' + sum; 22 | } 23 | 24 | function getNumber1() { 25 | return inputs[0].value; 26 | } 27 | 28 | function getNumber2() { 29 | return inputs[1].value; 30 | } 31 | var inputs = document.querySelectorAll('input'); 32 | var label = document.querySelector('p'); 33 | var button = document.querySelector('button'); 34 | button.addEventListener('click', onClick); -------------------------------------------------------------------------------- /js-knowledge/class-vs-prototype/prototype.js: -------------------------------------------------------------------------------- 1 | // declaration 2 | function Vehicle(make, model, color) { 3 | this.make = make; 4 | this.model = model; 5 | this.color = color; 6 | this.getName = function () { 7 | return this.make + " " + this.model; 8 | } 9 | } 10 | 11 | // problem 1 12 | let car = new Vehicle("Toyota", "Corolla", "Black"); 13 | car.year = 2012 14 | let car2 = new Vehicle("Benz", "ggsget", "White"); 15 | console.log(car); // car has 'year' 16 | console.log(car2); // but car2 instance doesn't have 'year' 17 | 18 | // problem 2 19 | // all instances share the same values of the new variable. in this case, all instances share 2 as 'month' 20 | Vehicle.prototype.month = 2 21 | console.log(car) // cant see month in the car object 22 | console.log(car2) // cant see month in the car2 object 23 | console.log(car.month); // 2012 24 | console.log(car2.month); // 2012 WTF 25 | 26 | // That's why we want class, make js more OOP -------------------------------------------------------------------------------- /js-knowledge/currying/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | e.g.1 3 | */ 4 | var add = function (a) { 5 | return function (b) { 6 | return a + b 7 | } 8 | } 9 | 10 | var addToFive = add(5) 11 | console.log(addToFive) 12 | /* 13 | it prints a function. it just consumed the outer function, so it becomes 14 | function (b) { 15 | return 5 + b 16 | } 17 | */ 18 | var result = addToFive(2) 19 | console.log(result) 20 | 21 | /* 22 | e.g.2 23 | */ 24 | var saySomething = function (a) { 25 | return function (b) { 26 | return function (c) { 27 | return "Say " + a + " to " + b + " from " + c 28 | } 29 | } 30 | } 31 | console.log(saySomething("Hi")) 32 | /* 33 | the above function: 34 | function (b) { 35 | return function (c) { 36 | return "Say " + 'Hi' + " to " + b + " from " + c 37 | } 38 | } 39 | */ 40 | console.log(saySomething("Hi")("Bob")) 41 | /* 42 | the above function: 43 | return function (c) { 44 | return "Say " + "Hi" + " to " + "Bob" + " from " + c 45 | } 46 | */ 47 | console.log(saySomething("Hi")("Bob")("Hong Kong")) -------------------------------------------------------------------------------- /js-knowledge/event-loop/event-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/js-knowledge/event-loop/event-loop.png -------------------------------------------------------------------------------- /js-knowledge/event-loop/readme.md: -------------------------------------------------------------------------------- 1 | Event Loop 2 | === 3 | 4 | 1 sentence 5 | --- 6 | 7 | Basically, it helps NodeJS to run async actions given that NodeJS is single-thread 8 | 9 | Detail 10 | --- 11 | 12 | Node is single-threaded, it executes the code line by line, so how does it run async actions? 13 | 14 | **Event Loop** 15 | 16 | 1. When the EventEmitter object emits an event, the events will be first enqueued into the event queue. 17 | 1. The event loop periodically checks if the queue has events, if yes then it dequeues the head event from the queue and calls the listeners. 18 | 1. All of the functions attached to that specific event are called synchronously. 19 | 1. Any values returned by the called listeners are ignored and will be discarded. 20 | 1. unlike callbacks/promise/aync&await, events are synchronous 21 | 22 | ![](./event-loop.png) 23 | 24 | Reference: 25 | 26 | - [Video Explanation](https://www.youtube.com/watch?v=8aGhZQkoFbQ) 27 | -------------------------------------------------------------------------------- /js-knowledge/hoist/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Hoisting in javascript is behavior in which 3 | all the declarations are automatically moved on top of the current scope before execution, 4 | so we can use a variable or a function before its declaration 5 | 6 | e.g. we can call a() and b() before a() and b() are declared 7 | */ 8 | a() 9 | b() 10 | 11 | function a() { 12 | console.log('a') 13 | } 14 | 15 | function b() { 16 | console.log('b') 17 | } 18 | 19 | /* 20 | Even for prototype, we can new an instance before its declaration e.g. 21 | */ 22 | let p = new Person("Calvin", 28) 23 | 24 | function Person(name, age) { 25 | this.name = name; 26 | this.age = age; 27 | } 28 | console.log(p); 29 | 30 | /* 31 | However, in a class, therefore we can't new an instance before its declaration e.g. 32 | */ 33 | let car = new Car("Toytota", "Black") 34 | class Car { 35 | constructor(brand, color) { 36 | this.brand = brand; 37 | this.color = color; 38 | } 39 | } 40 | console.log(car); -------------------------------------------------------------------------------- /js-knowledge/memory-profile-on-web/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/js-knowledge/memory-profile-on-web/.DS_Store -------------------------------------------------------------------------------- /js-knowledge/memory-profile-on-web/1a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/js-knowledge/memory-profile-on-web/1a.png -------------------------------------------------------------------------------- /js-knowledge/memory-profile-on-web/1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/js-knowledge/memory-profile-on-web/1b.png -------------------------------------------------------------------------------- /js-knowledge/memory-profile-on-web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Demo: Get Started Debugging JavaScript with Chrome DevTools 7 | 8 | 30 | 31 | 32 | 33 |

Memory Leak

34 |
Hey
35 |
Yo
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /js-knowledge/memory-profile-on-web/script.js: -------------------------------------------------------------------------------- 1 | // e.g. 1 from https://gist.github.com/kepta/0ac2636f86c0f4cee80de12821e4ef34 2 | // memory leak in a closure 3 | // in the sayHi() closure, since 'allNames' persists, the engine will quickly run out of memory when we call the function periodically 4 | function sayHi() { 5 | var allNames = []; 6 | return name => { 7 | allNames.push(allNames.join() + name); 8 | return allNames; 9 | } 10 | } 11 | 12 | // assign closure to a variable 13 | var hello = sayHi(); 14 | 15 | // setInterval(() => { 16 | // hello('Gandhi'); 17 | // }, 1); 18 | 19 | // e.g. 2 20 | // in this case, 'detachedNodes' is retained 21 | var detachedNodes; 22 | 23 | function create() { 24 | var ul = document.createElement('ul'); 25 | for (var i = 0; i < 1337; i++) { 26 | var li = document.createElement('li'); 27 | ul.appendChild(li); 28 | } 29 | detachedNodes = ul; 30 | } 31 | 32 | setInterval(() => { 33 | create(); 34 | }, 100); -------------------------------------------------------------------------------- /js-knowledge/mixins/readme.md: -------------------------------------------------------------------------------- 1 | # What is Mixins 2 | 3 | Mixins are a form of object **composition**, where component features get mixed into a composite object so that properties of each mixin become properties of the composite object. 4 | 5 | ```js 6 | class Vegetables { 7 | veggies() { 8 | return "Choose Veggies"; 9 | } 10 | } 11 | class Meat { 12 | meat() { 13 | return "Choose Meat"; 14 | } 15 | } 16 | 17 | class Sauces { 18 | choosingSauces() { 19 | return "Choose Sauces"; 20 | } 21 | } 22 | 23 | function combineClasses(dest, ...src) { 24 | for (let _dest of src) { 25 | for (var key of Object.getOwnPropertyNames(_dest.prototype)) { 26 | dest.prototype[key] = _dest.prototype[key]; 27 | } 28 | } 29 | } 30 | 31 | class Burger {} 32 | 33 | //adding a new class 34 | class Cheese { 35 | addingCheese() { 36 | return "Add Cheese"; 37 | } 38 | } 39 | 40 | combineClasses(Burger, Vegetables, Meat, Sauces, Cheese); 41 | 42 | var burger = new Burger(); 43 | console.log(burger.veggies()); 44 | console.log(burger.meat()); 45 | console.log(burger.choosingSauces()); 46 | console.log(burger.addingCheese()); 47 | ``` 48 | -------------------------------------------------------------------------------- /js-knowledge/prototype/basic.js: -------------------------------------------------------------------------------- 1 | function Dog(name) { 2 | this.name = name 3 | } 4 | 5 | // here is how we use prototype to extend functionalities 6 | Dog.prototype.bark = function () { 7 | console.log(this.name, 'bark') // btw, 'this' here refers to the dog instance 8 | } 9 | 10 | var dog = new Dog('gg') 11 | dog.bark() -------------------------------------------------------------------------------- /js-knowledge/prototype/chain.js: -------------------------------------------------------------------------------- 1 | function Dog(name) { 2 | this.name = name 3 | } 4 | 5 | // here is how we use prototype to extend functionalities 6 | Dog.prototype.bark = function () { 7 | console.log(this.name, 'bark') // btw, 'this' here refers to the dog instance 8 | } 9 | 10 | function SuperDog(name, lang) { 11 | Dog.call(this, name, lang) 12 | this.lang = lang 13 | } 14 | 15 | // to inherit dog's prototype 16 | // when we call the functions, 17 | // this "chain" goes all the way back until it reaches an object that has no prototype 18 | SuperDog.prototype = Object.create(Dog.prototype); 19 | 20 | SuperDog.prototype.speak = function () { 21 | console.log(this.name, 'i speak' + this.lang) 22 | } 23 | 24 | var dog = new Dog('gigi') 25 | dog.bark() 26 | // dog.speak() // it will crash 27 | 28 | var superdog = new SuperDog('momo', 'french') 29 | superdog.bark() 30 | superdog.speak() -------------------------------------------------------------------------------- /js-knowledge/referencing/primitive.js: -------------------------------------------------------------------------------- 1 | /* 2 | as mentioned, a variable is always pass by value unless it is a reference(object/array) 3 | */ 4 | 5 | // number 6 | let a = 1 7 | function add(n) { 8 | n++ 9 | console.log(n) 10 | } 11 | add(a) 12 | console.log(a) 13 | 14 | // string 15 | let b = 'abc' 16 | function addChar(s) { 17 | s += "d" 18 | console.log(s) 19 | } 20 | addChar(b) 21 | console.log(b) 22 | 23 | // boolean 24 | let c = true 25 | function invert(bool) { 26 | bool = !bool 27 | console.log(bool) 28 | } 29 | invert(c) 30 | console.log(c) -------------------------------------------------------------------------------- /js-knowledge/referencing/readme.md: -------------------------------------------------------------------------------- 1 | Referencing 2 | === 3 | 4 | In Javascript, a variable is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object. 5 | 6 | [Example of passing primitive types](./primitive.js) 7 | [Example of passing an array](./array.js) 8 | [Example of passing an object](./object.js) -------------------------------------------------------------------------------- /js-knowledge/self-invoking/index.js: -------------------------------------------------------------------------------- 1 | // An immediate function is one that executes as soon as it is defined. 2 | // Creating an immediate function is simple: 3 | // you add the open/close parentheses after the closing curly bracket, 4 | // and then wrap the entire function in parentheses. That's it 5 | let temp = (function () { 6 | var x = "Hello!!"; // I will invoke myself 7 | return x 8 | })(); 9 | console.log(temp) -------------------------------------------------------------------------------- /js-knowledge/singleton/God.js: -------------------------------------------------------------------------------- 1 | class God { 2 | constructor() { 3 | if (God.instance) { 4 | return God.instance; 5 | } 6 | // set singleton 7 | God.instance = this 8 | } 9 | static getInstance() { 10 | if (God.instance) { 11 | return God.instance 12 | } 13 | throw new Error("Please init first") 14 | } 15 | } 16 | // declare singleton 17 | God.instance = null 18 | 19 | module.exports = God -------------------------------------------------------------------------------- /js-knowledge/singleton/index.js: -------------------------------------------------------------------------------- 1 | const God = require('./God') 2 | const g1 = new God() 3 | const g2 = new God() 4 | console.log(g1 == g2) 5 | console.log(God.getInstance() == g1) 6 | console.log(God.getInstance() == g2) -------------------------------------------------------------------------------- /js-knowledge/this/1_constructor.js: -------------------------------------------------------------------------------- 1 | // it prints { value: 10} 2 | // it means that 'this' is refering to the 'ConstructorExample' 3 | function ConstructorExample() { 4 | console.log(this); 5 | this.value = 10; 6 | console.log(this); 7 | } 8 | 9 | new ConstructorExample(); 10 | 11 | // for example, it is how leetcode defines a Binary Tree 12 | function TreeNode(val) { 13 | this.val = val; 14 | this.left = this.right = null; 15 | } -------------------------------------------------------------------------------- /js-knowledge/this/2_apply_call_bind.js: -------------------------------------------------------------------------------- 1 | /* 2 | If apply, call, or bind are used to call a function, 3 | 'this' inside the function is the object that is passed in as the argument. 4 | */ 5 | function fn() { 6 | console.log(this); 7 | } 8 | 9 | var obj = { 10 | value: 5 11 | }; 12 | 13 | var boundFn = fn.bind(obj); 14 | 15 | boundFn(); // -> { value: 5 } 16 | fn.call(obj); // -> { value: 5 } 17 | fn.apply(obj); // -> { value: 5 } -------------------------------------------------------------------------------- /js-knowledge/this/3_method.js: -------------------------------------------------------------------------------- 1 | // If a function is called as a method, 2 | // this is the object that the function is a property of 3 | var obj = { 4 | value: 5, 5 | printThis: function () { 6 | console.log(this); 7 | } 8 | }; 9 | 10 | obj.printThis(); // { value: 5, printThis: [Function: printThis] } -------------------------------------------------------------------------------- /js-knowledge/this/4_global.js: -------------------------------------------------------------------------------- 1 | function fn() { 2 | console.log(this); 3 | } 4 | // If called in browser: 5 | fn(); // it prints the node contextd because node executes it -------------------------------------------------------------------------------- /js-knowledge/this/6_arrow.js: -------------------------------------------------------------------------------- 1 | /* 2 | If the function is an ES2015 arrow function, 3 | it ignores all the rules above 4 | and receives the this value of its surrounding scope at the time it’s created 5 | */ 6 | 7 | // e.g. 1 8 | let obj = { 9 | value: 'abc', 10 | createArrowFn: () => { 11 | console.log(this); 12 | } 13 | }; 14 | let arrowFn = obj.createArrowFn(); // {} 15 | 16 | // e.g. 2 17 | obj = { 18 | value: 'abc', 19 | createArrowFn: function () { 20 | return () => console.log(this); 21 | } 22 | }; 23 | arrowFn = obj.createArrowFn(); 24 | arrowFn(); // -> { value: 'abc', createArrowFn: ƒ } -------------------------------------------------------------------------------- /optimization/backend.md: -------------------------------------------------------------------------------- 1 | How to optimize performance? [WIP] 2 | ---- 3 | - memory leak: 4 | - Profile/monitor your app, find and fix memory leaks by capturing snapshots of your app while it is running, to see if there is any memory leak. If the memory usage keeps piling up and not going down after a certain period of time(after several mark&sweep), it means that there is a memory leak. 5 | - memory leaks usually happen with Global Variables, Multiple References, Closures 6 | - Tools: node-inspector, node-memwatch, chrome-devtools(browser) 7 | - check the time&space complexity of your algorithms 8 | - testcases: corner cases caught? any crash? 9 | - compress your source code(build) for production -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/.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 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/books-paginated-search/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/books-paginated-search/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/books-paginated-search/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/App.module.css: -------------------------------------------------------------------------------- 1 | .app { 2 | text-align: center; 3 | } -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from "@testing-library/react"; 2 | import App from "./App"; 3 | 4 | describe("App tests", () => { 5 | test("should render", () => { 6 | const view = render(); 7 | expect(view).toBeTruthy(); 8 | const onlyElementForNow = screen.getByText(/Boilerplate/i); 9 | expect(onlyElementForNow).toBeInTheDocument(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/components/BookList/index.js: -------------------------------------------------------------------------------- 1 | const BookList = ({ books }) => { 2 | return ( 3 |
4 | {books.map((obj) => ( 5 |
6 |

{obj.title}

7 |
8 | ))} 9 |
10 | ); 11 | }; 12 | 13 | export default BookList; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/hooks/useDebounce.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export const useDebounce = (value, delay) => { 4 | const [dbValue, setDbValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const tid = setTimeout(() => { 8 | setDbValue(value); 9 | }, delay); 10 | 11 | return () => clearTimeout(tid); 12 | }, [value, delay]); 13 | 14 | return dbValue; 15 | }; 16 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById("root")); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/reducers/appReducer.js: -------------------------------------------------------------------------------- 1 | export const BOOKS_ACTIONS = { 2 | SET_BOOKS: "SET_BOOKS", 3 | SET_QUERY: "SET_QUERY", 4 | SET_PAGE: "SET_PAGE", 5 | SET_MAX_PAGES: "SET_MAX_PAGES", 6 | }; 7 | 8 | export const booksInitStates = { 9 | books: [], 10 | query: "", 11 | page: 1, 12 | maxPages: 1, 13 | }; 14 | 15 | export const booksReducer = (state, action) => { 16 | switch (action.type) { 17 | case BOOKS_ACTIONS.SET_BOOKS: 18 | return { ...state, books: action.payload }; 19 | case BOOKS_ACTIONS.SET_QUERY: 20 | return { ...state, query: action.payload }; 21 | case BOOKS_ACTIONS.SET_PAGE: 22 | return { ...state, page: action.payload }; 23 | case BOOKS_ACTIONS.SET_MAX_PAGES: 24 | return { ...state, maxPages: action.payload }; 25 | default: 26 | return state; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/books-paginated-search/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "context-counter", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.17.0", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/context-counter/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/context-counter/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/context-counter/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | } 3 | 4 | .App-logo { 5 | height: 40vmin; 6 | pointer-events: none; 7 | } 8 | 9 | @media (prefers-reduced-motion: no-preference) { 10 | .App-logo { 11 | animation: App-logo-spin infinite 20s linear; 12 | } 13 | } 14 | 15 | .App-header { 16 | background-color: #282c34; 17 | min-height: 50px; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | color: white; 24 | } 25 | 26 | .App-link { 27 | color: #61dafb; 28 | } 29 | 30 | @keyframes App-logo-spin { 31 | from { 32 | transform: rotate(0deg); 33 | } 34 | to { 35 | transform: rotate(360deg); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/App.js: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | import './App.css'; 3 | 4 | import { AppContext } from './contexts/AppContext'; 5 | import { useState } from 'react'; 6 | import Coordinate from './components/Coordinate'; 7 | 8 | function App() { 9 | const [xy, setXY] = useState({ x: 0, y: 0 }) 10 | 11 | return ( 12 |
13 |
14 | whatever 15 |
16 | 17 | 18 | 19 |
20 | ); 21 | } 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/components/Coordinate.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import { AppContext } from "../contexts/AppContext"; 3 | 4 | function Coordinate() { 5 | const { xy, setXY } = useContext(AppContext); 6 | 7 | const onClickX = (delta) => { 8 | setXY((v) => ({ 9 | x: v.x+delta, y: v.y 10 | })) 11 | } 12 | 13 | const onClickY = (delta) => { 14 | setXY((v) => ({ 15 | x: v.x, y: v.y+delta 16 | })) 17 | } 18 | 19 | return ( 20 |
21 | 22 | x = {xy.x} 23 | 24 | 25 | 26 | y = {xy.y} 27 | 28 |
29 | ); 30 | } 31 | 32 | export default Coordinate; -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/contexts/AppContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const AppContext = createContext(null); 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/context-counter/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/Screenshot 2023-04-26 at 15.53.49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/Screenshot 2023-04-26 at 15.53.49.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/Screenshot 2023-04-26 at 15.54.01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/Screenshot 2023-04-26 at 15.54.01.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.18.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.23.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/Screenshot 2023-04-29 at 01.06.34.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "credit-card-component", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/public/visa_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/credit-card/public/visa_logo.png -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/credit-card/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/api/pokemon/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server' 2 | import { pokemons } from '@/mock-db/index' 3 | 4 | export async function GET(request) { 5 | try { 6 | const searchParams = request.nextUrl.searchParams 7 | const query = searchParams.get('query') 8 | 9 | const results = pokemons.filter(x => x.name.toLowerCase().includes(query?.toLowerCase())).slice(0, 500) 10 | 11 | return NextResponse.json({ pokemons: results }) 12 | } catch (error) { 13 | return NextResponse.json({ error: error.message }, { status: 500 }) 14 | } 15 | } -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/debounced-pokemon-search/app/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/globals.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/debounced-pokemon-search/app/globals.css -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from 'next/font/google' 2 | import './globals.css' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/page.js: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react' 2 | import styles from './page.module.css' 3 | import PokemonList from '@/components/PokemonList' 4 | import SearchInput from "@/components/SearchInput" 5 | 6 | export default function Home({ searchParams }) { 7 | const query = searchParams?.q ?? '' 8 | return ( 9 |
10 | 11 | Loading feed...
}> 12 | 13 | 14 | 15 | ) 16 | } -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/app/page.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | min-height: 100vh; 6 | } 7 | 8 | .searchbar { 9 | font-size: x-large; 10 | margin: 1rem; 11 | } 12 | 13 | .results { 14 | display: flex; 15 | flex-direction: row; 16 | flex-wrap: wrap; 17 | justify-content: flex-start; 18 | align-items: flex-start; 19 | } 20 | 21 | .resultCell { 22 | width: 200px; 23 | height: 200px; 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | border: 1px solid; 28 | } -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/components/PokemonList/index.js: -------------------------------------------------------------------------------- 1 | import { headers } from "next/headers"; 2 | import styles from "@/app/page.module.css"; 3 | 4 | const fetchData = async (query = "") => { 5 | console.log("query", query); 6 | try { 7 | const host = headers().get("host"); 8 | const resp = await fetch(`http://${host}/api/pokemon?query=${query}`); 9 | return resp.json(); 10 | } catch (error) { 11 | console.error(`error: ${error}`); 12 | } 13 | }; 14 | 15 | export default async function PokemonList({ query }) { 16 | const { pokemons } = await fetchData(query); 17 | 18 | return ( 19 | <> 20 |
21 | {pokemons && 22 | pokemons.map((obj, idx) => { 23 | const segments = obj.url.split("/"); 24 | const n = segments.length; 25 | const pID = segments[n - 2]; 26 | const imgURL = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/${pID}.png`; 27 | return ( 28 |
29 |
{obj.name}
30 | image 31 |
32 | ); 33 | })} 34 |
35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/components/SearchInput/index.js: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useEffect, useState } from "react"; 4 | import { useRouter } from 'next/navigation' 5 | import { useDebounce } from "@/hooks/useDebounce" 6 | import styles from "@/app/page.module.css" 7 | 8 | export default function SearchInput({ query = '' }) { 9 | 10 | const router = useRouter() 11 | const [searchInput, setSearchInput] = useState(query) 12 | 13 | const debouncedSearchInput = useDebounce(searchInput, 500) 14 | 15 | const handleSearch = event => { 16 | setSearchInput(event.target.value) 17 | } 18 | 19 | useEffect(() => { 20 | const searchParams = new URLSearchParams() 21 | searchParams.set('q', debouncedSearchInput) 22 | router.replace(`?${searchParams.toString()}`) 23 | }, [debouncedSearchInput, router]) 24 | 25 | return ( 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/hooks/useDebounce.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | export const useDebounce = (value, delay) => { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timeoutID = setTimeout(() => { 8 | setDebouncedValue(value) 9 | }, delay); 10 | return () => clearTimeout(timeoutID) 11 | }, [value, delay]); 12 | 13 | return debouncedValue; 14 | }; -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | images: { 5 | domains: ['raw.githubusercontent.com'], 6 | }, 7 | } 8 | 9 | module.exports = nextConfig 10 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "debounced-pokemon-search", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "react": "^18", 13 | "react-dom": "^18", 14 | "next": "14.0.1" 15 | }, 16 | "devDependencies": { 17 | "eslint": "^8", 18 | "eslint-config-next": "14.0.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-pokemon-search/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/.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 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "debounced-searchbar", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/debounced-search/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/debounced-search/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/debounced-search/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: left; 3 | } 4 | 5 | @media (prefers-reduced-motion: no-preference) { 6 | .App-logo { 7 | animation: App-logo-spin infinite 20s linear; 8 | } 9 | } 10 | 11 | .App-header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .App-link { 23 | color: #61dafb; 24 | } 25 | 26 | .infinit-table-spinner { 27 | height: 16px; 28 | width: 16px; 29 | animation: rotate-spinner 1s infinite linear; 30 | border: 4px solid #ff6600; 31 | border-right-color: transparent; 32 | border-radius: 50%; 33 | } 34 | 35 | @keyframes rotate-spinner { 36 | 0% { transform: rotate(0deg); } 37 | 100% { transform: rotate(360deg); } 38 | } -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/components/NewsCell/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './style.css' 3 | 4 | const NewsCell = ({ idx, feed }) => ( 5 |
window.open(`${feed.url}`, '_blank')}> 6 |
{`${idx + 1}.`}
7 |
8 |
{feed.title}
9 |
{feed.url}
10 |
{`${feed.points} points by ${feed.author}`}
11 |
12 |
13 | ) 14 | 15 | export default NewsCell -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/components/NewsCell/style.css: -------------------------------------------------------------------------------- 1 | .cell { 2 | display: flex; 3 | padding: 4px 4px 0px 4px; 4 | } 5 | 6 | .cell-index { 7 | padding: 4px; 8 | } 9 | 10 | .cell-title { 11 | word-break: break-word; 12 | } 13 | 14 | .cell-link { 15 | cursor: pointer; 16 | word-break: break-word; 17 | font-size: small; 18 | color: grey; 19 | } 20 | 21 | .cell-desc { 22 | word-break: break-word; 23 | font-size: small; 24 | color: grey; 25 | } -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/debounced-search/src/utils/useDebounce.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | export const useDebounce = (value, delay) => { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timeoutID = setTimeout(() => { 8 | setDebouncedValue(value) 9 | }, delay); 10 | return () => clearTimeout(timeoutID) 11 | }, [value, delay]); 12 | 13 | return debouncedValue; 14 | }; -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/.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 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "game-of-life", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/game-of-life/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/game-of-life/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/game-of-life/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: left; 3 | } 4 | 5 | #next-button { 6 | color: cadetblue; 7 | margin-top: 16px; 8 | } 9 | 10 | #game-board { 11 | display: block; 12 | width: 400px; 13 | } 14 | 15 | .row { 16 | display: flex; 17 | border-top: 1px solid rgb(128, 128, 128); 18 | } 19 | .row:last-child { 20 | border-bottom: 1px solid rgb(128, 128, 128); 21 | } 22 | 23 | .cell { 24 | height: 19px; 25 | width: 19px; 26 | 27 | border-left: 1px solid rgb(128, 128, 128); 28 | } 29 | .cell:last-child { 30 | border-right: 1px solid rgb(128, 128, 128); 31 | } 32 | 33 | .colored { 34 | background-color: cadetblue; 35 | } -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/game-of-life/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | **/node_modules 3 | 4 | # testing 5 | /coverage 6 | 7 | # next.js 8 | **/.next/ 9 | **/out/ 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | 18 | # debug 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # local env files 24 | .env.local 25 | .env.development.local 26 | .env.test.local 27 | .env.production.local 28 | 29 | # vercel 30 | .vercel 31 | 32 | # typescript 33 | *.tsbuildinfo 34 | 35 | # VSCode configs 36 | .vscode-test 37 | .vscode/ 38 | 39 | #IDEA config 40 | .idea 41 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global rule: 2 | * @cko-payment-interfaces/web-engineers 3 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/example.png -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "useWorkspaces": "true", 3 | "version": "0.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/**" 6 | ], 7 | "devDependencies": { 8 | "lerna": "^4.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/.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 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/components/PokeCard/index.js: -------------------------------------------------------------------------------- 1 | import styles from "../../styles/Home.module.css"; 2 | 3 | export default function PokeCard({ pokemon: { name, height, imageURL } }) { 4 | return (
5 |
{name}
6 |
{height > 0 ? height : '' }
7 | 8 |
) 9 | } -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poke-search-js", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "12.0.7", 13 | "react": "17.0.2", 14 | "react-dom": "17.0.2" 15 | }, 16 | "devDependencies": { 17 | "eslint": "8.4.1", 18 | "eslint-config-next": "12.0.7" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return 5 | } 6 | 7 | export default MyApp 8 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/packages/poke-search-js/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/public/pokeapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/packages/poke-search-js/public/pokeapi.png -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/styles/Card.modue.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/packages/poke-search-js/styles/Card.modue.css -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-js/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | reactStrictMode: true, 4 | } 5 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poke-search-ts", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "12.0.7", 13 | "react": "17.0.2", 14 | "react-dom": "17.0.2" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "16.11.13", 18 | "@types/react": "17.0.37", 19 | "eslint": "8.4.1", 20 | "eslint-config-next": "12.0.7", 21 | "typescript": "4.5.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import type { AppProps } from 'next/app' 3 | 4 | function MyApp({ Component, pageProps }: AppProps) { 5 | return 6 | } 7 | 8 | export default MyApp 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from "next"; 2 | import Head from "next/head"; 3 | import Image from "next/image"; 4 | import styles from "../styles/Home.module.css"; 5 | 6 | const Home: NextPage = () => { 7 | return ( 8 |
9 | 10 | Create Next App 11 | 12 | 13 | 14 | 15 |
16 |

Welcome to PokéSearch

17 |
18 | 19 | 32 |
33 | ); 34 | }; 35 | 36 | export default Home; 37 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/packages/poke-search-ts/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/public/pokeapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/pokemon-search/packages/poke-search-ts/public/pokeapi.png -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /react-widgets-implementation/pokemon-search/packages/poke-search-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "question-list", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/question-list/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/question-list/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/question-list/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/question-list/result.png -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/question-list/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "random-users", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "react": "^18", 13 | "react-dom": "^18", 14 | "next": "14.0.3" 15 | }, 16 | "devDependencies": { 17 | "eslint": "^8", 18 | "eslint-config-next": "14.0.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/app/globals.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/random-users/src/app/globals.css -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from 'next/font/google' 2 | import './globals.css' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/app/page.module.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/random-users/src/app/page.module.css -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/components/UserCell/index.js: -------------------------------------------------------------------------------- 1 | export default function UserCell({ user }) { 2 | if (!user) return null; 3 | return ( 4 | <> 5 |

6 | {user.name.first} {user.name.last} 7 |

8 | profile-pic 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/utils/debounceFn.js: -------------------------------------------------------------------------------- 1 | export default function debounce(fn, t) { 2 | let timeout = null; 3 | return function (...args) { 4 | if (timeout) { 5 | clearTimeout(timeout); 6 | } 7 | timeout = setTimeout(() => { 8 | fn(...args); 9 | }, t); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /react-widgets-implementation/random-users/src/utils/useDebounce.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export default function useDebounce(value, delay) { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timeoutID = setTimeout(() => { 8 | setDebouncedValue(value); 9 | return () => clearTimeout(timeoutID); 10 | }, delay); 11 | }, [value, delay]); 12 | 13 | return debouncedValue; 14 | } 15 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-debounce-vs-throttle", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.17.0", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-debounce-vs-throttle/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-debounce-vs-throttle/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-debounce-vs-throttle/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 1rem; 3 | } 4 | 5 | span { 6 | font-size: x-large; 7 | margin-left: 1rem; 8 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/App.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import './App.css'; 3 | import { useDebounce } from './hooks/useDebounce' 4 | import { useThrottle } from './hooks/useThrottle'; 5 | 6 | function App() { 7 | 8 | const [defaultText, setDefaultText] = useState('') 9 | const debouncedText = useDebounce(defaultText, 500) 10 | const throttledText = useThrottle(defaultText, 500) 11 | 12 | const defaultOnChange = e => { 13 | setDefaultText(e.target.value) 14 | } 15 | 16 | return ( 17 |
18 | 19 |
20 | Default: 21 | {defaultText} 22 |
23 |
24 | Debounce: 25 | {debouncedText} 26 |
27 |
28 | Throttle: 29 | {throttledText} 30 |
31 |
32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/hooks/useDebounce.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | export const useDebounce = (value, ms) => { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timeoutID = setTimeout(() => { 8 | setDebouncedValue(value) 9 | }, ms); 10 | return () => clearTimeout(timeoutID) 11 | }, [value, ms]); 12 | 13 | return debouncedValue; 14 | }; -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/hooks/useThrottle.js: -------------------------------------------------------------------------------- 1 | import { useState, useRef, useEffect } from 'react' 2 | 3 | export const useThrottle = (value, ms) => { 4 | const [throttledValue, setThrottledValue] = useState(value); 5 | const expiredAt = useRef(0) 6 | 7 | useEffect(() => { 8 | const delay = Math.max(0, expiredAt.current - Date.now()) 9 | const timeoutID = setTimeout(() => { 10 | setThrottledValue(value) 11 | expiredAt.current = Date.now() + ms 12 | }, delay); 13 | return () => clearTimeout(timeoutID) 14 | }, [value, ms]); 15 | 16 | return throttledValue; 17 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-debounce-vs-throttle/src/index.css -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/react-debounce-vs-throttle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-debounce-vs-throttle/src/react-debounce-vs-throttle.gif -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-debounce-vs-throttle/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-fetch-hook", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.17.0", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-fetch-hook/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-fetch-hook/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-fetch-hook/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .row { 6 | display: flex; 7 | gap: 16px; 8 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/hooks/useFetch.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | 3 | export const useFetch = url => { 4 | const [data, setData] = useState(null) 5 | const [error, setError] = useState(null) 6 | const [isLoading, setIsLoading] = useState(false) 7 | 8 | useEffect(() => { 9 | 10 | const ac = new AbortController() 11 | 12 | async function fetchData () { 13 | setIsLoading(true) 14 | try { 15 | const resp = await fetch(url, { 16 | mode: "cors", 17 | signal: ac.signal 18 | }) 19 | if (!resp.ok) { 20 | throw new Error(resp.status) 21 | } 22 | const respData = await resp.json() 23 | setData(respData) 24 | 25 | } catch (error) { 26 | setError(error) 27 | } finally { 28 | setIsLoading(false) 29 | } 30 | } 31 | fetchData() 32 | 33 | return () => ac.abort() 34 | 35 | }, [url]) 36 | 37 | return { data, error, isLoading } 38 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/hooks/useFeteches.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | 3 | /* 4 | concept 5 | */ 6 | export const useFetches = urls => { 7 | const [data, setData] = useState(null) 8 | 9 | useEffect(() => { 10 | 11 | async function fetchData () { 12 | Promise.allSettled(urls.map(url => fetch(url))) 13 | .then(results => { 14 | results.forEach((result, idx) => { 15 | if (result.status === "fulfilled") { 16 | console.log(`${urls[idx]}: ${result.value.status}`) 17 | } 18 | if (result.status === "rejected") { 19 | console.log(`${urls[idx]}: ${result.reason}`); 20 | } 21 | }); 22 | }); 23 | } 24 | fetchData() 25 | 26 | }, []) 27 | 28 | return { data } 29 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-fetch-hook/src/index.css -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-fetch-hook/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-reducer", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.17.0", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-reducer/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-reducer/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/react-reducer/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import { useReducer } from 'react'; 3 | import { initialCount, countReducer } from './reducers/countReducer' 4 | 5 | function App() { 6 | 7 | const [state, dispatch] = useReducer(countReducer, initialCount) 8 | 9 | const decrementOnClick = () => { 10 | dispatch({ type: 'decrement' }) 11 | } 12 | 13 | const incrementOnClick = () => { 14 | dispatch({ type: 'increment' }) 15 | } 16 | 17 | return ( 18 |
19 | 20 | {state.count} 21 | 22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/reducers/countReducer.js: -------------------------------------------------------------------------------- 1 | export const initialCount = { 2 | count: 0 3 | } 4 | 5 | export function countReducer(state, action) { 6 | switch (action.type) { 7 | case 'increment': 8 | return { count: state.count + 1 } 9 | case 'decrement': 10 | return { count: state.count - 1 } 11 | default: 12 | return state 13 | } 14 | } -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/react-reducer/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/.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 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recent-trades", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/recent-trades/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/recent-trades/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/recent-trades/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | td, 6 | th { 7 | border: 1px solid #dddddd; 8 | text-align: left; 9 | padding: 8px; 10 | } 11 | 12 | tr { 13 | cursor: pointer; 14 | } -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/recent-trades/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/.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 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stock-prices", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "eslint": "8.41.0", 13 | "eslint-config-next": "13.4.4", 14 | "next": "13.4.4", 15 | "react": "18.2.0", 16 | "react-dom": "18.2.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/src/app/StockList/index.module.css: -------------------------------------------------------------------------------- 1 | .row { 2 | display: flex; 3 | gap: 16px; 4 | } -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/stock-prices/src/app/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import { Inter } from 'next/font/google' 3 | 4 | const inter = Inter({ subsets: ['latin'] }) 5 | 6 | export const metadata = { 7 | title: 'Create Next App', 8 | description: 'Generated by create next app', 9 | } 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/src/app/page.js: -------------------------------------------------------------------------------- 1 | import styles from './page.module.css' 2 | import StockList from './StockList'; 3 | 4 | // const CRYPTO_PRICES_MOCK = 'https://api.frontendexpert.io/api/fe/cryptocurrencies'; 5 | const CRYPTO_PRICES_MOCK = 'https://comet-shimmer-stream.glitch.me/mock_crypto_prices'; 6 | 7 | 8 | async function fetchCryptos(page = 1) { 9 | const res = await fetch(`${CRYPTO_PRICES_MOCK}?page=${page}`); 10 | return res.json(); 11 | } 12 | 13 | export default async function Home() { 14 | const data = await fetchCryptos(); 15 | 16 | return (<> 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /react-widgets-implementation/stock-prices/src/hooks/useFetch.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | 3 | export const useFetch = (url, options = {}) => { 4 | const [data, setData] = useState() 5 | const [error, setError] = useState() 6 | const [isLoading, setIsLoading] = useState() 7 | 8 | useEffect(() => { 9 | 10 | const abc = new AbortController() 11 | 12 | setIsLoading(true) 13 | 14 | async function fetchData () { 15 | try { 16 | const resp = await fetch(url, { 17 | ...options, 18 | signal: abc.signal 19 | }) 20 | if (!resp.ok) { 21 | throw new Error(resp.status) 22 | } 23 | const respData = await resp.json() 24 | setData(respData) 25 | setIsLoading(false) 26 | 27 | } catch (error) { 28 | setError(error) 29 | setIsLoading(true) 30 | } 31 | } 32 | fetchData() 33 | 34 | return () => abc.abort() 35 | 36 | }, [url, options]) 37 | 38 | return { data, error, isLoading } 39 | } -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/.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 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "suspense-playground", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/suspense-playground/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/suspense-playground/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/suspense-playground/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/App.js: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import './App.css'; 3 | import Posts from './components/Posts'; 4 | import LoadingIndicator from './components/LoadingIndicator'; 5 | 6 | function App() { 7 | return ( 8 |
9 | }> 10 | 11 | 12 |
13 | ); 14 | } 15 | export default App; 16 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/components/LoadingIndicator.js: -------------------------------------------------------------------------------- 1 | const LoadingIndicator = () => { 2 | return (
Loading...
) 3 | }; 4 | export default LoadingIndicator; -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/components/Posts.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import genFetch from "../utils/genFetch"; 3 | 4 | const fetchFn = genFetch("https://jsonplaceholder.typicode.com/posts"); 5 | 6 | const Posts = () => { 7 | const posts = fetchFn.read() 8 | return ( 9 |
10 | {posts.map((post) => ( 11 |
12 |

{post.title}

13 |

{post.body}

14 |
15 | ))} 16 |
17 | ); 18 | }; 19 | export default Posts; -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/suspense-playground/src/utils/genFetch.js: -------------------------------------------------------------------------------- 1 | // This is the most critical part for using Suspend 2 | // aka. Suspense-enabled data sources 3 | function genFetch(url) { 4 | let status = "pending"; 5 | let result; 6 | let suspender = fetch(url) 7 | .then((res) => res.json()) 8 | // Fetch request has gone well 9 | .then((success) => { 10 | status = "fulfilled"; 11 | result = success; 12 | }) 13 | // Fetch request has failed 14 | .catch((error) => { 15 | status = "rejected"; 16 | result = error; 17 | }); 18 | 19 | const read = () => { 20 | if (status === "pending") { 21 | throw suspender; // Suspend(A way to tell React data is still fetching) 22 | } else if (status === "rejected") { 23 | throw result; // Result is an error 24 | } else if (status === "fulfilled") { 25 | return result; // Result is a fulfilled promise 26 | } 27 | }; 28 | 29 | return { read } 30 | } 31 | 32 | export default genFetch; -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/tip-calculator/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/tip-calculator/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/tip-calculator/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | 40 | #root { 41 | background-color: lightgrey; 42 | width: fit-content; 43 | padding: 10px; 44 | border-radius: 10px; 45 | } 46 | 47 | label { 48 | display: block; 49 | font-weight: bold; 50 | } 51 | 52 | input { 53 | display: block; 54 | font-weight: bold; 55 | } 56 | 57 | input { 58 | display: block; 59 | width: 100%; 60 | margin-bottom: 10px; 61 | } 62 | 63 | p { 64 | text-align: right; 65 | } 66 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/tip-calculator/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-list", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.17.0", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-scripts": "5.0.1", 12 | "web-vitals": "^2.1.4" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/todo-list/public/favicon.ico -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/todo-list/public/logo192.png -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/react-widgets-implementation/todo-list/public/logo512.png -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 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 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/App.css: -------------------------------------------------------------------------------- 1 | html { 2 | padding: 1rem; 3 | } 4 | 5 | .App { 6 | text-align: center; 7 | } 8 | 9 | .App-logo { 10 | height: 40vmin; 11 | pointer-events: none; 12 | } 13 | 14 | @media (prefers-reduced-motion: no-preference) { 15 | .App-logo { 16 | animation: App-logo-spin infinite 20s linear; 17 | } 18 | } 19 | 20 | .App-header { 21 | background-color: #282c34; 22 | min-height: 100vh; 23 | display: flex; 24 | flex-direction: column; 25 | align-items: center; 26 | justify-content: center; 27 | font-size: calc(10px + 2vmin); 28 | color: white; 29 | } 30 | 31 | .App-link { 32 | color: #61dafb; 33 | } 34 | 35 | @keyframes App-logo-spin { 36 | from { 37 | transform: rotate(0deg); 38 | } 39 | to { 40 | transform: rotate(360deg); 41 | } 42 | } 43 | 44 | .item { 45 | display: flex; 46 | column-gap: 1rem; 47 | color: red; 48 | font-size: x-large; 49 | } -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | const root = ReactDOM.createRoot(document.getElementById('root')); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /react-widgets-implementation/todo-list/src/setupTests.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/2048/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
2048
9 |
10 |
11 |
12 | up, down, left, right arrows to move the blocks 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/DOMRenderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DOM Renderer 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/accordion/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Accordion Demo 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/accordion/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | font-size: 16px; 4 | } 5 | 6 | .accordion { 7 | width: 600px; 8 | margin: auto; 9 | } 10 | 11 | .accordion-row { 12 | margin-top: 8px; 13 | } 14 | 15 | .accordion-row-title { 16 | font-size: 1.6rem; 17 | background-color: lightgray; 18 | } 19 | 20 | .accordion-row-desc { 21 | margin: 4px; 22 | } 23 | 24 | .display-none { 25 | display: none; 26 | } 27 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/analog-clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/analog-clock/index.js: -------------------------------------------------------------------------------- 1 | const hourHand = document.getElementById('hour') 2 | const minuteHand = document.getElementById('minute') 3 | const secondHand = document.getElementById('second') 4 | 5 | const floor = Math.floor 6 | 7 | setInterval(() => { 8 | 9 | const d = new Date() 10 | const hh = d.getHours() 11 | const mm = d.getMinutes() 12 | const ss = d.getSeconds() 13 | 14 | const rotation_hh = (hh%12) * floor(360/12) 15 | const rotation_mm = mm * floor(360/60) 16 | const rotation_ss = ss * floor(360/60) 17 | 18 | hourHand.style.transform = `rotate(${rotation_hh}deg)` 19 | minuteHand.style.transform = `rotate(${rotation_mm}deg)` 20 | secondHand.style.transform = `rotate(${rotation_ss}deg)` 21 | }, 1000) -------------------------------------------------------------------------------- /vanilla-widgets-implementation/analog-clock/style.css: -------------------------------------------------------------------------------- 1 | #clock { 2 | position: relative; 3 | margin: auto; 4 | height: 500px; 5 | /*to make the height and width responsive*/ 6 | width: 500px; 7 | /* background: url(clock.png) no-repeat; */ 8 | /*setting our background image*/ 9 | background-size: 100%; 10 | } 11 | 12 | #hour, 13 | #minute, 14 | #second { 15 | position: absolute; 16 | border-radius: 10px; 17 | transform-origin: bottom; 18 | } 19 | 20 | #hour { 21 | background: red; 22 | width: 1%; 23 | height: 25%; 24 | top: 25%; 25 | left: 50%; 26 | } 27 | 28 | #minute { 29 | background: grey; 30 | width: 1%; 31 | height: 30%; 32 | top: 20%; 33 | left: 50%; 34 | } 35 | 36 | #second { 37 | background: black; 38 | width: 1%; 39 | height: 40%; 40 | top: 10%; 41 | left: 50%; 42 | } 43 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/carousel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Carousel Demo 5 | 6 | 7 | 8 | 9 | 10 |
11 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/carousel/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | display: flex; 4 | height: 100vh; 5 | justify-content: center; 6 | align-items: center; 7 | } 8 | 9 | .carousel { 10 | display: flex; 11 | position: relative; 12 | } 13 | 14 | .button { 15 | background: rosybrown; 16 | height: 300px; 17 | width: 75px; 18 | color: white; 19 | } 20 | 21 | .buttonLeft { 22 | border-radius: 10px 0 0 10px; 23 | } 24 | 25 | .buttonRight { 26 | border-radius: 0 10px 10px 0; 27 | } 28 | 29 | .carouselDisplay { 30 | background: brown; 31 | height: 300px; 32 | width: 450px; 33 | display: flex; 34 | overflow: hidden; 35 | } 36 | 37 | .image { 38 | width: 100%; 39 | min-width: 450px; 40 | height: 100%; 41 | object-fit: cover; 42 | transform: translate(-450px, 0); 43 | } 44 | 45 | /* left button */ 46 | .image-slide-left { 47 | transition: 0.3s ease-in-out; 48 | transform: translate(0px, 0); 49 | } 50 | 51 | /* right button */ 52 | .image-slide-right { 53 | transition: 0.3s ease-in-out; 54 | transform: translate(-900px, 0); 55 | } 56 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/csv-viewer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CSV Viewer Demo 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/csv-viewer/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | font-size: 16px; 4 | } 5 | 6 | .header { 7 | display: flex; 8 | } 9 | 10 | .header-text { 11 | color: teal; 12 | width: 150px; 13 | } 14 | 15 | .row { 16 | display: flex; 17 | } 18 | 19 | .row-text { 20 | width: 150px; 21 | } 22 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/csv-viewer/test.csv: -------------------------------------------------------------------------------- 1 | email,phone,lname,fname,bday 2 | abc0@abc.com,1234567890,BC,A0,1 Feb 2020 3 | abc1@abc.com,1234567891,BC,A1,2 Feb 2020 4 | abc2@abc.com,1234567892,"BC, D",A2,3 Feb 2020 -------------------------------------------------------------------------------- /vanilla-widgets-implementation/debounce-and-throttle/debouncing-vs-throttling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/vanilla-widgets-implementation/debounce-and-throttle/debouncing-vs-throttling.gif -------------------------------------------------------------------------------- /vanilla-widgets-implementation/debounce-and-throttle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 | Default: 14 | 15 |
16 |
17 | Debounce: 18 | 19 |
20 |
21 | Throttle: 22 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/debounced-searchbar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Search for Companies 5 | 6 | 7 | 8 | 9 | 10 |

Search For Companies

11 | 12 |
    13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/debounced-searchbar/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/draggable-box/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
    9 |
    10 |
    11 | 12 | 13 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/draggable-box/style.css: -------------------------------------------------------------------------------- 1 | #box { 2 | width: 100px; 3 | height: 100px; 4 | background-color: red; 5 | position: absolute; 6 | } 7 | 8 | #resize { 9 | width: 10px; 10 | height: 10px; 11 | background-color: blue; 12 | position: absolute; 13 | bottom: -5px; 14 | right: -5px; 15 | } -------------------------------------------------------------------------------- /vanilla-widgets-implementation/game-of-life/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Game of Life 5 | 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/game-of-life/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* font-family: sans-serif; 3 | font-size: 16px; 4 | margin: 0px; */ 5 | } 6 | 7 | #next-button { 8 | color: cadetblue; 9 | margin-top: 16px; 10 | } 11 | 12 | #game-board { 13 | display: block; 14 | width: 400px; 15 | } 16 | 17 | .row { 18 | display: flex; 19 | } 20 | .row:last-child { 21 | border-bottom: 1px solid rgb(128, 128, 128); 22 | } 23 | 24 | .cell { 25 | height: 19px; 26 | width: 19px; 27 | border-top: 1px solid rgb(128, 128, 128); 28 | border-left: 1px solid rgb(128, 128, 128); 29 | } 30 | .cell:last-child { 31 | border-right: 1px solid rgb(128, 128, 128); 32 | } 33 | 34 | .colored { 35 | background-color: cadetblue; 36 | } 37 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/images/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/vanilla-widgets-implementation/images-at-corners/images/0.png -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/vanilla-widgets-implementation/images-at-corners/images/1.png -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/vanilla-widgets-implementation/images-at-corners/images/2.png -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/calvinchankf/JSConcepts/f313d26386c78ccc51bfbf2c7f0f05bb63b5ef7a/vanilla-widgets-implementation/images-at-corners/images/3.png -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Images at corners 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
    12 | 13 | 14 | 15 | 16 |
    17 |
    18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/src/index.js: -------------------------------------------------------------------------------- 1 | // https://www.glassdoor.com.hk/Interview/Given-a-DIV-box-of-x-width-and-y-height-in-a-browser-how-do-you-position-four-smaller-images-in-each-corner-of-the-box-QTN_45724.htm -------------------------------------------------------------------------------- /vanilla-widgets-implementation/images-at-corners/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | font-size: 16px; 4 | margin: 0px; 5 | } 6 | 7 | .box { 8 | width: 800px; 9 | height: 600px; 10 | margin: auto; 11 | background-color: turquoise; 12 | position: relative; 13 | } 14 | 15 | .box > img { 16 | width: 64px; 17 | object-fit: fill; 18 | position: absolute; 19 | } 20 | 21 | .top-left { 22 | left: 0; 23 | top: 0; 24 | } 25 | 26 | .top-right { 27 | top: 0; 28 | right: 0; 29 | } 30 | 31 | .bottom-left { 32 | bottom: 0; 33 | left: 0; 34 | } 35 | 36 | .bottom-right { 37 | bottom: 0; 38 | right: 0; 39 | } 40 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/instagram-create-poll/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Instagram Create Poll Demo 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
    12 |
    Which color do you like the most?
    13 |
    14 |
    15 |
    16 | 17 |
    18 |
    19 |
    20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/instagram-create-poll/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | font-size: x-large; 4 | } 5 | 6 | .poll-widget { 7 | width: 400px; 8 | } 9 | 10 | .option-nth-wrapper { 11 | border: 1px solid #ccc; 12 | border-radius: 14px; 13 | height: 28px; 14 | width: 28px; 15 | text-align: center; 16 | margin-right: 5px; 17 | } 18 | 19 | .option { 20 | border: 1px solid #ccc; 21 | border-radius: 28px; 22 | margin: 10px; 23 | padding: 10px; 24 | color: black; 25 | display: flex; 26 | } 27 | 28 | .selected { 29 | background-color: #4bbb1b; 30 | color: white; 31 | } 32 | 33 | .create-options { 34 | border: 2px dashed #ccc; 35 | border-radius: 28px; 36 | margin: 10px; 37 | padding: 10px; 38 | color: black; 39 | display: flex; 40 | } 41 | 42 | .add-option-input { 43 | font-size: x-large; 44 | border: unset; 45 | outline: none; 46 | } 47 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/query/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

    Main Page Header

    5 |

    Secondary Header

    6 |

    P0

    7 |
    8 |
    Content0
    9 |

    P1

    10 |
    11 | 12 |
    13 |
    Content1
    14 |

    P2

    15 |
    16 | 17 |
    18 |
      19 |
    • Li0
    • 20 |
    • Li1
    • 21 |
    • Li2
    • 22 |
    • Li3
    • 23 |
    • Li4
    • 24 |
    • Li5
    • 25 |
    26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/query/src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.1point3acres.com/bbs/interview/goldmansachs-front-end-developer-464431.html 3 | */ 4 | 5 | // Q1 6 | const pTagElements = document.querySelectorAll('p') 7 | console.log(pTagElements) 8 | 9 | // Q2 10 | let allChildren = [] 11 | for (let ele of pTagElements) { 12 | allChildren = allChildren.concat(ele.children) 13 | } 14 | console.log(allChildren) 15 | 16 | // Q3 17 | const liElements = document.querySelectorAll('li') 18 | for (let ele of liElements) { 19 | const spanElement = document.createElement("span"); 20 | ele.appendChild(spanElement) 21 | } -------------------------------------------------------------------------------- /vanilla-widgets-implementation/simple-sudoku/README.md: -------------------------------------------------------------------------------- 1 | # simple-sudoku 2 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/simple-sudoku/widget.css: -------------------------------------------------------------------------------- 1 | /* Add CSS here */ 2 | body { 3 | } 4 | 5 | .board { 6 | width: 160px; 7 | } 8 | 9 | .row { 10 | display: flex; 11 | border-top: 1px solid black; 12 | } 13 | 14 | .row:last-child { 15 | border-bottom: 1px solid black; 16 | } 17 | 18 | .col { 19 | width: 40px; 20 | height: 40px; 21 | border-left: 1px solid black; 22 | } 23 | 24 | .col:last-child { 25 | border-right: 1px solid black; 26 | } -------------------------------------------------------------------------------- /vanilla-widgets-implementation/snake-game/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
    9 |
    10 |
    11 | up, down, left, right arrows to move the snake 12 |
    13 | 14 | 15 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/snake-game/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | /* width: 100%; 3 | height: 100%; */ 4 | } 5 | 6 | body { 7 | /* width: 100%; 8 | height: 100%; */ 9 | display: flex; 10 | flex-direction: column; 11 | /* justify-content: center; */ 12 | align-items: center; 13 | } 14 | 15 | .row { 16 | display: flex; 17 | border-top: 1px solid rgb(128, 128, 128); 18 | } 19 | 20 | .row:last-child { 21 | border-bottom: 1px solid rgb(128, 128, 128); 22 | } 23 | 24 | .cell { 25 | height: 19px; 26 | width: 19px; 27 | border-left: 1px solid rgb(128, 128, 128); 28 | } 29 | 30 | .cell:last-child { 31 | border-right: 1px solid rgb(128, 128, 128); 32 | } 33 | 34 | .colored { 35 | background-color: cadetblue; 36 | } 37 | 38 | .snake { 39 | background-color: cadetblue; 40 | } 41 | 42 | .food { 43 | background-color: red; 44 | } -------------------------------------------------------------------------------- /vanilla-widgets-implementation/stock-prices/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Search for Companies 5 | 6 | 7 | 8 | 9 | 10 |

    Mock crypyo prices

    11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
    NamePriceMarketCap
    20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/stock-prices/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/tableview/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | 5 | td, 6 | th { 7 | border: 1px solid #dddddd; 8 | text-align: left; 9 | padding: 8px; 10 | } 11 | 12 | tr { 13 | cursor: pointer; 14 | } 15 | 16 | /* tr:nth-child(even) { 17 | background-color: #dddddd; 18 | } */ 19 | 20 | .highlight { 21 | background-color: red; 22 | } 23 | 24 | .non-highlight { 25 | background-color: unset; 26 | } 27 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/tic-tac-toe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tic Tac Toe 7 | 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /vanilla-widgets-implementation/tic-tac-toe/styles.css: -------------------------------------------------------------------------------- 1 | /* Add CSS here */ 2 | 3 | #board { 4 | width: 150px; 5 | height: 150px; 6 | margin: auto; 7 | } 8 | 9 | .row { 10 | display: flex; 11 | border-top: 1px solid black; 12 | } 13 | 14 | .row:last-child { 15 | border-bottom: 1px solid black; 16 | } 17 | 18 | .col { 19 | width: 50px; 20 | height: 50px; 21 | border-left: 1px solid black; 22 | } 23 | 24 | .col:last-child { 25 | border-right: 1px solid black; 26 | } --------------------------------------------------------------------------------