diff --git a/hooks/00_BoilerPlate/package.json b/hooks/00_BoilerPlate/package.json index 12b2f5b2..11503643 100644 --- a/hooks/00_BoilerPlate/package.json +++ b/hooks/00_BoilerPlate/package.json @@ -1,35 +1,30 @@ { - "name": "react-typescript-by-sample", + "name": "00_boilerplate", "version": "1.0.0", - "description": "React Typescript examples", + "description": "In this sample we setup the basic plumbing to \"build\" our project and launch it in a dev server.", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, - "keywords": [ - "react", - "typescript", - "hooks" - ], - "author": "Braulio Diez Botella", - "license": "MIT", + "author": "", + "license": "ISC", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" } } diff --git a/hooks/00_BoilerPlate/src/index.html b/hooks/00_BoilerPlate/src/index.html index d493ac4d..50d0c9cc 100644 --- a/hooks/00_BoilerPlate/src/index.html +++ b/hooks/00_BoilerPlate/src/index.html @@ -1,12 +1,15 @@ - + + - - + + +
-

Sample app

+

Sample app

- - + + + \ No newline at end of file diff --git a/hooks/00_BoilerPlate/webpack.config.js b/hooks/00_BoilerPlate/webpack.config.js index 37715722..67747365 100644 --- a/hooks/00_BoilerPlate/webpack.config.js +++ b/hooks/00_BoilerPlate/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: ["@babel/polyfill", "./main.ts"], - output: { - path: path.join(basePath, "dist"), - filename: "bundle.js", - }, - devtool: "source-map", - devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", - }, - module: { - rules: [ - { - test: /\.(ts|tsx)$/, - exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, - }, - { - test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], - }, - { - test: /\.(png|jpg|gif|svg)$/, - loader: "file-loader", - options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - hash: true, - }), - new MiniCssExtractPlugin({ - filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + context: path.join(basePath, "src"), + resolve: { + extensions: [".js", ".ts", ".tsx"] + }, + entry: ["@babel/polyfill", "./main.ts"], + output: { + path: path.join(basePath, "dist"), + filename: "bundle.js" + }, + devtool: "source-map", + devServer: { + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } + }, + module: { + rules: [ + { + test: /\.(ts|tsx)$/, + exclude: /node_modules/, + loader: "ts-loader", + }, + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, "css-loader"] + }, + { + test: /\.(png|jpg|gif|svg)$/, + loader: "file-loader", + options: { + name: "assets/img/[name].[ext]?[hash]" + } + } + ] + }, + plugins: [ + //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: "index.html", //Name of file in ./dist/ + template: "index.html", //Name of template in ./src + hash: true + }), + new MiniCssExtractPlugin({ + filename: "[name].css", + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/01_HelloReact/.babelrc b/hooks/01_HelloReact/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/01_HelloReact/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/01_HelloReact/package.json b/hooks/01_HelloReact/package.json index 264e71d2..2e688fec 100644 --- a/hooks/01_HelloReact/package.json +++ b/hooks/01_HelloReact/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,25 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/01_HelloReact/webpack.config.js b/hooks/01_HelloReact/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/01_HelloReact/webpack.config.js +++ b/hooks/01_HelloReact/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/02_Properties/.babelrc b/hooks/02_Properties/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/02_Properties/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/02_Properties/package.json b/hooks/02_Properties/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/02_Properties/package.json +++ b/hooks/02_Properties/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/02_Properties/webpack.config.js b/hooks/02_Properties/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/02_Properties/webpack.config.js +++ b/hooks/02_Properties/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/03_State/.babelrc b/hooks/03_State/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/03_State/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/03_State/package.json b/hooks/03_State/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/03_State/package.json +++ b/hooks/03_State/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/03_State/src/app.tsx b/hooks/03_State/src/app.tsx index f7d14292..d1883875 100644 --- a/hooks/03_State/src/app.tsx +++ b/hooks/03_State/src/app.tsx @@ -3,16 +3,14 @@ import { HelloComponent } from "./hello"; import { NameEditComponent } from "./nameEdit"; export const App = () => { - const [name, setName] = React.useState("initialName"); - - const setUsernameState = (event: React.ChangeEvent) => { - setName(event.target.value); - }; - - return ( - <> - - - - ); -}; + const [name, setName] = React.useState('defaultUserName') + const setUsernameState = (event: React.ChangeEvent) => { + setName(event.target.value) + } + return ( + <> + + + + ); +}; \ No newline at end of file diff --git a/hooks/03_State/src/hello.tsx b/hooks/03_State/src/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/03_State/src/hello.tsx +++ b/hooks/03_State/src/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/03_State/src/index.tsx b/hooks/03_State/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/03_State/src/index.tsx +++ b/hooks/03_State/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/03_State/src/nameEdit.tsx b/hooks/03_State/src/nameEdit.tsx index 02f7e36d..a6ef1ef8 100644 --- a/hooks/03_State/src/nameEdit.tsx +++ b/hooks/03_State/src/nameEdit.tsx @@ -1,13 +1,13 @@ import * as React from "react"; interface Props { - userName: string; - onChange: (e: React.ChangeEvent) => void; + userName: string; + onChange: (e: React.ChangeEvent) => void; } -export const NameEditComponent: React.FC = (props) => ( - <> - - - -); +export const NameEditComponent = (props: Props) => ( + <> + + + +) \ No newline at end of file diff --git a/hooks/03_State/webpack.config.js b/hooks/03_State/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/03_State/webpack.config.js +++ b/hooks/03_State/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/04_Callback/.babelrc b/hooks/04_Callback/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/04_Callback/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/04_Callback/package.json b/hooks/04_Callback/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/04_Callback/package.json +++ b/hooks/04_Callback/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/04_Callback/src/app.tsx b/hooks/04_Callback/src/app.tsx index 84c22a8a..870f4a82 100644 --- a/hooks/04_Callback/src/app.tsx +++ b/hooks/04_Callback/src/app.tsx @@ -3,16 +3,14 @@ import { HelloComponent } from "./hello"; import { NameEditComponent } from "./nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - - const setUsernameState = (newName : string) => { - setName(newName); - }; - - return ( - <> - - - - ); -}; + const [name, setName] = React.useState('defaultUserName') + const setUsernameState = (newName: string) => { + setName(newName) + } + return ( + <> + + + + ); +}; \ No newline at end of file diff --git a/hooks/04_Callback/src/hello.tsx b/hooks/04_Callback/src/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/04_Callback/src/hello.tsx +++ b/hooks/04_Callback/src/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/04_Callback/src/index.tsx b/hooks/04_Callback/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/04_Callback/src/index.tsx +++ b/hooks/04_Callback/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/04_Callback/src/nameEdit.tsx b/hooks/04_Callback/src/nameEdit.tsx index 8b1a5ca8..0e203eab 100644 --- a/hooks/04_Callback/src/nameEdit.tsx +++ b/hooks/04_Callback/src/nameEdit.tsx @@ -1,26 +1,25 @@ import * as React from "react"; interface Props { - initialUserName: string; - onNameUpdated: (newName: string) => any; + initialUserName: string, + onNameUpdated: (newName: string) => any; } -export const NameEditComponent: React.FC = (props) => { - const [editingName, setEditingName] = React.useState(props.initialUserName); +export const NameEditComponent = (props: Props) => { + const [editingName, setEditingName] = React.useState(props.initialUserName); - const onChange = (e: React.ChangeEvent) => { - setEditingName(e.target.value); - }; + const onChange = (e: React.ChangeEvent) => { + setEditingName(e.target.value); + } - const onNameSubmit = (event: any): any => { - props.onNameUpdated(editingName); - }; - - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + props.onNameUpdated(editingName); + } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/04_Callback/webpack.config.js b/hooks/04_Callback/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/04_Callback/webpack.config.js +++ b/hooks/04_Callback/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/05_Refactor/.babelrc b/hooks/05_Refactor/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/05_Refactor/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/05_Refactor/package.json b/hooks/05_Refactor/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/05_Refactor/package.json +++ b/hooks/05_Refactor/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/05_Refactor/src/app.tsx b/hooks/05_Refactor/src/app.tsx index e02695fb..854dc0fe 100644 --- a/hooks/05_Refactor/src/app.tsx +++ b/hooks/05_Refactor/src/app.tsx @@ -3,33 +3,26 @@ import { HelloComponent } from "./hello"; import { NameEditComponent } from "./nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - - - - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + + + + ); +}; \ No newline at end of file diff --git a/hooks/05_Refactor/src/hello.tsx b/hooks/05_Refactor/src/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/05_Refactor/src/hello.tsx +++ b/hooks/05_Refactor/src/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/05_Refactor/src/index.tsx b/hooks/05_Refactor/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/05_Refactor/src/index.tsx +++ b/hooks/05_Refactor/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/05_Refactor/src/nameEdit.tsx b/hooks/05_Refactor/src/nameEdit.tsx index c2eebf31..2a40ec7f 100644 --- a/hooks/05_Refactor/src/nameEdit.tsx +++ b/hooks/05_Refactor/src/nameEdit.tsx @@ -1,26 +1,35 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onNameUpdated(); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/05_Refactor/webpack.config.js b/hooks/05_Refactor/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/05_Refactor/webpack.config.js +++ b/hooks/05_Refactor/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/06_Enable/.babelrc b/hooks/06_Enable/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/06_Enable/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/06_Enable/package.json b/hooks/06_Enable/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/06_Enable/package.json +++ b/hooks/06_Enable/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/06_Enable/src/app.tsx b/hooks/06_Enable/src/app.tsx index 8a834bf6..3e5fc01f 100644 --- a/hooks/06_Enable/src/app.tsx +++ b/hooks/06_Enable/src/app.tsx @@ -3,34 +3,30 @@ import { HelloComponent } from "./hello"; import { NameEditComponent } from "./nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - - - - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + + + + ); +}; \ No newline at end of file diff --git a/hooks/06_Enable/src/hello.tsx b/hooks/06_Enable/src/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/06_Enable/src/hello.tsx +++ b/hooks/06_Enable/src/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/06_Enable/src/index.tsx b/hooks/06_Enable/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/06_Enable/src/index.tsx +++ b/hooks/06_Enable/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/06_Enable/src/nameEdit.tsx b/hooks/06_Enable/src/nameEdit.tsx index 7f9091e3..d7648086 100644 --- a/hooks/06_Enable/src/nameEdit.tsx +++ b/hooks/06_Enable/src/nameEdit.tsx @@ -1,29 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled: boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/06_Enable/webpack.config.js b/hooks/06_Enable/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/06_Enable/webpack.config.js +++ b/hooks/06_Enable/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/07_ColorPicker/.babelrc b/hooks/07_ColorPicker/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/07_ColorPicker/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/07_ColorPicker/package.json b/hooks/07_ColorPicker/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/07_ColorPicker/package.json +++ b/hooks/07_ColorPicker/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/app.tsx b/hooks/07_ColorPicker/src/app.tsx index b629405c..ce3c9494 100644 --- a/hooks/07_ColorPicker/src/app.tsx +++ b/hooks/07_ColorPicker/src/app.tsx @@ -1,43 +1,37 @@ import * as React from "react"; -import { HelloComponent, NameEditComponent, ColorBrowser, ColorPicker } from "./components"; +import { ColorBrowser, HelloComponent, NameEditComponent, ColorPicker } from "./components"; import { Color } from "./model/color"; +// import { HelloComponent } from "./components/hello"; +// import { NameEditComponent } from "./components/nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); - const [color, setColor] = React.useState({ - red: 20, - green: 40, - blue: 180 - }); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ red: 20, green: 40, blue: 180 }) + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - - - - - - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + + + + + + ); +}; \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/components/colorBrowser.tsx b/hooks/07_ColorPicker/src/components/colorBrowser.tsx index 813746ce..827ae714 100644 --- a/hooks/07_ColorPicker/src/components/colorBrowser.tsx +++ b/hooks/07_ColorPicker/src/components/colorBrowser.tsx @@ -1,16 +1,16 @@ import * as React from "react"; -import { Color } from "../model/color"; +import { Color } from "../model/color" interface Props { - color: Color; + color: Color; } -export const ColorBrowser: React.FC = (props) => { - const divStyle: React.CSSProperties = { - width: "11rem", - height: "7rem", - backgroundColor: `rgb(${props.color.red},${props.color.green}, ${props.color.blue})`, - }; +export const ColorBrowser = (props: Props) => { + const divStyle: React.CSSProperties = { + width: "11rem", + height: "7rem", + backgroundColor: `rgb(${props.color.red},${props.color.green},${props.color.blue})` + } - return
; -}; + return
; +} \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/components/colorPicker.tsx b/hooks/07_ColorPicker/src/components/colorPicker.tsx deleted file mode 100644 index 23bdca3c..00000000 --- a/hooks/07_ColorPicker/src/components/colorPicker.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react"; -import { Color } from "../model/color"; - -interface Props { - color: Color; - onColorUpdated: (color: Color) => void; -} - -export const ColorPicker: React.FC = (props) => ( -
- - props.onColorUpdated({ - red: +event.target.value, - green: props.color.green, - blue: props.color.blue - }) - } - /> - {props.color.red} -
- - props.onColorUpdated({ - red: props.color.red, - green: event.target.value, - blue: props.color.blue - }) - } - /> - {props.color.green} -
- - props.onColorUpdated({ - red: props.color.red, - green: props.color.green, - blue: event.target.value - }) - } - /> - {props.color.blue} -
-
-); diff --git a/hooks/07_ColorPicker/src/components/colorpicker.tsx b/hooks/07_ColorPicker/src/components/colorpicker.tsx new file mode 100644 index 00000000..4e9f680a --- /dev/null +++ b/hooks/07_ColorPicker/src/components/colorpicker.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import { Color } from "../model/color"; + +interface Props { + color: Color; + onColorUpdated: (color: Color) => void; +} + +export const ColorPicker = (props: Props) => ( +
+ + props.onColorUpdated({ + red: +event.target.value, + green: props.color.green, + blue: props.color.blue + }) + } + /> + {props.color.red} + +
+ + props.onColorUpdated({ + red: props.color.red, + green: +event.target.value, + blue: props.color.blue + }) + } + /> + {props.color.green} +
+ + + props.onColorUpdated({ + red: props.color.red, + green: props.color.green, + blue: +event.target.value + }) + } + /> + {props.color.blue} +
+
+); \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/components/hello.tsx b/hooks/07_ColorPicker/src/components/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/07_ColorPicker/src/components/hello.tsx +++ b/hooks/07_ColorPicker/src/components/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/07_ColorPicker/src/components/index.tsx b/hooks/07_ColorPicker/src/components/index.tsx index 7d9f725c..c9937b6f 100644 --- a/hooks/07_ColorPicker/src/components/index.tsx +++ b/hooks/07_ColorPicker/src/components/index.tsx @@ -1,4 +1,14 @@ -export * from "./hello"; -export * from "./nameEdit"; -export * from "./colorBrowser"; -export * from "./colorPicker"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from '../app'; + +ReactDOM.render( + , + document.getElementById('root') +); + + +export * from "./hello" +export * from "./nameEdit" +export * from "./colorBrowser" +export * from './colorPicker' \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/components/nameEdit.tsx b/hooks/07_ColorPicker/src/components/nameEdit.tsx index 5461073e..d7648086 100644 --- a/hooks/07_ColorPicker/src/components/nameEdit.tsx +++ b/hooks/07_ColorPicker/src/components/nameEdit.tsx @@ -1,30 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled : boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/07_ColorPicker/src/index.tsx b/hooks/07_ColorPicker/src/index.tsx deleted file mode 100644 index 26ed977f..00000000 --- a/hooks/07_ColorPicker/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); diff --git a/hooks/07_ColorPicker/src/model/color.ts b/hooks/07_ColorPicker/src/model/color.ts deleted file mode 100644 index 17acfedc..00000000 --- a/hooks/07_ColorPicker/src/model/color.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Color { - red: number; - green: number; - blue: number; -} diff --git a/hooks/07_ColorPicker/src/model/color.tsx b/hooks/07_ColorPicker/src/model/color.tsx new file mode 100644 index 00000000..c1783c64 --- /dev/null +++ b/hooks/07_ColorPicker/src/model/color.tsx @@ -0,0 +1,5 @@ +export interface Color { + red: number; + green: number; + blue: number; +} \ No newline at end of file diff --git a/hooks/07_ColorPicker/webpack.config.js b/hooks/07_ColorPicker/webpack.config.js index 32eff849..c2fd5a1a 100644 --- a/hooks/07_ColorPicker/webpack.config.js +++ b/hooks/07_ColorPicker/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, - entry: ["@babel/polyfill", "./index.tsx"], + entry: ["@babel/polyfill", "./components/index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/.babelrc b/hooks/08_ColorPickerRefactor/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/08_ColorPickerRefactor/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/08_ColorPickerRefactor/package.json b/hooks/08_ColorPickerRefactor/package.json index 264e71d2..6c2b1b98 100644 --- a/hooks/08_ColorPickerRefactor/package.json +++ b/hooks/08_ColorPickerRefactor/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,27 +15,27 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } -} +} \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/app.tsx b/hooks/08_ColorPickerRefactor/src/app.tsx index b629405c..ce3c9494 100644 --- a/hooks/08_ColorPickerRefactor/src/app.tsx +++ b/hooks/08_ColorPickerRefactor/src/app.tsx @@ -1,43 +1,37 @@ import * as React from "react"; -import { HelloComponent, NameEditComponent, ColorBrowser, ColorPicker } from "./components"; +import { ColorBrowser, HelloComponent, NameEditComponent, ColorPicker } from "./components"; import { Color } from "./model/color"; +// import { HelloComponent } from "./components/hello"; +// import { NameEditComponent } from "./components/nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); - const [color, setColor] = React.useState({ - red: 20, - green: 40, - blue: 180 - }); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ red: 20, green: 40, blue: 180 }) + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - - - - - - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + + + + + + ); +}; \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/components/colorBrowser.tsx b/hooks/08_ColorPickerRefactor/src/components/colorBrowser.tsx index a28e438e..827ae714 100644 --- a/hooks/08_ColorPickerRefactor/src/components/colorBrowser.tsx +++ b/hooks/08_ColorPickerRefactor/src/components/colorBrowser.tsx @@ -1,18 +1,16 @@ import * as React from "react"; -import { Color } from "../model/color"; +import { Color } from "../model/color" interface Props { - color: Color; + color: Color; } -export const ColorBrowser: React.FC = (props) => { - const divStyle: React.CSSProperties = { - width: "11rem", - height: "7rem", - backgroundColor: `rgb(${props.color.red},${props.color.green}, ${ - props.color.blue - })` - }; +export const ColorBrowser = (props: Props) => { + const divStyle: React.CSSProperties = { + width: "11rem", + height: "7rem", + backgroundColor: `rgb(${props.color.red},${props.color.green},${props.color.blue})` + } - return
; -}; + return
; +} \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/components/colorPicker.tsx b/hooks/08_ColorPickerRefactor/src/components/colorPicker.tsx index ff4cbcdc..aaa5e541 100644 --- a/hooks/08_ColorPickerRefactor/src/components/colorPicker.tsx +++ b/hooks/08_ColorPickerRefactor/src/components/colorPicker.tsx @@ -2,55 +2,46 @@ import * as React from "react"; import { Color } from "../model/color"; interface Props { - color: Color; - onColorUpdated: (color: Color) => void; + color: Color; + onColorUpdated: (color: Color) => void; } -const updateColor = (props: Props, colorId: keyof Color) => (value: any) => { - // keyof Color ensures only 'red', 'blue' or 'green' can be passed in. - props.onColorUpdated({ - ...props.color, // this creates a clone of the current props.color object... - [colorId]: value, // ... which gets one of its properties (colorId) immediately replaced by a new value. - }); -}; +interface PropsColorSlider { + key: string; + value: number; + onValueUpdated: (newValue: number) => void; +} -export const ColorPicker: React.FC = (props) => ( -
- -
- -
- - {props.color.blue} -
-
-); +const ColorSliderComponent = (props: PropsColorSlider) => { + return ( +
+ props.onValueUpdated(+event.target.value)} + /> + {props.value} +
+ ) +} -interface PropsColorSlider { - value: number; - onValueUpdated: (newValue: number) => void; +const updateColor = (props: Props, colorId: keyof Color) => (value) => { + props.onColorUpdated({ + ...props.color, + [colorId]: value + }) } -const ColorSliderComponent: React.FC = (props: PropsColorSlider) => { - return ( -
- props.onValueUpdated(+event.target.value)} - /> - {props.value} -
- ); -}; +export const ColorPicker = (props: Props) => ( + <> + {Object.keys(props.color).map((field: keyof Color) => ( + + ))} + +); \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/components/hello.tsx b/hooks/08_ColorPickerRefactor/src/components/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/08_ColorPickerRefactor/src/components/hello.tsx +++ b/hooks/08_ColorPickerRefactor/src/components/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/08_ColorPickerRefactor/src/components/index.tsx b/hooks/08_ColorPickerRefactor/src/components/index.tsx index 7d9f725c..c9937b6f 100644 --- a/hooks/08_ColorPickerRefactor/src/components/index.tsx +++ b/hooks/08_ColorPickerRefactor/src/components/index.tsx @@ -1,4 +1,14 @@ -export * from "./hello"; -export * from "./nameEdit"; -export * from "./colorBrowser"; -export * from "./colorPicker"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from '../app'; + +ReactDOM.render( + , + document.getElementById('root') +); + + +export * from "./hello" +export * from "./nameEdit" +export * from "./colorBrowser" +export * from './colorPicker' \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/components/nameEdit.tsx b/hooks/08_ColorPickerRefactor/src/components/nameEdit.tsx index 7f9091e3..d7648086 100644 --- a/hooks/08_ColorPickerRefactor/src/components/nameEdit.tsx +++ b/hooks/08_ColorPickerRefactor/src/components/nameEdit.tsx @@ -1,29 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled: boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/src/index.tsx b/hooks/08_ColorPickerRefactor/src/index.tsx deleted file mode 100644 index 26ed977f..00000000 --- a/hooks/08_ColorPickerRefactor/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); diff --git a/hooks/08_ColorPickerRefactor/src/model/color.ts b/hooks/08_ColorPickerRefactor/src/model/color.ts deleted file mode 100644 index 17acfedc..00000000 --- a/hooks/08_ColorPickerRefactor/src/model/color.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Color { - red: number; - green: number; - blue: number; -} diff --git a/hooks/08_ColorPickerRefactor/src/model/color.tsx b/hooks/08_ColorPickerRefactor/src/model/color.tsx new file mode 100644 index 00000000..c1783c64 --- /dev/null +++ b/hooks/08_ColorPickerRefactor/src/model/color.tsx @@ -0,0 +1,5 @@ +export interface Color { + red: number; + green: number; + blue: number; +} \ No newline at end of file diff --git a/hooks/08_ColorPickerRefactor/webpack.config.js b/hooks/08_ColorPickerRefactor/webpack.config.js index 32eff849..c2fd5a1a 100644 --- a/hooks/08_ColorPickerRefactor/webpack.config.js +++ b/hooks/08_ColorPickerRefactor/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, - entry: ["@babel/polyfill", "./index.tsx"], + entry: ["@babel/polyfill", "./components/index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/09_Sidebar/.babelrc b/hooks/09_Sidebar/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/09_Sidebar/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/09_Sidebar/package.json b/hooks/09_Sidebar/package.json index 40171b2f..d4138688 100644 --- a/hooks/09_Sidebar/package.json +++ b/hooks/09_Sidebar/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,28 +15,28 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/node": "^18.15.3", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } } diff --git a/hooks/09_Sidebar/src/app.tsx b/hooks/09_Sidebar/src/app.tsx index 6eed921b..1f9e5223 100644 --- a/hooks/09_Sidebar/src/app.tsx +++ b/hooks/09_Sidebar/src/app.tsx @@ -1,69 +1,51 @@ import * as React from "react"; -import { - HelloComponent, - NameEditComponent, - ColorBrowser, - ColorPicker, - SidebarComponent -} from "./components"; +import { ColorBrowser, HelloComponent, NameEditComponent, ColorPicker, SidebarComponent } from "./components"; import { Color } from "./model/color"; +// import { HelloComponent } from "./components/hello"; +// import { NameEditComponent } from "./components/nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); - const [color, setColor] = React.useState({ - red: 20, - green: 40, - blue: 180 - }); - const [isVisible, setVisible] = React.useState(false); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ red: 20, green: 40, blue: 180 }) + const [isVisible, setVisible] = React.useState(false) + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - -

Cool Scfi movies

- -
- - - - -
- -
- - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + +

Cool Scfi movies

+ +
+ + + + +
+ +
+ + ); +}; \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/colorBrowser.tsx b/hooks/09_Sidebar/src/components/colorBrowser.tsx index 813746ce..827ae714 100644 --- a/hooks/09_Sidebar/src/components/colorBrowser.tsx +++ b/hooks/09_Sidebar/src/components/colorBrowser.tsx @@ -1,16 +1,16 @@ import * as React from "react"; -import { Color } from "../model/color"; +import { Color } from "../model/color" interface Props { - color: Color; + color: Color; } -export const ColorBrowser: React.FC = (props) => { - const divStyle: React.CSSProperties = { - width: "11rem", - height: "7rem", - backgroundColor: `rgb(${props.color.red},${props.color.green}, ${props.color.blue})`, - }; +export const ColorBrowser = (props: Props) => { + const divStyle: React.CSSProperties = { + width: "11rem", + height: "7rem", + backgroundColor: `rgb(${props.color.red},${props.color.green},${props.color.blue})` + } - return
; -}; + return
; +} \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/colorPicker.tsx b/hooks/09_Sidebar/src/components/colorPicker.tsx index 4346cd4d..aaa5e541 100644 --- a/hooks/09_Sidebar/src/components/colorPicker.tsx +++ b/hooks/09_Sidebar/src/components/colorPicker.tsx @@ -2,55 +2,46 @@ import * as React from "react"; import { Color } from "../model/color"; interface Props { - color: Color; - onColorUpdated: (color: Color) => void; + color: Color; + onColorUpdated: (color: Color) => void; } -const updateColor = (props: Props, colorId: keyof Color) => (value) => { - // keyof Color ensures only 'red', 'blue' or 'green' can be passed in. - props.onColorUpdated({ - ...props.color, // this creates a clone of the current props.color object... - [colorId]: value, // ... which gets one of its properties (colorId) immediately replaced by a new value. - }); -}; +interface PropsColorSlider { + key: string; + value: number; + onValueUpdated: (newValue: number) => void; +} -export const ColorPicker: React.FC = (props) => ( -
- -
- -
- - {props.color.blue} -
-
-); +const ColorSliderComponent = (props: PropsColorSlider) => { + return ( +
+ props.onValueUpdated(+event.target.value)} + /> + {props.value} +
+ ) +} -interface PropsColorSlider { - value: number; - onValueUpdated: (newValue: number) => void; +const updateColor = (props: Props, colorId: keyof Color) => (value) => { + props.onColorUpdated({ + ...props.color, + [colorId]: value + }) } -const ColorSliderComponent: React.FC = (props) => { - return ( -
- props.onValueUpdated(+event.target.value)} - /> - {props.value} -
- ); -}; +export const ColorPicker = (props: Props) => ( + <> + {Object.keys(props.color).map((field: keyof Color) => ( + + ))} + +); \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/hello.tsx b/hooks/09_Sidebar/src/components/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/09_Sidebar/src/components/hello.tsx +++ b/hooks/09_Sidebar/src/components/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/09_Sidebar/src/components/index.tsx b/hooks/09_Sidebar/src/components/index.tsx index 67742591..045006fc 100644 --- a/hooks/09_Sidebar/src/components/index.tsx +++ b/hooks/09_Sidebar/src/components/index.tsx @@ -1,5 +1,15 @@ -export * from "./hello"; -export * from "./nameEdit"; -export * from "./colorBrowser"; -export * from "./colorPicker"; -export * from "./sidebar"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from '../app'; + +ReactDOM.render( + , + document.getElementById('root') +); + + +export * from "./hello" +export * from "./nameEdit" +export * from "./colorBrowser" +export * from './colorPicker' +export * from './sidebar' \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/nameEdit.tsx b/hooks/09_Sidebar/src/components/nameEdit.tsx index 7f9091e3..d7648086 100644 --- a/hooks/09_Sidebar/src/components/nameEdit.tsx +++ b/hooks/09_Sidebar/src/components/nameEdit.tsx @@ -1,29 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled: boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/sidebar.css b/hooks/09_Sidebar/src/components/sidebar.css index 907d868f..2a472518 100644 --- a/hooks/09_Sidebar/src/components/sidebar.css +++ b/hooks/09_Sidebar/src/components/sidebar.css @@ -1,38 +1,47 @@ /* The side navigation menu */ .sidenav { - height: 100%; /* 100% Full-height */ - width: 0; /* 0 width - change this with JavaScript */ - position: fixed; /* Stay in place */ - z-index: 1; /* Stay on top */ - top: 0; - left: 0; - background-color: #808080; /* Gray*/ - overflow-x: hidden; /* Disable horizontal scroll */ - padding-top: 60px; /* Place content 60px from the top */ - transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */ + height: 100%; + /* 100% Full-height */ + width: 0; + /* 0 width - change this with JavaScript */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Stay on top */ + top: 0; + left: 0; + background-color: #808080; + /* Gray*/ + overflow-x: hidden; + /* Disable horizontal scroll */ + padding-top: 60px; + /* Place content 60px from the top */ + transition: 0.5s; + /* 0.5 second transition effect to slide in the sidenav */ } /* Position and style the close button (top right corner) */ .sidenav .closebtn { - position: absolute; - top: 0; - right: 25px; - font-size: 36px; - margin-left: 50px; + position: absolute; + top: 0; + right: 25px; + font-size: 36px; + margin-left: 50px; } /* Style page content - use this if you want to push the page content to the right when you open the side navigation */ #main { - transition: margin-left 0.5s; - padding: 20px; + transition: margin-left 0.5s; + padding: 20px; } /* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */ @media screen and (max-height: 450px) { - .sidenav { - padding-top: 15px; - } - .sidenav a { - font-size: 18px; - } -} + .sidenav { + padding-top: 15px; + } + + .sidenav a { + font-size: 18px; + } +} \ No newline at end of file diff --git a/hooks/09_Sidebar/src/components/sidebar.tsx b/hooks/09_Sidebar/src/components/sidebar.tsx index 0847a552..ebeb7e55 100644 --- a/hooks/09_Sidebar/src/components/sidebar.tsx +++ b/hooks/09_Sidebar/src/components/sidebar.tsx @@ -3,15 +3,16 @@ import * as React from "react"; const classNames = require("./sidebar.css"); interface Props { - isVisible: boolean; + isVisible: boolean; + children: React.ReactNode } const divStyle = (props: Props): React.CSSProperties => ({ - width: props.isVisible ? "23rem" : "0rem", -}); + width: (props.isVisible) ? '23rem' : '0rem' +}) -export const SidebarComponent: React.StatelessComponent = (props) => ( -
- {props.children} -
-); +export const SidebarComponent: React.FC = (props) => ( +
+ {props.children} +
+); \ No newline at end of file diff --git a/hooks/09_Sidebar/src/index.html b/hooks/09_Sidebar/src/index.html index c57efeff..ff56f8d6 100644 --- a/hooks/09_Sidebar/src/index.html +++ b/hooks/09_Sidebar/src/index.html @@ -1,13 +1,16 @@ - - - - - -
-

Sample app

-
-
- - + + + + + + + +
+

Sample app

+
+
+ + + \ No newline at end of file diff --git a/hooks/09_Sidebar/src/index.tsx b/hooks/09_Sidebar/src/index.tsx deleted file mode 100644 index 26ed977f..00000000 --- a/hooks/09_Sidebar/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); diff --git a/hooks/09_Sidebar/src/model/color.ts b/hooks/09_Sidebar/src/model/color.ts deleted file mode 100644 index 17acfedc..00000000 --- a/hooks/09_Sidebar/src/model/color.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Color { - red: number; - green: number; - blue: number; -} diff --git a/hooks/09_Sidebar/src/model/color.tsx b/hooks/09_Sidebar/src/model/color.tsx new file mode 100644 index 00000000..c1783c64 --- /dev/null +++ b/hooks/09_Sidebar/src/model/color.tsx @@ -0,0 +1,5 @@ +export interface Color { + red: number; + green: number; + blue: number; +} \ No newline at end of file diff --git a/hooks/09_Sidebar/webpack.config.js b/hooks/09_Sidebar/webpack.config.js index c9996585..9860631f 100644 --- a/hooks/09_Sidebar/webpack.config.js +++ b/hooks/09_Sidebar/webpack.config.js @@ -1,80 +1,78 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx", ".css"], + extensions: [".js", ".ts", ".tsx", ".css"] }, - entry: ["@babel/polyfill", "./index.tsx"], + entry: ["@babel/polyfill", "./components/index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, include: /node_modules/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, + // Use CSS modules for custom stylesheets { test: /\.css$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, { - loader: "css-loader", + loader: 'css-loader', options: { + modules: true, modules: { localIdentName: "[name]__[local]___[hash:base64:5]", }, - localsConvention: "camelCase", }, - }, - ], + } + ] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/10_TableMock/.babelrc b/hooks/10_TableMock/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/10_TableMock/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/10_TableMock/Readme_es.md b/hooks/10_TableMock/Readme_es.md new file mode 100644 index 00000000..109add7b --- /dev/null +++ b/hooks/10_TableMock/Readme_es.md @@ -0,0 +1,342 @@ +# 09 Sidebar + +En este ejemplo vamos a añadir una barra lateral a nuestra aplicación, empezaremos con una implementación específica, y luego la haremos genérica. + +# Pasos a seguir + +- Tomaremos como punto de partida el ejemplo _08 ColorPickerRefactor_, copiamos el contenido de ese archivo y ejecutamos _npm install_. + +```bash +npm install +``` + +- Cree un archivo llamado _src/components/sidebar.css_ y añada los siguientes estilos (http://www.w3schools.com/howto/howto_js_sidenav.asp): + +_./src/components/sidebar.css_ + +```css +/* The side navigation menu */ +.sidenav { + height: 100%; /* 100% Full-height */ + width: 0; /* 0 width - change this with JavaScript */ + position: fixed; /* Stay in place */ + z-index: 1; /* Stay on top */ + top: 0; + left: 0; + background-color: #808080; /* Gray*/ + overflow-x: hidden; /* Disable horizontal scroll */ + padding-top: 60px; /* Place content 60px from the top */ + transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */ +} + +/* Position and style the close button (top right corner) */ +.sidenav .closebtn { + position: absolute; + top: 0; + right: 25px; + font-size: 36px; + margin-left: 50px; +} + +/* Style page content - use this if you want to push the page content to the right when you open the side navigation */ +#main { + transition: margin-left 0.5s; + padding: 20px; +} + +/* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */ +@media screen and (max-height: 450px) { + .sidenav { + padding-top: 15px; + } + .sidenav a { + font-size: 18px; + } +} +``` + +- Vamos a usar módulos CSS, así que vamos a configurarlo. + +_./webpack.config.js_ + +```diff + module.exports = { + context: path.join(basePath, "src"), + resolve: { +- extensions: ['.js', '.ts', '.tsx'] ++ extensions: ['.js', '.ts', '.tsx', '.css'] + }, +``` + +- Sólo usaremos módulos CSS para hojas de estilo personalizadas. No usaremos Módulos CSS para otros archivos CSS, como Bootstrap (carpeta node_modules). + +_./webpack.config.js_ + +```diff + { + test: /\.css$/, ++ include: /node_modules/, + use: [MiniCssExtractPlugin.loader, "css-loader"] + }, ++ // Use CSS modules for custom stylesheets ++ { ++ test: /\.css$/, ++ exclude: /node_modules/, ++ use: [ ++ MiniCssExtractPlugin.loader, ++ { ++ loader: 'css-loader', ++ options: { ++ modules: true, ++ localIdentName: '[name]__[local]___[hash:base64:5]', ++ camelCase: true, ++ }, ++ }, ++ ] ++ }, ++ // Do not use CSS modules in node_modules folder + +``` + +- Vamos a crear el componente de la barra lateral, _src/components/sidebar.tsx_. Crearemos sólo + un rectángulo e interactuaremos con la animación. + +Necesitamos instalar los tipos para _node_, ya que usaremos _require_ a la hora de importar desde el _css_. + +```bash +npm install @types/node --save-dev +``` + +_./src/components/sidebar.tsx_ + +```jsx +import * as React from "react"; + +const classNames = require("./sidebar.css"); + +export const SidebarComponent = () => ( +
+ Basic side bar, first steps +
+); +``` + +- Añadimos este componente a nuestro barrel _index_ + +_./src/components/index.ts_ + +```diff +export * from "./hello"; +export * from "./nameEdit"; +export * from "./colorBrowser"; +export * from "./colorPicker"; ++ export * from "./sidebar"; +``` + +- Vamos a añadir un _id_ al elemento _body_ de la página _src/index.html_ + +_./src/index.html_ + +```diff +- ++ +``` + +- Colocamos el componente añadiéndolo en `app.tsx`: + +_./src/app.tsx_ + +```diff +import * as React from "react"; +- import { HelloComponent, NameEditComponent, ColorBrowser, ColorPicker } from "./components"; ++ import { HelloComponent, NameEditComponent, ColorBrowser, ColorPicker, SidebarComponent } from "./components"; +import { Color } from "./model/color"; +``` + +_./src/app.tsx_ + +```diff + return ( + <> ++ + +``` + +- Comencemos con la parte interesante de esta implementación, agreguemos una opción para mostrar/ocultar la barra lateral _sidebar.tsx_. + +_./src/components/sidebar.tsx_ + +```diff +import * as React from 'react'; + +const classNames = require('./sidebar.css'); + ++ interface Props { ++ isVisible: boolean; ++ } + +- export const SidebarComponent = () => ++ export const SidebarComponent = (props: Props) => +
+ Basic sidebar, first steps +
+``` + +- Ahora vamos a añadir algo de lógica para mostrar / ocultar la barra lateral en caso de que se actualice dicha opción. + + +_./src/sidebar.tsx_ + +```diff +import * as React from 'react'; + +const classNames = require('./sidebar.css'); + +interface Props { + isVisible: boolean; +}; + ++ const divStyle = (props: Props): React.CSSProperties => ({ ++ width: (props.isVisible) ? '23rem' : '0rem' ++ }); + +export const SidebarComponent = (props: Props) => +-
++
+ Basic sidebar, first steps +
+``` + +- Hagamos una prueba rápida para mostrar siempre la barra lateral: + +_./src/app.tsx_ + +```diff + return ( + <> +- ++ + +``` + +- Si arrancamos el proyecto veremos la barra lateral que hemos creado (un rectángulo gris). + + +```bash +npm start +``` +_¿Qué pasa si no puedo ver la barra lateral?_ Compruebe que _webpack.config.js_ y sus estilos se han aplicado, es posible que tenga que iniciar de nuevo _webpack-dev-sever_ (relanzar _npm start_), compruebe con dev tools que está cargando los estilos CSS. + +- Ahora a nivel de aplicación podemos recordar la opción de visibilidad, y añadir un botón para alternar la visualización de la barra lateral. + + +_./src/app.tsx_ + +```diff +export const App = () => { + const [name, setName] = React.useState("defaultUserName"); + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ + red: 20, + green: 40, + blue: 180 + }); ++ const[isVisible, setVisible] = React.useState(false); +``` + +_./src/app.tsx_ + +```diff + return ( + <> +- ++ + + + + ++
++ ++
+ +``` + +- Iniciemos la aplicación para comprobar cómo se comporta: + +```bash +npm start +``` + +> Ejercicio: la llamada en línea a la función dentro de _onClick_ no se +> considera una buena práctica (en cada render se recreará la función), +> vamos a refactorizarla en dos pasos: + +- Primero extraeremos esta lógica a una función, la llamaremos _toggleSidebarVisibility_. + +- Ahora envolvemos _visibility_ y _toggleSidebarVisibility_ en un _hook_ personalizado. + +* Hasta ahora todo va bien, pero ¿qué pasa si queremos que esta barra lateral sea un componente reutilizable? Podríamos simplemente mostrar el marco pero el contenido debe ser dinámico. + +* Comencemos por añadir algo de contenido al instanciar la barra lateral (_app.tsx_). + + +_./src/app.tsx_ + +```diff + <> +- ++ ++

Cool Scfi movies

++ ++
+ +``` + +> Tenemos un error, _children_ no está definido, vamos a arreglarlo en el +> siguiente paso.... + +- Ahora en _sidebar.tsx_ volcaremos este contenido usando {this.props.children} + +_./src/components/sidebar.tsx_ + +```diff +- export const SidebarComponent = (props: Props) => ( ++ export const SidebarComponent: React.StatelessComponent = (props) => ( + +
+- Basic side bar, first steps ++ {props.children} +
+); +``` + +- Probemos el ejemplo + +``` +npm start +``` + +# About Basefactor + Lemoncode + +We are an innovating team of Javascript experts, passionate about turning your ideas into robust products. + +[Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services. + +[Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services. + +For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend diff --git a/hooks/10_TableMock/package.json b/hooks/10_TableMock/package.json index 40171b2f..d4138688 100644 --- a/hooks/10_TableMock/package.json +++ b/hooks/10_TableMock/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,28 +15,28 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/node": "^18.15.3", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1" + "react": "^18.2.0", + "react-dom": "^18.2.0" } } diff --git a/hooks/10_TableMock/src/api/memberApi.ts b/hooks/10_TableMock/src/api/memberApi.ts deleted file mode 100644 index b0ad6e11..00000000 --- a/hooks/10_TableMock/src/api/memberApi.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MemberEntity } from "../model/member"; - -export const getMembersCollection = (): Promise => { - const promise = new Promise((resolve, reject) => { - setTimeout( - () => - resolve([ - { - id: 1457912, - login: "brauliodiez", - avatar_url: "https://avatars.githubusercontent.com/u/1457912?v=3" - }, - { - id: 4374977, - login: "Nasdan", - avatar_url: "https://avatars.githubusercontent.com/u/4374977?v=3" - } - ]), - 500 - ); - }); - - return promise; -}; diff --git a/hooks/10_TableMock/src/api/memberApi.tsx b/hooks/10_TableMock/src/api/memberApi.tsx new file mode 100644 index 00000000..ba18de2c --- /dev/null +++ b/hooks/10_TableMock/src/api/memberApi.tsx @@ -0,0 +1,24 @@ +import { MemberEntity } from "../model/member"; + +export const getMembersCollection = (): Promise => { + const promise = new Promise((resolve, reject) => { + setTimeout( + () => + resolve([ + { + id: 1457912, + login: "brauliodiez", + avatar_url: "https://avatars.githubusercontent.com/u/1457912?v=3" + }, + { + id: 4374977, + login: "Nasdan", + avatar_url: "https://avatars.githubusercontent.com/u/4374977?v=3" + } + ]), + 500 + ); + }); + + return promise; +}; \ No newline at end of file diff --git a/hooks/10_TableMock/src/app.tsx b/hooks/10_TableMock/src/app.tsx index d6623e0b..eea14150 100644 --- a/hooks/10_TableMock/src/app.tsx +++ b/hooks/10_TableMock/src/app.tsx @@ -1,71 +1,52 @@ import * as React from "react"; -import { - HelloComponent, - NameEditComponent, - ColorBrowser, - ColorPicker, - SidebarComponent, - MemberTableComponent -} from "./components"; +import { ColorBrowser, HelloComponent, NameEditComponent, ColorPicker, SidebarComponent, MemberTableComponent } from "./components"; import { Color } from "./model/color"; +// import { HelloComponent } from "./components/hello"; +// import { NameEditComponent } from "./components/nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); - const [color, setColor] = React.useState({ - red: 20, - green: 40, - blue: 180 - }); - const [isVisible, setVisible] = React.useState(false); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ red: 20, green: 40, blue: 180 }) + const [isVisible, setVisible] = React.useState(false) + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - -

Cool Scfi movies

- -
- - - - - -
- -
- - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + +

Cool Scfi movies

+ +
+ + + + + +
+ +
+ + ); +}; \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/colorBrowser.tsx b/hooks/10_TableMock/src/components/colorBrowser.tsx index 813746ce..827ae714 100644 --- a/hooks/10_TableMock/src/components/colorBrowser.tsx +++ b/hooks/10_TableMock/src/components/colorBrowser.tsx @@ -1,16 +1,16 @@ import * as React from "react"; -import { Color } from "../model/color"; +import { Color } from "../model/color" interface Props { - color: Color; + color: Color; } -export const ColorBrowser: React.FC = (props) => { - const divStyle: React.CSSProperties = { - width: "11rem", - height: "7rem", - backgroundColor: `rgb(${props.color.red},${props.color.green}, ${props.color.blue})`, - }; +export const ColorBrowser = (props: Props) => { + const divStyle: React.CSSProperties = { + width: "11rem", + height: "7rem", + backgroundColor: `rgb(${props.color.red},${props.color.green},${props.color.blue})` + } - return
; -}; + return
; +} \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/colorPicker.tsx b/hooks/10_TableMock/src/components/colorPicker.tsx index 4346cd4d..aaa5e541 100644 --- a/hooks/10_TableMock/src/components/colorPicker.tsx +++ b/hooks/10_TableMock/src/components/colorPicker.tsx @@ -2,55 +2,46 @@ import * as React from "react"; import { Color } from "../model/color"; interface Props { - color: Color; - onColorUpdated: (color: Color) => void; + color: Color; + onColorUpdated: (color: Color) => void; } -const updateColor = (props: Props, colorId: keyof Color) => (value) => { - // keyof Color ensures only 'red', 'blue' or 'green' can be passed in. - props.onColorUpdated({ - ...props.color, // this creates a clone of the current props.color object... - [colorId]: value, // ... which gets one of its properties (colorId) immediately replaced by a new value. - }); -}; +interface PropsColorSlider { + key: string; + value: number; + onValueUpdated: (newValue: number) => void; +} -export const ColorPicker: React.FC = (props) => ( -
- -
- -
- - {props.color.blue} -
-
-); +const ColorSliderComponent = (props: PropsColorSlider) => { + return ( +
+ props.onValueUpdated(+event.target.value)} + /> + {props.value} +
+ ) +} -interface PropsColorSlider { - value: number; - onValueUpdated: (newValue: number) => void; +const updateColor = (props: Props, colorId: keyof Color) => (value) => { + props.onColorUpdated({ + ...props.color, + [colorId]: value + }) } -const ColorSliderComponent: React.FC = (props) => { - return ( -
- props.onValueUpdated(+event.target.value)} - /> - {props.value} -
- ); -}; +export const ColorPicker = (props: Props) => ( + <> + {Object.keys(props.color).map((field: keyof Color) => ( + + ))} + +); \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/hello.tsx b/hooks/10_TableMock/src/components/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/10_TableMock/src/components/hello.tsx +++ b/hooks/10_TableMock/src/components/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/10_TableMock/src/components/index.tsx b/hooks/10_TableMock/src/components/index.tsx index 7b909f0e..33158d79 100644 --- a/hooks/10_TableMock/src/components/index.tsx +++ b/hooks/10_TableMock/src/components/index.tsx @@ -1,6 +1,16 @@ -export * from "./hello"; -export * from "./nameEdit"; -export * from "./colorBrowser"; -export * from "./colorPicker"; -export * from "./sidebar"; -export * from "./memberTable"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from '../app'; + +ReactDOM.render( + , + document.getElementById('root') +); + + +export * from "./hello" +export * from "./nameEdit" +export * from "./colorBrowser" +export * from './colorPicker' +export * from './sidebar' +export * from './memberTable' \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/memberTable.tsx b/hooks/10_TableMock/src/components/memberTable.tsx index eee44798..f9cda89e 100644 --- a/hooks/10_TableMock/src/components/memberTable.tsx +++ b/hooks/10_TableMock/src/components/memberTable.tsx @@ -1,58 +1,51 @@ -import * as React from "react"; import { MemberEntity } from "../model/member"; import { getMembersCollection } from "../api/memberApi"; +import * as React from "react"; const useMemberCollection = () => { - const [memberCollection, setMemberCollection] = React.useState< - MemberEntity[] - >([]); + const [memberCollection, setMemberCollection] = React.useState([]) + + const loadMemberCollection = () => { + getMembersCollection().then(memberCollection => + setMemberCollection(memberCollection) + ); + }; - const loadMemberCollection = () => { - getMembersCollection().then(memberCollection => - setMemberCollection(memberCollection) - ); - }; + return { memberCollection, loadMemberCollection } +} - return { memberCollection, loadMemberCollection }; -}; +const MemberRow = ({ member }: { member: MemberEntity }) => + + + {member.id} + {member.login} + export const MemberTableComponent = () => { - const { memberCollection, loadMemberCollection } = useMemberCollection(); - - React.useEffect(() => { - loadMemberCollection(); - }, []); - - return ( - <> - - - - - - - - - - {memberCollection.map(member => ( - - ))} - -
AvatarIdName
- - ); -}; - -const MemberRow = ({ member }: { member: MemberEntity }) => ( - - - - - - {member.id} - - - {member.login} - - -); + const { memberCollection, loadMemberCollection } = useMemberCollection(); + + React.useEffect(() => { + console.log(memberCollection) + loadMemberCollection() + }, []) + + return ( + <> + + + + + + + + + + {memberCollection.map(member => ( + + ))} + +
AvatarIdname
+ + + ) +} \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/nameEdit.tsx b/hooks/10_TableMock/src/components/nameEdit.tsx index 7f9091e3..d7648086 100644 --- a/hooks/10_TableMock/src/components/nameEdit.tsx +++ b/hooks/10_TableMock/src/components/nameEdit.tsx @@ -1,29 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled: boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/sidebar.css b/hooks/10_TableMock/src/components/sidebar.css index 907d868f..2a472518 100644 --- a/hooks/10_TableMock/src/components/sidebar.css +++ b/hooks/10_TableMock/src/components/sidebar.css @@ -1,38 +1,47 @@ /* The side navigation menu */ .sidenav { - height: 100%; /* 100% Full-height */ - width: 0; /* 0 width - change this with JavaScript */ - position: fixed; /* Stay in place */ - z-index: 1; /* Stay on top */ - top: 0; - left: 0; - background-color: #808080; /* Gray*/ - overflow-x: hidden; /* Disable horizontal scroll */ - padding-top: 60px; /* Place content 60px from the top */ - transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */ + height: 100%; + /* 100% Full-height */ + width: 0; + /* 0 width - change this with JavaScript */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Stay on top */ + top: 0; + left: 0; + background-color: #808080; + /* Gray*/ + overflow-x: hidden; + /* Disable horizontal scroll */ + padding-top: 60px; + /* Place content 60px from the top */ + transition: 0.5s; + /* 0.5 second transition effect to slide in the sidenav */ } /* Position and style the close button (top right corner) */ .sidenav .closebtn { - position: absolute; - top: 0; - right: 25px; - font-size: 36px; - margin-left: 50px; + position: absolute; + top: 0; + right: 25px; + font-size: 36px; + margin-left: 50px; } /* Style page content - use this if you want to push the page content to the right when you open the side navigation */ #main { - transition: margin-left 0.5s; - padding: 20px; + transition: margin-left 0.5s; + padding: 20px; } /* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */ @media screen and (max-height: 450px) { - .sidenav { - padding-top: 15px; - } - .sidenav a { - font-size: 18px; - } -} + .sidenav { + padding-top: 15px; + } + + .sidenav a { + font-size: 18px; + } +} \ No newline at end of file diff --git a/hooks/10_TableMock/src/components/sidebar.tsx b/hooks/10_TableMock/src/components/sidebar.tsx index 762991eb..19af0eee 100644 --- a/hooks/10_TableMock/src/components/sidebar.tsx +++ b/hooks/10_TableMock/src/components/sidebar.tsx @@ -3,17 +3,16 @@ import * as React from "react"; const classNames = require("./sidebar.css"); interface Props { - isVisible: boolean; + isVisible: boolean; + children: React.ReactNode; } const divStyle = (props: Props): React.CSSProperties => ({ - width: props.isVisible ? "23rem" : "0rem" -}); - -export const SidebarComponent: React.StatelessComponent = props => ( -
- {props.children} -
-); - + width: (props.isVisible) ? '23rem' : '0rem' +}) +export const SidebarComponent: React.FC = (props) => ( +
+ {props.children} +
+); \ No newline at end of file diff --git a/hooks/10_TableMock/src/index.html b/hooks/10_TableMock/src/index.html index c57efeff..ff56f8d6 100644 --- a/hooks/10_TableMock/src/index.html +++ b/hooks/10_TableMock/src/index.html @@ -1,13 +1,16 @@ - - - - - -
-

Sample app

-
-
- - + + + + + + + +
+

Sample app

+
+
+ + + \ No newline at end of file diff --git a/hooks/10_TableMock/src/index.tsx b/hooks/10_TableMock/src/index.tsx deleted file mode 100644 index 26ed977f..00000000 --- a/hooks/10_TableMock/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); diff --git a/hooks/10_TableMock/src/model/color.ts b/hooks/10_TableMock/src/model/color.ts deleted file mode 100644 index 17acfedc..00000000 --- a/hooks/10_TableMock/src/model/color.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Color { - red: number; - green: number; - blue: number; -} diff --git a/hooks/10_TableMock/src/model/color.tsx b/hooks/10_TableMock/src/model/color.tsx new file mode 100644 index 00000000..c1783c64 --- /dev/null +++ b/hooks/10_TableMock/src/model/color.tsx @@ -0,0 +1,5 @@ +export interface Color { + red: number; + green: number; + blue: number; +} \ No newline at end of file diff --git a/hooks/10_TableMock/src/model/member.ts b/hooks/10_TableMock/src/model/member.tsx similarity index 100% rename from hooks/10_TableMock/src/model/member.ts rename to hooks/10_TableMock/src/model/member.tsx diff --git a/hooks/10_TableMock/webpack.config.js b/hooks/10_TableMock/webpack.config.js index c9996585..9860631f 100644 --- a/hooks/10_TableMock/webpack.config.js +++ b/hooks/10_TableMock/webpack.config.js @@ -1,80 +1,78 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx", ".css"], + extensions: [".js", ".ts", ".tsx", ".css"] }, - entry: ["@babel/polyfill", "./index.tsx"], + entry: ["@babel/polyfill", "./components/index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, include: /node_modules/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, + // Use CSS modules for custom stylesheets { test: /\.css$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, { - loader: "css-loader", + loader: 'css-loader', options: { + modules: true, modules: { localIdentName: "[name]__[local]___[hash:base64:5]", }, - localsConvention: "camelCase", }, - }, - ], + } + ] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/11_TableAxios/.babelrc b/hooks/11_TableAxios/.babelrc deleted file mode 100644 index 06770f7d..00000000 --- a/hooks/11_TableAxios/.babelrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ], - "@babel/preset-typescript", - "@babel/preset-react" - ], - "plugins": ["@babel/plugin-transform-runtime"] -} diff --git a/hooks/11_TableAxios/package.json b/hooks/11_TableAxios/package.json index 0d0d92b0..5f282d0b 100644 --- a/hooks/11_TableAxios/package.json +++ b/hooks/11_TableAxios/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,33 +15,29 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/plugin-transform-runtime": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/node": "^18.15.3", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "@babel/runtime": "^7.10.5", - "axios": "^0.19.2", - "react": "^16.13.1", - "react-dom": "^16.13.1" + "axios": "^1.3.4", + "react": "^18.2.0", + "react-dom": "^18.2.0" } } diff --git a/hooks/11_TableAxios/src/api/memberApi.ts b/hooks/11_TableAxios/src/api/memberApi.ts deleted file mode 100644 index 68ca97cf..00000000 --- a/hooks/11_TableAxios/src/api/memberApi.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MemberEntity } from "../model/member"; -import Axios, { AxiosResponse } from "axios"; - -const gitHubURL = "https://api.github.com"; -const gitHubMembersUrl = `${gitHubURL}/orgs/lemoncode/members`; - -export const getMembersCollection = (): Promise => { - const promise = new Promise((resolve, reject) => { - try { - Axios.get(gitHubMembersUrl).then(response => - resolve(mapMemberListApiToModel(response)) - ); - } catch (ex) { - reject(ex); - } - }); - - return promise; -}; - -const mapMemberListApiToModel = ({ - data -}: AxiosResponse): MemberEntity[] => - data.map(gitHubMember => ({ - id: gitHubMember.id, - login: gitHubMember.login, - avatar_url: gitHubMember.avatar_url - })); diff --git a/hooks/11_TableAxios/src/api/memberApi.tsx b/hooks/11_TableAxios/src/api/memberApi.tsx new file mode 100644 index 00000000..e772f604 --- /dev/null +++ b/hooks/11_TableAxios/src/api/memberApi.tsx @@ -0,0 +1,25 @@ +import { MemberEntity } from "../model/member"; +import Axios, { AxiosResponse } from 'axios'; + +const gitHubURL = 'https://api.github.com'; +const gitHubMembersUrl = `${gitHubURL}/orgs/lemoncode/members`; + +export const getMembersCollection = (): Promise => { + const promise = new Promise((resolve, reject) => { + try { + Axios.get(gitHubMembersUrl) + .then(response => resolve(mapMemberListApiToModel(response))); + } catch (ex) { + reject(ex) + + } + }) + return promise; +}; + +const mapMemberListApiToModel = ({ data }: AxiosResponse): MemberEntity[] => + data.map(gitHubMember => ({ + id: gitHubMember.id, + login: gitHubMember.login, + avatar_url: gitHubMember.avatar_url + })) \ No newline at end of file diff --git a/hooks/11_TableAxios/src/app.tsx b/hooks/11_TableAxios/src/app.tsx index d6623e0b..eea14150 100644 --- a/hooks/11_TableAxios/src/app.tsx +++ b/hooks/11_TableAxios/src/app.tsx @@ -1,71 +1,52 @@ import * as React from "react"; -import { - HelloComponent, - NameEditComponent, - ColorBrowser, - ColorPicker, - SidebarComponent, - MemberTableComponent -} from "./components"; +import { ColorBrowser, HelloComponent, NameEditComponent, ColorPicker, SidebarComponent, MemberTableComponent } from "./components"; import { Color } from "./model/color"; +// import { HelloComponent } from "./components/hello"; +// import { NameEditComponent } from "./components/nameEdit"; export const App = () => { - const [name, setName] = React.useState("defaultUserName"); - const [editingName, setEditingName] = React.useState("defaultUserName"); - const [color, setColor] = React.useState({ - red: 20, - green: 40, - blue: 180 - }); - const [isVisible, setVisible] = React.useState(false); + const [name, setName] = React.useState('defaultUserName') + const [editingName, setEditingName] = React.useState("defaultUserName"); + const [color, setColor] = React.useState({ red: 20, green: 40, blue: 180 }) + const [isVisible, setVisible] = React.useState(false) + const setUsernameState = () => { + setName(editingName) + } - const loadUsername = () => { - setTimeout(() => { - setName("name from async call"); - setEditingName("name from async call"); - }, 500); - }; + const loadUsername = () => { + setTimeout(() => { + setName("name from async call"); + setEditingName("name from async call"); + }, 500); + }; - React.useEffect(() => { - loadUsername(); - }, []); - - const setUsernameState = () => { - setName(editingName); - }; - - return ( - <> - -

Cool Scfi movies

- -
- - - - - -
- -
- - ); -}; + React.useEffect(() => { + loadUsername() + }, []); + return ( + <> + +

Cool Scfi movies

+ +
+ + + + + +
+ +
+ + ); +}; \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/colorBrowser.tsx b/hooks/11_TableAxios/src/components/colorBrowser.tsx index 813746ce..827ae714 100644 --- a/hooks/11_TableAxios/src/components/colorBrowser.tsx +++ b/hooks/11_TableAxios/src/components/colorBrowser.tsx @@ -1,16 +1,16 @@ import * as React from "react"; -import { Color } from "../model/color"; +import { Color } from "../model/color" interface Props { - color: Color; + color: Color; } -export const ColorBrowser: React.FC = (props) => { - const divStyle: React.CSSProperties = { - width: "11rem", - height: "7rem", - backgroundColor: `rgb(${props.color.red},${props.color.green}, ${props.color.blue})`, - }; +export const ColorBrowser = (props: Props) => { + const divStyle: React.CSSProperties = { + width: "11rem", + height: "7rem", + backgroundColor: `rgb(${props.color.red},${props.color.green},${props.color.blue})` + } - return
; -}; + return
; +} \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/colorPicker.tsx b/hooks/11_TableAxios/src/components/colorPicker.tsx index 4346cd4d..aaa5e541 100644 --- a/hooks/11_TableAxios/src/components/colorPicker.tsx +++ b/hooks/11_TableAxios/src/components/colorPicker.tsx @@ -2,55 +2,46 @@ import * as React from "react"; import { Color } from "../model/color"; interface Props { - color: Color; - onColorUpdated: (color: Color) => void; + color: Color; + onColorUpdated: (color: Color) => void; } -const updateColor = (props: Props, colorId: keyof Color) => (value) => { - // keyof Color ensures only 'red', 'blue' or 'green' can be passed in. - props.onColorUpdated({ - ...props.color, // this creates a clone of the current props.color object... - [colorId]: value, // ... which gets one of its properties (colorId) immediately replaced by a new value. - }); -}; +interface PropsColorSlider { + key: string; + value: number; + onValueUpdated: (newValue: number) => void; +} -export const ColorPicker: React.FC = (props) => ( -
- -
- -
- - {props.color.blue} -
-
-); +const ColorSliderComponent = (props: PropsColorSlider) => { + return ( +
+ props.onValueUpdated(+event.target.value)} + /> + {props.value} +
+ ) +} -interface PropsColorSlider { - value: number; - onValueUpdated: (newValue: number) => void; +const updateColor = (props: Props, colorId: keyof Color) => (value) => { + props.onColorUpdated({ + ...props.color, + [colorId]: value + }) } -const ColorSliderComponent: React.FC = (props) => { - return ( -
- props.onValueUpdated(+event.target.value)} - /> - {props.value} -
- ); -}; +export const ColorPicker = (props: Props) => ( + <> + {Object.keys(props.color).map((field: keyof Color) => ( + + ))} + +); \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/hello.tsx b/hooks/11_TableAxios/src/components/hello.tsx index b6b7aca4..b9b1d810 100644 --- a/hooks/11_TableAxios/src/components/hello.tsx +++ b/hooks/11_TableAxios/src/components/hello.tsx @@ -4,6 +4,6 @@ interface Props { userName: string; } -export const HelloComponent: React.FC = (props) => { - return

Hello user: {props.userName} !

; -}; +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/11_TableAxios/src/components/index.tsx b/hooks/11_TableAxios/src/components/index.tsx index 7b909f0e..33158d79 100644 --- a/hooks/11_TableAxios/src/components/index.tsx +++ b/hooks/11_TableAxios/src/components/index.tsx @@ -1,6 +1,16 @@ -export * from "./hello"; -export * from "./nameEdit"; -export * from "./colorBrowser"; -export * from "./colorPicker"; -export * from "./sidebar"; -export * from "./memberTable"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from '../app'; + +ReactDOM.render( + , + document.getElementById('root') +); + + +export * from "./hello" +export * from "./nameEdit" +export * from "./colorBrowser" +export * from './colorPicker' +export * from './sidebar' +export * from './memberTable' \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/memberTable.tsx b/hooks/11_TableAxios/src/components/memberTable.tsx index 4ae64fa6..f6862b47 100644 --- a/hooks/11_TableAxios/src/components/memberTable.tsx +++ b/hooks/11_TableAxios/src/components/memberTable.tsx @@ -1,57 +1,50 @@ -import * as React from "react"; import { MemberEntity } from "../model/member"; import { getMembersCollection } from "../api/memberApi"; +import * as React from "react"; const useMemberCollection = () => { - const [memberCollection, setMemberCollection] = React.useState< - MemberEntity[] - >([]); + const [memberCollection, setMemberCollection] = React.useState([]) + + const loadMemberCollection = async () => { + const memberCollection = await getMembersCollection(); + setMemberCollection(memberCollection); + }; - const loadMemberCollection = async () => { - const memberCollection = await getMembersCollection(); - setMemberCollection(memberCollection); - }; + return { memberCollection, loadMemberCollection } +} - return { memberCollection, loadMemberCollection }; -}; +const MemberRow = ({ member }: { member: MemberEntity }) => + + + {member.id} + {member.login} + export const MemberTableComponent = () => { - const { memberCollection, loadMemberCollection } = useMemberCollection(); - - React.useEffect(() => { - loadMemberCollection(); - }, []); - - return ( - <> - - - - - - - - - - {memberCollection.map((member) => ( - - ))} - -
AvatarIdName
- - ); -}; - -const MemberRow = ({ member }: { member: MemberEntity }) => ( - - - - - - {member.id} - - - {member.login} - - -); + const { memberCollection, loadMemberCollection } = useMemberCollection(); + + React.useEffect(() => { + console.log(memberCollection) + loadMemberCollection() + }, []) + + return ( + <> + + + + + + + + + + {memberCollection.map(member => ( + + ))} + +
AvatarIdname
+ + + ) +} \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/nameEdit.tsx b/hooks/11_TableAxios/src/components/nameEdit.tsx index 7f9091e3..d7648086 100644 --- a/hooks/11_TableAxios/src/components/nameEdit.tsx +++ b/hooks/11_TableAxios/src/components/nameEdit.tsx @@ -1,29 +1,36 @@ import * as React from "react"; interface Props { - initialUserName: string; - editingName: string; - onNameUpdated: () => any; - onEditingNameUpdated: (newEditingName: string) => any; - disabled: boolean; + initialUserName: string; + onNameUpdated: () => any; + editingName: string; + onEditingNameUpdated: (newEditingName: string) => any; + disabled: boolean; } -export const NameEditComponent: React.FC = (props) => { - const onChange = (e: React.ChangeEvent) => { - props.onEditingNameUpdated(e.target.value); - }; +export const NameEditComponent = (props: Props) => { + // const [editingName, setEditingName] = React.useState(props.initialUserName); + const [lastInitialName, setLastInitialName] = React.useState(props.initialUserName); - const onNameSubmit = (event: any): any => { - props.onNameUpdated(); - }; + const onChange = (e: React.ChangeEvent) => { + // setEditingName(e.target.value); + props.onEditingNameUpdated(e.target.value); + } - return ( - <> - - - - - ); -}; + const onNameSubmit = (event: any): any => { + // props.onNameUpdated(editingName); + props.onNameUpdated(); + } + + // if (props.initialUserName !== lastInitialName) { + // setLastInitialName(props.initialUserName); + // setEditingName(props.initialUserName); + // } + return ( + <> + + + + + ) +} \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/sidebar.css b/hooks/11_TableAxios/src/components/sidebar.css index 907d868f..2a472518 100644 --- a/hooks/11_TableAxios/src/components/sidebar.css +++ b/hooks/11_TableAxios/src/components/sidebar.css @@ -1,38 +1,47 @@ /* The side navigation menu */ .sidenav { - height: 100%; /* 100% Full-height */ - width: 0; /* 0 width - change this with JavaScript */ - position: fixed; /* Stay in place */ - z-index: 1; /* Stay on top */ - top: 0; - left: 0; - background-color: #808080; /* Gray*/ - overflow-x: hidden; /* Disable horizontal scroll */ - padding-top: 60px; /* Place content 60px from the top */ - transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */ + height: 100%; + /* 100% Full-height */ + width: 0; + /* 0 width - change this with JavaScript */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Stay on top */ + top: 0; + left: 0; + background-color: #808080; + /* Gray*/ + overflow-x: hidden; + /* Disable horizontal scroll */ + padding-top: 60px; + /* Place content 60px from the top */ + transition: 0.5s; + /* 0.5 second transition effect to slide in the sidenav */ } /* Position and style the close button (top right corner) */ .sidenav .closebtn { - position: absolute; - top: 0; - right: 25px; - font-size: 36px; - margin-left: 50px; + position: absolute; + top: 0; + right: 25px; + font-size: 36px; + margin-left: 50px; } /* Style page content - use this if you want to push the page content to the right when you open the side navigation */ #main { - transition: margin-left 0.5s; - padding: 20px; + transition: margin-left 0.5s; + padding: 20px; } /* On smaller screens, where height is less than 450px, change the style of the sidenav (less padding and a smaller font size) */ @media screen and (max-height: 450px) { - .sidenav { - padding-top: 15px; - } - .sidenav a { - font-size: 18px; - } -} + .sidenav { + padding-top: 15px; + } + + .sidenav a { + font-size: 18px; + } +} \ No newline at end of file diff --git a/hooks/11_TableAxios/src/components/sidebar.tsx b/hooks/11_TableAxios/src/components/sidebar.tsx index 762991eb..19af0eee 100644 --- a/hooks/11_TableAxios/src/components/sidebar.tsx +++ b/hooks/11_TableAxios/src/components/sidebar.tsx @@ -3,17 +3,16 @@ import * as React from "react"; const classNames = require("./sidebar.css"); interface Props { - isVisible: boolean; + isVisible: boolean; + children: React.ReactNode; } const divStyle = (props: Props): React.CSSProperties => ({ - width: props.isVisible ? "23rem" : "0rem" -}); - -export const SidebarComponent: React.StatelessComponent = props => ( -
- {props.children} -
-); - + width: (props.isVisible) ? '23rem' : '0rem' +}) +export const SidebarComponent: React.FC = (props) => ( +
+ {props.children} +
+); \ No newline at end of file diff --git a/hooks/11_TableAxios/src/index.html b/hooks/11_TableAxios/src/index.html index c57efeff..ff56f8d6 100644 --- a/hooks/11_TableAxios/src/index.html +++ b/hooks/11_TableAxios/src/index.html @@ -1,13 +1,16 @@ - - - - - -
-

Sample app

-
-
- - + + + + + + + +
+

Sample app

+
+
+ + + \ No newline at end of file diff --git a/hooks/11_TableAxios/src/index.tsx b/hooks/11_TableAxios/src/index.tsx deleted file mode 100644 index 26ed977f..00000000 --- a/hooks/11_TableAxios/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); diff --git a/hooks/11_TableAxios/src/model/color.ts b/hooks/11_TableAxios/src/model/color.ts deleted file mode 100644 index 17acfedc..00000000 --- a/hooks/11_TableAxios/src/model/color.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Color { - red: number; - green: number; - blue: number; -} diff --git a/hooks/11_TableAxios/src/model/color.tsx b/hooks/11_TableAxios/src/model/color.tsx new file mode 100644 index 00000000..c1783c64 --- /dev/null +++ b/hooks/11_TableAxios/src/model/color.tsx @@ -0,0 +1,5 @@ +export interface Color { + red: number; + green: number; + blue: number; +} \ No newline at end of file diff --git a/hooks/11_TableAxios/src/model/member.ts b/hooks/11_TableAxios/src/model/member.tsx similarity index 100% rename from hooks/11_TableAxios/src/model/member.ts rename to hooks/11_TableAxios/src/model/member.tsx diff --git a/hooks/11_TableAxios/webpack.config.js b/hooks/11_TableAxios/webpack.config.js index c9996585..9860631f 100644 --- a/hooks/11_TableAxios/webpack.config.js +++ b/hooks/11_TableAxios/webpack.config.js @@ -1,80 +1,78 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx", ".css"], + extensions: [".js", ".ts", ".tsx", ".css"] }, - entry: ["@babel/polyfill", "./index.tsx"], + entry: ["@babel/polyfill", "./components/index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, include: /node_modules/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, + // Use CSS modules for custom stylesheets { test: /\.css$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, { - loader: "css-loader", + loader: 'css-loader', options: { + modules: true, modules: { localIdentName: "[name]__[local]___[hash:base64:5]", }, - localsConvention: "camelCase", }, - }, - ], + } + ] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/12_ReactRouter/.babelrc b/hooks/12_ReactRouter/.babelrc deleted file mode 100644 index d09d473e..00000000 --- a/hooks/12_ReactRouter/.babelrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ], - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/hooks/12_ReactRouter/package.json b/hooks/12_ReactRouter/package.json index fb377361..2dd4ac8f 100644 --- a/hooks/12_ReactRouter/package.json +++ b/hooks/12_ReactRouter/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,32 +15,29 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "@types/react-router-dom": "^5.1.5", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-router-dom": "^5.3.3", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-router-dom": "^5.2.0" + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" } } diff --git a/hooks/12_ReactRouter/src/app.tsx b/hooks/12_ReactRouter/src/app.tsx index 18beb8eb..f3207a95 100644 --- a/hooks/12_ReactRouter/src/app.tsx +++ b/hooks/12_ReactRouter/src/app.tsx @@ -1,18 +1,21 @@ import * as React from "react"; -import { HashRouter, Switch, Route } from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; import { PageA } from "./pages/pageA"; import { PageB } from "./pages/pageB"; +/** + * not use Switch (V6) + * @returns + */ export const App = () => { - - return ( - <> - - - - - - - - ); -}; + return ( + <> + + + } /> + } /> + + + + ); +}; \ No newline at end of file diff --git a/hooks/12_ReactRouter/src/hello.tsx b/hooks/12_ReactRouter/src/hello.tsx new file mode 100644 index 00000000..b9b1d810 --- /dev/null +++ b/hooks/12_ReactRouter/src/hello.tsx @@ -0,0 +1,9 @@ +import * as React from "react"; + +interface Props { + userName: string; +} + +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/12_ReactRouter/src/index.tsx b/hooks/12_ReactRouter/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/12_ReactRouter/src/index.tsx +++ b/hooks/12_ReactRouter/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/12_ReactRouter/src/nameEdit.tsx b/hooks/12_ReactRouter/src/nameEdit.tsx new file mode 100644 index 00000000..a6ef1ef8 --- /dev/null +++ b/hooks/12_ReactRouter/src/nameEdit.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; + +interface Props { + userName: string; + onChange: (e: React.ChangeEvent) => void; +} + +export const NameEditComponent = (props: Props) => ( + <> + + + +) \ No newline at end of file diff --git a/hooks/12_ReactRouter/src/pages/pageA.tsx b/hooks/12_ReactRouter/src/pages/pageA.tsx index 1eab2e8c..25799fc8 100644 --- a/hooks/12_ReactRouter/src/pages/pageA.tsx +++ b/hooks/12_ReactRouter/src/pages/pageA.tsx @@ -1,9 +1,9 @@ -import * as React from "react"; -import { Link } from "react-router-dom"; +import * as React from "react" +import { Link } from "react-router-dom" -export const PageA = () => -
-

Hello from page A

-
- Navigate to Page B -
+export const PageA = () => +
+

Hello from page A

+
+ Navigate to Page B +
\ No newline at end of file diff --git a/hooks/12_ReactRouter/src/pages/pageB.tsx b/hooks/12_ReactRouter/src/pages/pageB.tsx index 39a86dd1..c18f1022 100644 --- a/hooks/12_ReactRouter/src/pages/pageB.tsx +++ b/hooks/12_ReactRouter/src/pages/pageB.tsx @@ -1,9 +1,9 @@ -import * as React from "react"; -import { Link } from "react-router-dom"; +import * as React from "react" +import { Link } from "react-router-dom" -export const PageB = () => -
-

Hello from page B

-
- Navigate to Page A -
+export const PageB = () => +
+

Hello from page B

+
+ Navigate to Page A +
\ No newline at end of file diff --git a/hooks/12_ReactRouter/webpack.config.js b/hooks/12_ReactRouter/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/12_ReactRouter/webpack.config.js +++ b/hooks/12_ReactRouter/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/13_LoginForm/.babelrc b/hooks/13_LoginForm/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/13_LoginForm/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/13_LoginForm/package.json b/hooks/13_LoginForm/package.json index 258ceb77..8f7c3c5d 100644 --- a/hooks/13_LoginForm/package.json +++ b/hooks/13_LoginForm/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,34 +15,34 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "@types/react-router-dom": "^5.1.5", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-router-dom": "^5.3.3", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-router-dom": "^5.2.0" + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/icons-material": "^5.11.11", + "@mui/material": "^5.11.14", + "@mui/styled-engine": "^5.11.11", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" } } diff --git a/hooks/13_LoginForm/src/app.tsx b/hooks/13_LoginForm/src/app.tsx index 169d50d8..600249f8 100644 --- a/hooks/13_LoginForm/src/app.tsx +++ b/hooks/13_LoginForm/src/app.tsx @@ -1,17 +1,22 @@ import * as React from "react"; -import { HashRouter, Switch, Route } from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { LoginComponent } from "./pages/login.component"; import { LoginContainer } from "./pages/login.container"; import { PageB } from "./pages/pageB"; +/** + * not use Switch (V6) + * @returns + */ export const App = () => { - return ( - <> - - - - - - - - ); -}; + return ( + <> + + + } /> + } /> + + + + ); +}; \ No newline at end of file diff --git a/hooks/13_LoginForm/src/common/index.ts b/hooks/13_LoginForm/src/common/index.ts index d9b217ce..dd99c4d0 100644 --- a/hooks/13_LoginForm/src/common/index.ts +++ b/hooks/13_LoginForm/src/common/index.ts @@ -1 +1 @@ -export * from './notification'; +export * from "./notification"; diff --git a/hooks/13_LoginForm/src/common/notification.tsx b/hooks/13_LoginForm/src/common/notification.tsx index 50e2b706..a5725a2f 100644 --- a/hooks/13_LoginForm/src/common/notification.tsx +++ b/hooks/13_LoginForm/src/common/notification.tsx @@ -1,52 +1,41 @@ +import { IconButton, Snackbar } from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; import * as React from "react"; -import Snackbar from "@material-ui/core/Snackbar"; -import IconButton from "@material-ui/core/IconButton"; -import CloseIcon from "@material-ui/icons/Close"; -import createStyles from "@material-ui/core/styles/createStyles"; -import makeStyles from "@material-ui/core/styles/makeStyles"; interface Props { - message: string; - show: boolean; - onClose: () => void; + message: string; + show: boolean; + onClose: () => void; } -const useStyles = makeStyles((theme) => - createStyles({ - close: { - padding: theme.spacing(0.5), - }, - }) -); -export const NotificationComponent: React.FC = (props) => { - const classes = useStyles(); - const { message, show, onClose } = props; - return ( - {message}} - action={[ - - - , - ]} - /> - ); -}; +export const NotificationComponent = (props: Props) => { + const { message, show, onClose } = props; + + return ( + {message}} + action={[ + + + + ]} + /> + ); +}; \ No newline at end of file diff --git a/hooks/13_LoginForm/src/hello.tsx b/hooks/13_LoginForm/src/hello.tsx new file mode 100644 index 00000000..b9b1d810 --- /dev/null +++ b/hooks/13_LoginForm/src/hello.tsx @@ -0,0 +1,9 @@ +import * as React from "react"; + +interface Props { + userName: string; +} + +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/13_LoginForm/src/index.html b/hooks/13_LoginForm/src/index.html index 2ad4810e..7594228e 100644 --- a/hooks/13_LoginForm/src/index.html +++ b/hooks/13_LoginForm/src/index.html @@ -1,12 +1,15 @@ - - - - - -
-
-
- - + + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/hooks/13_LoginForm/src/index.tsx b/hooks/13_LoginForm/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/13_LoginForm/src/index.tsx +++ b/hooks/13_LoginForm/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/13_LoginForm/src/model/login.ts b/hooks/13_LoginForm/src/model/login.ts index 32854b75..5b7d14a7 100644 --- a/hooks/13_LoginForm/src/model/login.ts +++ b/hooks/13_LoginForm/src/model/login.ts @@ -5,5 +5,5 @@ export interface LoginEntity { export const createEmptyLogin = (): LoginEntity => ({ login: "", - password: "" + password: "", }); diff --git a/hooks/13_LoginForm/src/nameEdit.tsx b/hooks/13_LoginForm/src/nameEdit.tsx new file mode 100644 index 00000000..a6ef1ef8 --- /dev/null +++ b/hooks/13_LoginForm/src/nameEdit.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; + +interface Props { + userName: string; + onChange: (e: React.ChangeEvent) => void; +} + +export const NameEditComponent = (props: Props) => ( + <> + + + +) \ No newline at end of file diff --git a/hooks/13_LoginForm/src/pages/login.component.tsx b/hooks/13_LoginForm/src/pages/login.component.tsx index c78a4851..dd7152b8 100644 --- a/hooks/13_LoginForm/src/pages/login.component.tsx +++ b/hooks/13_LoginForm/src/pages/login.component.tsx @@ -1,60 +1,46 @@ +import { Button, Divider, TextField } from "@mui/material"; +import { styled } from "@mui/system"; import * as React from "react"; -import makeStyles from "@material-ui/styles/makeStyles"; -import createStyles from "@material-ui/styles/createStyles"; -import TextField from "@material-ui/core/TextField"; -import Button from "@material-ui/core/Button"; -import { LoginEntity, createEmptyLogin } from "../model/login"; +import { FormProps } from "react-router-dom"; +import { createEmptyLogin, LoginEntity } from "../model/login"; interface PropsForm { - onLogin: (login: LoginEntity) => void; + onLogin: (login: LoginEntity) => void; } -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - formContainer: { - display: "flex", - flexDirection: "column", - justifyContent: "center", - }, - }) -); +// const useFormStyles = makeStyles(theme => +// createStyles({ +// formContainer: { +// display: "flex", +// flexDirection: "column", +// justifyContent: "center" +// } +// }) +// ); -export const LoginComponent: React.FC = (props) => { - const { onLogin } = props; - const [loginInfo, setLoginInfo] = React.useState( - createEmptyLogin() - ); - const classes = useFormStyles(); - const onTexFieldChange = (fieldId) => (e) => { - setLoginInfo({ - ...loginInfo, - [fieldId]: e.target.value, - }); - }; +export const LoginComponent = (props: PropsForm) => { + const { onLogin } = props; - return ( -
- - - -
- ); -}; + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ); + + const onTextFieldChange = (fieldId) => (e) => { + setLoginInfo({ + ...loginInfo, + [fieldId]: e.target.value + }) + } + + return ( +
+ + + +
+ ) +} diff --git a/hooks/13_LoginForm/src/pages/login.container.tsx b/hooks/13_LoginForm/src/pages/login.container.tsx index 943c433b..954641e1 100644 --- a/hooks/13_LoginForm/src/pages/login.container.tsx +++ b/hooks/13_LoginForm/src/pages/login.container.tsx @@ -1,57 +1,61 @@ +import { Card, CardContent, CardHeader, createStyles, makeStyles, styled } from "@mui/material"; import * as React from "react"; -import { useHistory } from "react-router-dom"; -import { LoginEntity } from "../model/login"; -import { isValidLogin } from "../api/login"; +import { useNavigate } from "react-router-dom"; import { LoginComponent } from "./login.component"; -import Card from "@material-ui/core/Card"; -import CardHeader from "@material-ui/core/CardHeader"; -import CardContent from "@material-ui/core/CardContent"; -import createStyles from "@material-ui/styles/createStyles"; -import makeStyles from "@material-ui/styles/makeStyles"; +import { LoginEntity, createEmptyLogin } from "../model/login"; +import { isValidLogin } from "../api/login"; import { NotificationComponent } from "../common"; -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - card: { - maxWidth: 400, - margin: "0 auto", - }, - }) -); +interface Props { } -interface Props {} +// const useStyles = makeStyles(theme => +// createStyles({ +// card: { +// maxWidth: 400, +// margin: "0 auto" +// } +// }) +// ); + +const SampleCardStyled = styled(Card)(({ theme }) => ({ + maxWidth: 400, + margin: "0 auto" +})) export const LoginContainer: React.FC = (props) => { - const history = useHistory(); - const [isShowAlert, setShowAlert] = React.useState(false); - const classes = useFormStyles(); - - const loginSucceeded = (isValid: boolean) => { - if (isValid) { - history.push("/pageB"); - } else { - setShowAlert(true); + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ) + const [isShowAlert, setShowAlert] = React.useState(false); + + const navigate = useNavigate(); + + const loginSucceeded = (isValid: boolean) => { + console.log(isValid) + if (isValid) { + navigate('/pageB') + } else { + setShowAlert(true) + } } - }; - - const handleLogin = (login: LoginEntity) => { - isValidLogin(login).then(loginSucceeded); - }; - - return ( - <> - - - - - setShowAlert(false)} - /> - - - - ); + + const handleLogin = (login: LoginEntity) => { + isValidLogin(login).then(loginSucceeded); + }; + + return ( + <> + + + + + + + setShowAlert(false)} /> + + ); }; + diff --git a/hooks/13_LoginForm/src/pages/loginPage.tsx b/hooks/13_LoginForm/src/pages/loginPage.tsx new file mode 100644 index 00000000..0b708c53 --- /dev/null +++ b/hooks/13_LoginForm/src/pages/loginPage.tsx @@ -0,0 +1,9 @@ +import * as React from "react" +import { FormProps, Link } from "react-router-dom" + +export const LoginComponent: React.FC = (props) => +
+

Hello from login Page

+
+ Navigate to Page B +
\ No newline at end of file diff --git a/hooks/13_LoginForm/src/pages/pageB.tsx b/hooks/13_LoginForm/src/pages/pageB.tsx index 87ec4719..a8853c0c 100644 --- a/hooks/13_LoginForm/src/pages/pageB.tsx +++ b/hooks/13_LoginForm/src/pages/pageB.tsx @@ -1,10 +1,9 @@ -import * as React from "react"; -import { Link } from "react-router-dom"; +import * as React from "react" +import { Link } from "react-router-dom" -export const PageB = () => ( -
-

Hello from page B

-
- Navigate to Login -
-); +export const PageB = () => +
+

Hello from page B

+
+ Navigate to Login +
\ No newline at end of file diff --git a/hooks/13_LoginForm/webpack.config.js b/hooks/13_LoginForm/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/13_LoginForm/webpack.config.js +++ b/hooks/13_LoginForm/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/14_FormValidation/.babelrc b/hooks/14_FormValidation/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/14_FormValidation/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/14_FormValidation/package.json b/hooks/14_FormValidation/package.json index 79169511..a6f809bc 100644 --- a/hooks/14_FormValidation/package.json +++ b/hooks/14_FormValidation/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,37 +15,37 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "@types/react-router-dom": "^5.1.5", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-router-dom": "^5.3.3", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "@lemoncode/fonk": "^1.3.0", + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@lemoncode/fonk": "^1.5.4", "@lemoncode/fonk-formik": "^4.0.1", - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "formik": "^2.1.5", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-router-dom": "^5.2.0" + "@mui/icons-material": "^5.11.11", + "@mui/material": "^5.11.14", + "@mui/styled-engine": "^5.11.11", + "formik": "^2.2.9", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" } -} +} \ No newline at end of file diff --git a/hooks/14_FormValidation/src/app.tsx b/hooks/14_FormValidation/src/app.tsx index 169d50d8..600249f8 100644 --- a/hooks/14_FormValidation/src/app.tsx +++ b/hooks/14_FormValidation/src/app.tsx @@ -1,17 +1,22 @@ import * as React from "react"; -import { HashRouter, Switch, Route } from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { LoginComponent } from "./pages/login.component"; import { LoginContainer } from "./pages/login.container"; import { PageB } from "./pages/pageB"; +/** + * not use Switch (V6) + * @returns + */ export const App = () => { - return ( - <> - - - - - - - - ); -}; + return ( + <> + + + } /> + } /> + + + + ); +}; \ No newline at end of file diff --git a/hooks/14_FormValidation/src/common/index.ts b/hooks/14_FormValidation/src/common/index.ts index f377fb57..fe9e7da1 100644 --- a/hooks/14_FormValidation/src/common/index.ts +++ b/hooks/14_FormValidation/src/common/index.ts @@ -1,2 +1,2 @@ -export * from './notification'; -export * from './textField.component'; \ No newline at end of file +export * from "./notification"; +export * from "./textField.component"; diff --git a/hooks/14_FormValidation/src/common/notification.tsx b/hooks/14_FormValidation/src/common/notification.tsx index 50e2b706..a5725a2f 100644 --- a/hooks/14_FormValidation/src/common/notification.tsx +++ b/hooks/14_FormValidation/src/common/notification.tsx @@ -1,52 +1,41 @@ +import { IconButton, Snackbar } from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; import * as React from "react"; -import Snackbar from "@material-ui/core/Snackbar"; -import IconButton from "@material-ui/core/IconButton"; -import CloseIcon from "@material-ui/icons/Close"; -import createStyles from "@material-ui/core/styles/createStyles"; -import makeStyles from "@material-ui/core/styles/makeStyles"; interface Props { - message: string; - show: boolean; - onClose: () => void; + message: string; + show: boolean; + onClose: () => void; } -const useStyles = makeStyles((theme) => - createStyles({ - close: { - padding: theme.spacing(0.5), - }, - }) -); -export const NotificationComponent: React.FC = (props) => { - const classes = useStyles(); - const { message, show, onClose } = props; - return ( - {message}} - action={[ - - - , - ]} - /> - ); -}; +export const NotificationComponent = (props: Props) => { + const { message, show, onClose } = props; + + return ( + {message}} + action={[ + + + + ]} + /> + ); +}; \ No newline at end of file diff --git a/hooks/14_FormValidation/src/common/textField.component.tsx b/hooks/14_FormValidation/src/common/textField.component.tsx index 718e1173..957a4c80 100644 --- a/hooks/14_FormValidation/src/common/textField.component.tsx +++ b/hooks/14_FormValidation/src/common/textField.component.tsx @@ -1,25 +1,26 @@ import * as React from "react"; import { useField } from "formik"; -import MuiTextField, { TextFieldProps } from "@material-ui/core/TextField"; +import { TextField, TextFieldProps } from "@mui/material"; export const TextFieldComponent: React.FC = (props) => { - const [field, meta] = useField(props.name); - const textFieldProps = Boolean(field) ? field : props; - const hasError = Boolean(meta && meta.touched && meta.error); + const [field, meta] = useField(props.name); + const TextFieldProps = Boolean(field) ? field : props; + const hasError = Boolean(meta && meta.touched && meta.error); - return ( - <> - - - ); -}; + return ( + <> + + + + ); +} \ No newline at end of file diff --git a/hooks/14_FormValidation/src/hello.tsx b/hooks/14_FormValidation/src/hello.tsx new file mode 100644 index 00000000..b9b1d810 --- /dev/null +++ b/hooks/14_FormValidation/src/hello.tsx @@ -0,0 +1,9 @@ +import * as React from "react"; + +interface Props { + userName: string; +} + +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/14_FormValidation/src/index.html b/hooks/14_FormValidation/src/index.html index 2ad4810e..7594228e 100644 --- a/hooks/14_FormValidation/src/index.html +++ b/hooks/14_FormValidation/src/index.html @@ -1,12 +1,15 @@ - - - - - -
-
-
- - + + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/hooks/14_FormValidation/src/index.tsx b/hooks/14_FormValidation/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/14_FormValidation/src/index.tsx +++ b/hooks/14_FormValidation/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/14_FormValidation/src/model/login.ts b/hooks/14_FormValidation/src/model/login.ts index 32854b75..5b7d14a7 100644 --- a/hooks/14_FormValidation/src/model/login.ts +++ b/hooks/14_FormValidation/src/model/login.ts @@ -5,5 +5,5 @@ export interface LoginEntity { export const createEmptyLogin = (): LoginEntity => ({ login: "", - password: "" + password: "", }); diff --git a/hooks/14_FormValidation/src/nameEdit.tsx b/hooks/14_FormValidation/src/nameEdit.tsx new file mode 100644 index 00000000..a6ef1ef8 --- /dev/null +++ b/hooks/14_FormValidation/src/nameEdit.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; + +interface Props { + userName: string; + onChange: (e: React.ChangeEvent) => void; +} + +export const NameEditComponent = (props: Props) => ( + <> + + + +) \ No newline at end of file diff --git a/hooks/14_FormValidation/src/pages/login.component.tsx b/hooks/14_FormValidation/src/pages/login.component.tsx index e968d5d6..6b643530 100644 --- a/hooks/14_FormValidation/src/pages/login.component.tsx +++ b/hooks/14_FormValidation/src/pages/login.component.tsx @@ -1,53 +1,76 @@ +import { Button, Divider, TextField } from "@mui/material"; +// import { styled } from "@mui/system"; import * as React from "react"; -import { LoginEntity, createEmptyLogin } from "../model/login"; -import { TextFieldComponent } from "../common"; -import { Form } from "formik"; -import createStyles from "@material-ui/styles/createStyles"; -import makeStyles from "@material-ui/styles/makeStyles"; -import Button from "@material-ui/core/Button"; +// import { FormProps } from "react-router-dom"; +import { createEmptyLogin, LoginEntity } from "../model/login"; import { loginFormValidation } from "./login.validation"; -import { Formik } from "formik"; +import { TextFieldComponent } from "../common"; +import { Form, Formik } from "formik"; interface PropsForm { - onLogin: (login: LoginEntity) => void; + onLogin: (login: LoginEntity) => void; } -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - formContainer: { - display: "flex", - flexDirection: "column", - justifyContent: "center", - }, - }) -); - -export const LoginComponent: React.FC = (props) => { - const classes = useFormStyles(); - const { onLogin } = props; - - return ( - - {() => ( -
-
- - - -
-
- )} -
- ); -}; +// const useFormStyles = makeStyles(theme => +// createStyles({ +// formContainer: { +// display: "flex", +// flexDirection: "column", +// justifyContent: "center" +// } +// }) +// ); + +export const LoginComponent = (props: PropsForm) => { + const { onLogin } = props; + + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ); + + const onTextFieldChange = (fieldId) => (e) => { + setLoginInfo({ + ...loginInfo, + [fieldId]: e.target.value + }) + } + + return ( + + {() => ( +
+ //
+ + + +
+
+ )} +
+ + + + + //
+ // + // + // + //
+ ) +} diff --git a/hooks/14_FormValidation/src/pages/login.container.tsx b/hooks/14_FormValidation/src/pages/login.container.tsx index 1da3ed87..954641e1 100644 --- a/hooks/14_FormValidation/src/pages/login.container.tsx +++ b/hooks/14_FormValidation/src/pages/login.container.tsx @@ -1,58 +1,61 @@ +import { Card, CardContent, CardHeader, createStyles, makeStyles, styled } from "@mui/material"; import * as React from "react"; -import { useHistory } from "react-router-dom"; -import { LoginEntity } from "../model/login"; -import { isValidLogin } from "../api/login"; +import { useNavigate } from "react-router-dom"; import { LoginComponent } from "./login.component"; -import Card from "@material-ui/core/Card"; -import CardHeader from "@material-ui/core/CardHeader"; -import CardContent from "@material-ui/core/CardContent"; -import createStyles from "@material-ui/styles/createStyles"; -import makeStyles from "@material-ui/styles/makeStyles"; +import { LoginEntity, createEmptyLogin } from "../model/login"; +import { isValidLogin } from "../api/login"; import { NotificationComponent } from "../common"; -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - card: { - maxWidth: 400, - margin: "0 auto", - }, - }) -); +interface Props { } -interface Props {} -interface Props {} +// const useStyles = makeStyles(theme => +// createStyles({ +// card: { +// maxWidth: 400, +// margin: "0 auto" +// } +// }) +// ); + +const SampleCardStyled = styled(Card)(({ theme }) => ({ + maxWidth: 400, + margin: "0 auto" +})) export const LoginContainer: React.FC = (props) => { - const history = useHistory(); - const [isShowAlert, setShowAlert] = React.useState(false); - const classes = useFormStyles(); - - const loginSucceeded = (isValid: boolean) => { - if (isValid) { - history.push("/pageB"); - } else { - setShowAlert(true); + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ) + const [isShowAlert, setShowAlert] = React.useState(false); + + const navigate = useNavigate(); + + const loginSucceeded = (isValid: boolean) => { + console.log(isValid) + if (isValid) { + navigate('/pageB') + } else { + setShowAlert(true) + } } - }; - - const handleLogin = (login: LoginEntity) => { - isValidLogin(login).then(loginSucceeded); - }; - - return ( - <> - - - - - setShowAlert(false)} - /> - - - - ); + + const handleLogin = (login: LoginEntity) => { + isValidLogin(login).then(loginSucceeded); + }; + + return ( + <> + + + + + + + setShowAlert(false)} /> + + ); }; + diff --git a/hooks/14_FormValidation/src/pages/login.validation.ts b/hooks/14_FormValidation/src/pages/login.validation.ts index 20942129..5b4a9c67 100644 --- a/hooks/14_FormValidation/src/pages/login.validation.ts +++ b/hooks/14_FormValidation/src/pages/login.validation.ts @@ -1,5 +1,8 @@ -import { ValidationSchema, Validators } from "@lemoncode/fonk"; -import { createFormikValidation } from "@lemoncode/fonk-formik"; +import { + createFormValidation, + ValidationSchema, + Validators, +} from "@lemoncode/fonk"; const validationSchema: ValidationSchema = { field: { @@ -8,4 +11,4 @@ const validationSchema: ValidationSchema = { }, }; -export const loginFormValidation = createFormikValidation(validationSchema); +export const loginFormValidation = createFormValidation(validationSchema); diff --git a/hooks/14_FormValidation/src/pages/loginPage.tsx b/hooks/14_FormValidation/src/pages/loginPage.tsx new file mode 100644 index 00000000..0b708c53 --- /dev/null +++ b/hooks/14_FormValidation/src/pages/loginPage.tsx @@ -0,0 +1,9 @@ +import * as React from "react" +import { FormProps, Link } from "react-router-dom" + +export const LoginComponent: React.FC = (props) => +
+

Hello from login Page

+
+ Navigate to Page B +
\ No newline at end of file diff --git a/hooks/14_FormValidation/src/pages/pageB.tsx b/hooks/14_FormValidation/src/pages/pageB.tsx index 87ec4719..a8853c0c 100644 --- a/hooks/14_FormValidation/src/pages/pageB.tsx +++ b/hooks/14_FormValidation/src/pages/pageB.tsx @@ -1,10 +1,9 @@ -import * as React from "react"; -import { Link } from "react-router-dom"; +import * as React from "react" +import { Link } from "react-router-dom" -export const PageB = () => ( -
-

Hello from page B

-
- Navigate to Login -
-); +export const PageB = () => +
+

Hello from page B

+
+ Navigate to Login +
\ No newline at end of file diff --git a/hooks/14_FormValidation/webpack.config.js b/hooks/14_FormValidation/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/14_FormValidation/webpack.config.js +++ b/hooks/14_FormValidation/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/hooks/15_Context/.babelrc b/hooks/15_Context/.babelrc deleted file mode 100644 index 957cae3e..00000000 --- a/hooks/15_Context/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry" - } - ] - ] -} diff --git a/hooks/15_Context/package.json b/hooks/15_Context/package.json index 79169511..a6f809bc 100644 --- a/hooks/15_Context/package.json +++ b/hooks/15_Context/package.json @@ -4,7 +4,7 @@ "description": "React Typescript examples", "main": "index.js", "scripts": { - "start": "webpack-dev-server --mode development --inline --hot --open", + "start": "webpack-dev-server --mode development --hot --open", "build": "webpack --mode development" }, "keywords": [ @@ -15,37 +15,37 @@ "author": "Braulio Diez Botella", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.10.5", - "@babel/polyfill": "^7.10.4", - "@babel/preset-env": "^7.10.4", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", - "@types/node": "^14.0.24", - "@types/react": "^16.9.43", - "@types/react-dom": "^16.9.8", - "@types/react-router-dom": "^5.1.5", - "awesome-typescript-loader": "^5.2.1", - "babel-loader": "^8.1.0", - "css-loader": "^3.6.0", - "file-loader": "^6.0.0", - "html-webpack-plugin": "^4.3.0", - "mini-css-extract-plugin": "^0.9.0", - "style-loader": "^1.2.1", - "typescript": "^3.9.7", - "url-loader": "^4.1.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-dev-server": "^3.11.0" + "@babel/cli": "^7.21.0", + "@babel/core": "^7.21.0", + "@babel/polyfill": "^7.12.1", + "@babel/preset-env": "^7.20.2", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-router-dom": "^5.3.3", + "babel-loader": "^9.1.2", + "css-loader": "^6.7.3", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "mini-css-extract-plugin": "^2.7.3", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.2", + "typescript": "^4.9.5", + "url-loader": "^4.1.1", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "webpack-dev-server": "^4.11.1" }, "dependencies": { - "@lemoncode/fonk": "^1.3.0", + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@lemoncode/fonk": "^1.5.4", "@lemoncode/fonk-formik": "^4.0.1", - "@material-ui/core": "^4.11.0", - "@material-ui/icons": "^4.9.1", - "formik": "^2.1.5", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-router-dom": "^5.2.0" + "@mui/icons-material": "^5.11.11", + "@mui/material": "^5.11.14", + "@mui/styled-engine": "^5.11.11", + "formik": "^2.2.9", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.9.0" } -} +} \ No newline at end of file diff --git a/hooks/15_Context/src/app.tsx b/hooks/15_Context/src/app.tsx index 89ae2660..e50e8946 100644 --- a/hooks/15_Context/src/app.tsx +++ b/hooks/15_Context/src/app.tsx @@ -1,20 +1,25 @@ import * as React from "react"; -import { HashRouter, Switch, Route } from "react-router-dom"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { SessionProvider } from "./common/sessionContext"; +import { LoginComponent } from "./pages/login.component"; import { LoginContainer } from "./pages/login.container"; import { PageB } from "./pages/pageB"; -import { SessionProvider } from "./common"; +/** + * not use Switch (V6) + * @returns + */ export const App = () => { - return ( - <> - - - - - - - - - - ); -}; + return ( + <> + + + } > + } > + + } /> + + + + ); +}; \ No newline at end of file diff --git a/hooks/15_Context/src/common/index.ts b/hooks/15_Context/src/common/index.ts index feefdf2a..ad4d962b 100644 --- a/hooks/15_Context/src/common/index.ts +++ b/hooks/15_Context/src/common/index.ts @@ -1,3 +1,3 @@ export * from "./notification"; export * from "./textField.component"; -export * from "./sessionContext"; +// export * from "./sessionContext"; diff --git a/hooks/15_Context/src/common/notification.tsx b/hooks/15_Context/src/common/notification.tsx index 50e2b706..a5725a2f 100644 --- a/hooks/15_Context/src/common/notification.tsx +++ b/hooks/15_Context/src/common/notification.tsx @@ -1,52 +1,41 @@ +import { IconButton, Snackbar } from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; import * as React from "react"; -import Snackbar from "@material-ui/core/Snackbar"; -import IconButton from "@material-ui/core/IconButton"; -import CloseIcon from "@material-ui/icons/Close"; -import createStyles from "@material-ui/core/styles/createStyles"; -import makeStyles from "@material-ui/core/styles/makeStyles"; interface Props { - message: string; - show: boolean; - onClose: () => void; + message: string; + show: boolean; + onClose: () => void; } -const useStyles = makeStyles((theme) => - createStyles({ - close: { - padding: theme.spacing(0.5), - }, - }) -); -export const NotificationComponent: React.FC = (props) => { - const classes = useStyles(); - const { message, show, onClose } = props; - return ( - {message}} - action={[ - - - , - ]} - /> - ); -}; +export const NotificationComponent = (props: Props) => { + const { message, show, onClose } = props; + + return ( + {message}} + action={[ + + + + ]} + /> + ); +}; \ No newline at end of file diff --git a/hooks/15_Context/src/common/sessionContext.tsx b/hooks/15_Context/src/common/sessionContext.tsx index 4edab12f..19ca35f2 100644 --- a/hooks/15_Context/src/common/sessionContext.tsx +++ b/hooks/15_Context/src/common/sessionContext.tsx @@ -1,29 +1,36 @@ import * as React from "react"; +import { LoginContainer } from "../pages/login.container"; +import { Route, Routes } from "react-router-dom"; export interface SessionContextProps { - login: string; - updateLogin: (value) => void; + login: string; + updateLogin: (value: string) => void; } export const createDefaultUser = (): SessionContextProps => ({ - login: "no user", - updateLogin: (value) => { - console.warn( - "if you are reading this, likely you forgot to add the provider on top of your app" - ); - }, + login: "no user", + updateLogin: value => { + console.warn( + "if you are reading this, likely you forgot to add the provider on top of your app" + ); + } }); -export const SessionContext = React.createContext( - createDefaultUser() -); +export interface Props { + children?: React.ReactNode; +} -export const SessionProvider: React.FC = (props) => { - const [login, setLogin] = React.useState(""); +export const SessionProvider: React.FunctionComponent = (props: Props) => { + const [login, setLogin] = React.useState(""); - return ( - - {props.children} - - ); + return ( + + {/* {props.children} */} + + } /> + + + ); }; + +export const SessionContext = React.createContext(createDefaultUser()); \ No newline at end of file diff --git a/hooks/15_Context/src/common/textField.component.tsx b/hooks/15_Context/src/common/textField.component.tsx index 718e1173..957a4c80 100644 --- a/hooks/15_Context/src/common/textField.component.tsx +++ b/hooks/15_Context/src/common/textField.component.tsx @@ -1,25 +1,26 @@ import * as React from "react"; import { useField } from "formik"; -import MuiTextField, { TextFieldProps } from "@material-ui/core/TextField"; +import { TextField, TextFieldProps } from "@mui/material"; export const TextFieldComponent: React.FC = (props) => { - const [field, meta] = useField(props.name); - const textFieldProps = Boolean(field) ? field : props; - const hasError = Boolean(meta && meta.touched && meta.error); + const [field, meta] = useField(props.name); + const TextFieldProps = Boolean(field) ? field : props; + const hasError = Boolean(meta && meta.touched && meta.error); - return ( - <> - - - ); -}; + return ( + <> + + + + ); +} \ No newline at end of file diff --git a/hooks/15_Context/src/hello.tsx b/hooks/15_Context/src/hello.tsx new file mode 100644 index 00000000..b9b1d810 --- /dev/null +++ b/hooks/15_Context/src/hello.tsx @@ -0,0 +1,9 @@ +import * as React from "react"; + +interface Props { + userName: string; +} + +export const HelloComponent: React.FC = (props) => ( +

Hello user: {props.userName} !

+); diff --git a/hooks/15_Context/src/index.html b/hooks/15_Context/src/index.html index 2ad4810e..7594228e 100644 --- a/hooks/15_Context/src/index.html +++ b/hooks/15_Context/src/index.html @@ -1,12 +1,15 @@ - - - - - -
-
-
- - + + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/hooks/15_Context/src/index.tsx b/hooks/15_Context/src/index.tsx index 26ed977f..0f847e17 100644 --- a/hooks/15_Context/src/index.tsx +++ b/hooks/15_Context/src/index.tsx @@ -1,6 +1,8 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { App } from './app'; -import { App } from "./app"; - -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/hooks/15_Context/src/model/login.ts b/hooks/15_Context/src/model/login.ts index 32854b75..5b7d14a7 100644 --- a/hooks/15_Context/src/model/login.ts +++ b/hooks/15_Context/src/model/login.ts @@ -5,5 +5,5 @@ export interface LoginEntity { export const createEmptyLogin = (): LoginEntity => ({ login: "", - password: "" + password: "", }); diff --git a/hooks/15_Context/src/nameEdit.tsx b/hooks/15_Context/src/nameEdit.tsx new file mode 100644 index 00000000..a6ef1ef8 --- /dev/null +++ b/hooks/15_Context/src/nameEdit.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; + +interface Props { + userName: string; + onChange: (e: React.ChangeEvent) => void; +} + +export const NameEditComponent = (props: Props) => ( + <> + + + +) \ No newline at end of file diff --git a/hooks/15_Context/src/pages/login.component.tsx b/hooks/15_Context/src/pages/login.component.tsx index 2c4adb0e..6272a908 100644 --- a/hooks/15_Context/src/pages/login.component.tsx +++ b/hooks/15_Context/src/pages/login.component.tsx @@ -1,57 +1,79 @@ +import { Button, Divider, TextField } from "@mui/material"; +// import { styled } from "@mui/system"; import * as React from "react"; -import { LoginEntity, createEmptyLogin } from "../model/login"; -import { TextFieldComponent } from "../common"; -import { Form } from "formik"; -import createStyles from "@material-ui/styles/createStyles"; -import makeStyles from "@material-ui/styles/makeStyles"; -import Button from "@material-ui/core/Button"; +// import { FormProps } from "react-router-dom"; +import { createEmptyLogin, LoginEntity } from "../model/login"; import { loginFormValidation } from "./login.validation"; -import { Formik } from "formik"; +import { TextFieldComponent } from "../common"; +import { Form, Formik } from "formik"; interface PropsForm { - onLogin: (login: LoginEntity) => void; + onLogin: (login: LoginEntity) => void; } -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - formContainer: { - display: "flex", - flexDirection: "column", - justifyContent: "center", - }, - card: { - maxWidth: 400, - margin: "0 auto", - }, - }) -); - -export const LoginComponent: React.FC = (props) => { - const classes = useFormStyles(); - const { onLogin } = props; - - return ( - - {() => ( -
-
- - - -
-
- )} -
- ); -}; +// const useFormStyles = makeStyles(theme => +// createStyles({ +// formContainer: { +// display: "flex", +// flexDirection: "column", +// justifyContent: "center" +// } +// }) +// ); + +export const LoginComponent = (props: PropsForm) => { + const { onLogin } = props; + + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ); + + const onTextFieldChange = (fieldId) => (e) => { + console.log(e); + setLoginInfo({ + ...loginInfo, + [fieldId]: e.target.value + }) + } + + return ( + + {() => ( +
+
+ + + +
+
+ )} +
+ + + + + //
+ // + // + // + //
+ ) +} diff --git a/hooks/15_Context/src/pages/login.container.tsx b/hooks/15_Context/src/pages/login.container.tsx index e3e65ca0..5c892f23 100644 --- a/hooks/15_Context/src/pages/login.container.tsx +++ b/hooks/15_Context/src/pages/login.container.tsx @@ -1,59 +1,61 @@ +import { Card, CardContent, CardHeader, createStyles, makeStyles, styled } from "@mui/material"; import * as React from "react"; -import { useHistory } from "react-router-dom"; -import { LoginEntity } from "../model/login"; -import { isValidLogin } from "../api/login"; +import { useNavigate } from "react-router-dom"; import { LoginComponent } from "./login.component"; -import Card from "@material-ui/core/Card"; -import CardHeader from "@material-ui/core/CardHeader"; -import CardContent from "@material-ui/core/CardContent"; -import createStyles from "@material-ui/styles/createStyles"; -import makeStyles from "@material-ui/styles/makeStyles"; -import { NotificationComponent, SessionContext } from "../common"; - -// https://material-ui.com/styles/api/#makestyles-styles-options-hook -const useFormStyles = makeStyles((theme) => - createStyles({ - card: { - maxWidth: 400, - margin: "0 auto", - }, - }) -); - -interface Props {} +import { LoginEntity, createEmptyLogin } from "../model/login"; +import { isValidLogin } from "../api/login"; +import { NotificationComponent } from "../common"; + +interface Props { } + +// const useStyles = makeStyles(theme => +// createStyles({ +// card: { +// maxWidth: 400, +// margin: "0 auto" +// } +// }) +// ); + +const SampleCardStyled = styled(Card)(({ theme }) => ({ + maxWidth: 400, + margin: "0 auto" +})) export const LoginContainer: React.FC = (props) => { - const loginContext = React.useContext(SessionContext); - const history = useHistory(); - const [isShowAlert, setShowAlert] = React.useState(false); - const classes = useFormStyles(); - - const loginSucceeded = (isValid: boolean, login: LoginEntity) => { - if (isValid) { - history.push("/pageB"); - loginContext.updateLogin(login.login); - } else { - setShowAlert(true); + const [loginInfo, setLoginInfo] = React.useState( + createEmptyLogin() + ) + const [isShowAlert, setShowAlert] = React.useState(false); + + const navigate = useNavigate(); + + const loginSucceeded = (isValid: boolean) => { + if (isValid) { + navigate('/pageB') + } else { + setShowAlert(true) + } } - }; - - const handleLogin = (login: LoginEntity) => { - isValidLogin(login).then((isValid) => loginSucceeded(isValid, login)); - }; - - return ( - <> - - - - - setShowAlert(false)} - /> - - - - ); + + const handleLogin = (login: LoginEntity) => { + console.log(login); + isValidLogin(login).then(loginSucceeded); + }; + + return ( + <> + + + + + + + setShowAlert(false)} /> + + ); }; + diff --git a/hooks/15_Context/src/pages/login.validation.ts b/hooks/15_Context/src/pages/login.validation.ts index 20942129..5b4a9c67 100644 --- a/hooks/15_Context/src/pages/login.validation.ts +++ b/hooks/15_Context/src/pages/login.validation.ts @@ -1,5 +1,8 @@ -import { ValidationSchema, Validators } from "@lemoncode/fonk"; -import { createFormikValidation } from "@lemoncode/fonk-formik"; +import { + createFormValidation, + ValidationSchema, + Validators, +} from "@lemoncode/fonk"; const validationSchema: ValidationSchema = { field: { @@ -8,4 +11,4 @@ const validationSchema: ValidationSchema = { }, }; -export const loginFormValidation = createFormikValidation(validationSchema); +export const loginFormValidation = createFormValidation(validationSchema); diff --git a/hooks/15_Context/src/pages/loginPage.tsx b/hooks/15_Context/src/pages/loginPage.tsx new file mode 100644 index 00000000..0b708c53 --- /dev/null +++ b/hooks/15_Context/src/pages/loginPage.tsx @@ -0,0 +1,9 @@ +import * as React from "react" +import { FormProps, Link } from "react-router-dom" + +export const LoginComponent: React.FC = (props) => +
+

Hello from login Page

+
+ Navigate to Page B +
\ No newline at end of file diff --git a/hooks/15_Context/src/pages/pageB.tsx b/hooks/15_Context/src/pages/pageB.tsx index ccf75980..a8853c0c 100644 --- a/hooks/15_Context/src/pages/pageB.tsx +++ b/hooks/15_Context/src/pages/pageB.tsx @@ -1,16 +1,9 @@ -import * as React from "react"; -import { Link } from "react-router-dom"; -import { SessionContext } from "../common"; +import * as React from "react" +import { Link } from "react-router-dom" -export const PageB: React.FC = () => { - const loginContext = React.useContext(SessionContext); - - return ( +export const PageB = () =>
-

Hello from page B

-

User logged in: {loginContext.login}

-
- Navigate to Login -
- ); -}; +

Hello from page B

+
+ Navigate to Login +
\ No newline at end of file diff --git a/hooks/15_Context/tsconfig.json b/hooks/15_Context/tsconfig.json index f90a3f02..3cd3eef2 100644 --- a/hooks/15_Context/tsconfig.json +++ b/hooks/15_Context/tsconfig.json @@ -8,7 +8,7 @@ "jsx": "react", "sourceMap": true, "noLib": false, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": false }, "compileOnSave": false, "exclude": ["node_modules"] diff --git a/hooks/15_Context/webpack.config.js b/hooks/15_Context/webpack.config.js index 32eff849..1d6fce31 100644 --- a/hooks/15_Context/webpack.config.js +++ b/hooks/15_Context/webpack.config.js @@ -1,63 +1,60 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const webpack = require("webpack"); -const path = require("path"); +var HtmlWebpackPlugin = require("html-webpack-plugin"); +var MiniCssExtractPlugin = require("mini-css-extract-plugin"); +var webpack = require("webpack"); +var path = require("path"); -const basePath = __dirname; +var basePath = __dirname; module.exports = { context: path.join(basePath, "src"), resolve: { - extensions: [".js", ".ts", ".tsx"], + extensions: [".js", ".ts", ".tsx"] }, entry: ["@babel/polyfill", "./index.tsx"], output: { path: path.join(basePath, "dist"), - filename: "bundle.js", + filename: "bundle.js" }, devtool: "source-map", devServer: { - contentBase: "./dist", // Content base - inline: true, // Enable watch and live reload - host: "localhost", - port: 8080, - stats: "errors-only", + // inline: true, // Enable watch and live reload + // host: "localhost", + // port: 8080, + // stats: "errors-only", + static: { + directory: "./dist", + } }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, - loader: "awesome-typescript-loader", - options: { - useBabel: true, - babelCore: "@babel/core", // needed for Babel v7 - }, + loader: "ts-loader", }, { test: /\.css$/, - use: [MiniCssExtractPlugin.loader, "css-loader"], + use: [MiniCssExtractPlugin.loader, "css-loader"] }, { test: /\.(png|jpg|gif|svg)$/, loader: "file-loader", options: { - name: "assets/img/[name].[ext]?[hash]", - esModule: false, - }, - }, - ], + name: "assets/img/[name].[ext]?[hash]" + } + } + ] }, plugins: [ //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: "index.html", //Name of file in ./dist/ template: "index.html", //Name of template in ./src - hash: true, + hash: true }), new MiniCssExtractPlugin({ filename: "[name].css", - chunkFilename: "[id].css", - }), - ], -}; + chunkFilename: "[id].css" + }) + ] +}; \ No newline at end of file diff --git a/readme.md b/readme.md index 9036f076..3a0f2539 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,7 @@ # React Typescript by sample +git init test + [🇪🇸 Versión Español](./readme_es.md) The goal of this project is to provide a set of simple samples, providing and step by step guide to @@ -122,7 +124,7 @@ Starting from sample 03,start using React-Router (SPA navigation). ### [13 Login Form](https://github.com/Lemoncode/react-typescript-samples/tree/master/hooks/13_LoginForm) -Starting from sample 12, implement a basic login page, that will redirect the user to another page whenever the login has completed successfully. +Starting from sample 12, implement a basic login page, that will redirect the user to another page whenever the login has completed successfully. ### [14 Form Validation](https://github.com/Lemoncode/react-typescript-samples/tree/master/hooks/14_FormValidation)