├── LICENSE.md ├── README.md ├── ch01 └── README.md ├── ch02 ├── hello.html ├── hello.py └── requirements.txt ├── ch03 ├── js_function.html ├── js_function.py └── requirements.txt ├── ch04 ├── mapping.html ├── mapping.py └── requirements.txt ├── ch05 ├── external_jq.html ├── external_jq.py └── requirements.txt ├── ch06 ├── react_hello.html ├── react_hello.py └── requirements.txt ├── ch07 └── README.md ├── ch08 ├── pyreact2.py ├── react_hello2.html ├── react_hello2.py └── requirements.txt ├── ch09 ├── package.json ├── pyreact3.py ├── react_hello3.html ├── react_hello3.py └── requirements.txt ├── ch10 ├── package.json ├── pyreact4.py ├── react_hello4.html ├── react_hello4.py └── requirements.txt ├── ch11 └── README.md ├── ch12 ├── app.py ├── index.html ├── package.json ├── pyreact.py └── requirements.txt ├── ch13 ├── app.py ├── app_v1.py ├── index.html ├── package.json ├── pyreact.py └── requirements.txt ├── ch14 ├── app.py ├── index.html ├── package.json ├── pyreact.py └── requirements.txt ├── ch15 ├── app.py ├── app_v1.py ├── app_v2.py ├── index.html ├── listItems.py ├── package.json ├── pyreact.py └── requirements.txt ├── ch16 ├── app.py ├── index.html ├── package.json ├── pyreact.py ├── requirements.txt └── todo.jsx ├── ch17 ├── app.css ├── app.py ├── app_v1.py ├── app_v2.py ├── app_v3.py ├── index.html ├── index_v1.html ├── index_v2.html ├── package.json ├── pyreact.py └── requirements.txt ├── ch18 ├── app.py ├── appTheme.py ├── appTheme_v1.py ├── app_v1.py ├── app_v2.py ├── index.html ├── package.json ├── pymui.py ├── pymui_v1.py ├── pymui_v2.py ├── pymui_v3.py ├── pyreact.py └── requirements.txt ├── ch19 ├── app.py ├── appTheme.py ├── dev-server.js ├── index.html ├── package.json ├── pymui.py ├── pyreact.py ├── requirements.txt └── webserver.py ├── ch20 ├── app.py ├── dev-server.js ├── index.html ├── jsutils.py ├── jsutils_v1.py ├── package.json ├── pymui.py ├── pyreact.py ├── requirements.txt └── webserver.py ├── ch21 ├── app.py ├── app_v1.py ├── dev-server.js ├── index.html ├── package.json ├── pymui.py ├── pyreact.py └── requirements.txt ├── ch22 └── jsutils.py ├── ch23 ├── package.json └── version.py ├── ch24 ├── app.py ├── dev-server.js ├── index.html ├── jsutils.py ├── package.json ├── pymui.py ├── pyreact.py ├── requirements.txt ├── version.py └── webserver.py ├── ch25 └── package.json └── ch26 └── README.md /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 John Sheehan 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## React to Python 2 | ### Part I & II Chapter Code 3 | 4 | This repository contains source code files for *React to Python* Part 1 and Part 2 5 | 6 | Source code for Part 3 of the book is in the [Project Repository](https://github.com/rtp-book/project) 7 | 8 | For information on the *React to Python* book itself, visit [https://pyreact.com](https://pyreact.com) 9 | -------------------------------------------------------------------------------- /ch01/README.md: -------------------------------------------------------------------------------- 1 | There are no code modules for Chapter 1. 2 | 3 | -------------------------------------------------------------------------------- /ch02/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /ch02/hello.py: -------------------------------------------------------------------------------- 1 | def say_hello(): 2 | document.getElementById('destination').innerHTML = "Hello World!" 3 | 4 | 5 | def clear_it(): 6 | document.getElementById('destination').innerHTML = "" 7 | -------------------------------------------------------------------------------- /ch02/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch03/js_function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 |
?
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch03/js_function.py: -------------------------------------------------------------------------------- 1 | def get_number(): 2 | new_val = int(window.Math.random() * 10) 3 | document.getElementById('myval').innerHTML = new_val 4 | 5 | -------------------------------------------------------------------------------- /ch03/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch04/mapping.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch04/mapping.py: -------------------------------------------------------------------------------- 1 | def print_stuff(): 2 | console.log("Native JS console.log call") 3 | print("Python print") 4 | console.invalid_method("This will be an error") 5 | 6 | -------------------------------------------------------------------------------- /ch04/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch05/external_jq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
    10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch05/external_jq.py: -------------------------------------------------------------------------------- 1 | # __pragma__ ('alias', 'jq', '$') 2 | 3 | def set_click(): 4 | def add_item(): 5 | jq("ol").append("
  1. List item
  2. ") 6 | 7 | jq("#append_btn").click(add_item) 8 | 9 | jq(document).ready(set_click) 10 | 11 | -------------------------------------------------------------------------------- /ch05/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch06/react_hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | 12 | 13 |
    14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ch06/react_hello.py: -------------------------------------------------------------------------------- 1 | def App(): 2 | val, setVal = React.useState("") 3 | 4 | def say_hello(): 5 | setVal("Hello React!") 6 | 7 | def clear_it(): 8 | setVal("") 9 | 10 | return [ 11 | React.createElement('button', {'onClick': say_hello}, "Click Me!"), 12 | React.createElement('button', {'onClick': clear_it}, "Clear"), 13 | React.createElement('div', None, val) 14 | ] 15 | 16 | def render(): 17 | ReactDOM.render( 18 | React.createElement(App, None), 19 | document.getElementById('root') 20 | ) 21 | 22 | document.addEventListener('DOMContentLoaded', render) 23 | 24 | -------------------------------------------------------------------------------- /ch06/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch07/README.md: -------------------------------------------------------------------------------- 1 | There are no code modules for Chapter 7. 2 | 3 | -------------------------------------------------------------------------------- /ch08/pyreact2.py: -------------------------------------------------------------------------------- 1 | # __pragma__('skip') 2 | # These are here to quiet the Python linter and are ignored by Transcrypt 3 | React = None 4 | ReactDOM = None 5 | document = None 6 | # __pragma__('noskip') 7 | 8 | # Map React javaScript objects to Python identifiers 9 | createElement = React.createElement 10 | useState = React.useState 11 | 12 | def render(root_component, props, container): 13 | """Loads main react component into DOM""" 14 | def main(): 15 | ReactDOM.render( 16 | React.createElement(root_component, props), 17 | document.getElementById(container) 18 | ) 19 | 20 | document.addEventListener('DOMContentLoaded', main) 21 | 22 | -------------------------------------------------------------------------------- /ch08/react_hello2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | 12 | 13 |
    14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ch08/react_hello2.py: -------------------------------------------------------------------------------- 1 | from pyreact2 import useState, render, createElement as el 2 | 3 | def App(): 4 | val, setVal = useState("") 5 | 6 | def say_hello(): 7 | setVal("Hello React!") 8 | 9 | def clear_it(): 10 | setVal("") 11 | 12 | return [ 13 | el('button', {'onClick': say_hello}, "Click Me!"), 14 | el('button', {'onClick': clear_it}, "Clear"), 15 | el('div', None, val) 16 | ] 17 | 18 | render(App, None, 'root') 19 | 20 | -------------------------------------------------------------------------------- /ch08/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch09/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch09", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "react": "^16.14.0", 14 | "react-dom": "^16.14.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ch09/pyreact3.py: -------------------------------------------------------------------------------- 1 | # __pragma__('skip') 2 | # These are here to quiet the Python linter and are ignored by Transcrypt 3 | window = None 4 | document = None 5 | # __pragma__('noskip') 6 | 7 | # Create local references to the React and ReactDOM JavaScript libraries 8 | React = window.React 9 | ReactDOM = window.ReactDOM 10 | 11 | # Remove the React and ReactDOM JavaScript libraries from the global namespace 12 | # __pragma__('js', 'delete window.React;') 13 | # __pragma__('js', 'delete window.ReactDOM;') 14 | 15 | # Map React javaScript objects to Python identifiers 16 | createElement = React.createElement 17 | useState = React.useState 18 | 19 | 20 | def render(root_component, props, container): 21 | """Loads main react component into DOM""" 22 | 23 | def main(): 24 | ReactDOM.render( 25 | React.createElement(root_component, props), 26 | document.getElementById(container) 27 | ) 28 | 29 | document.addEventListener('DOMContentLoaded', main) 30 | 31 | -------------------------------------------------------------------------------- /ch09/react_hello3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch09/react_hello3.py: -------------------------------------------------------------------------------- 1 | from pyreact3 import useState, render, createElement as el 2 | 3 | def App(): 4 | val, setVal = useState("") 5 | 6 | def say_hello(): 7 | setVal("Hello React!") 8 | 9 | def clear_it(): 10 | setVal("") 11 | 12 | return [ 13 | el('button', {'onClick': say_hello}, "Click Me!"), 14 | el('button', {'onClick': clear_it}, "Clear"), 15 | el('div', None, val) 16 | ] 17 | 18 | render(App, None, 'root') 19 | 20 | -------------------------------------------------------------------------------- /ch09/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch10/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch10", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 react_hello4.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build react_hello4.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch10/pyreact4.py: -------------------------------------------------------------------------------- 1 | # __pragma__('skip') 2 | # These are here to quiet the Python linter and are ignored by Transcrypt 3 | require = None 4 | document = None 5 | # __pragma__('noskip') 6 | 7 | # Load the React and ReactDOM JavaScript libraries into the local namespace 8 | React = require('react') 9 | ReactDOM = require('react-dom') 10 | 11 | # Map React javaScript objects to Python identifiers 12 | createElement = React.createElement 13 | useState = React.useState 14 | 15 | 16 | def render(root_component, props, container): 17 | """Loads main react component into DOM""" 18 | 19 | def main(): 20 | ReactDOM.render( 21 | React.createElement(root_component, props), 22 | document.getElementById(container) 23 | ) 24 | 25 | document.addEventListener('DOMContentLoaded', main) 26 | 27 | -------------------------------------------------------------------------------- /ch10/react_hello4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch10/react_hello4.py: -------------------------------------------------------------------------------- 1 | from pyreact4 import useState, render, createElement as el 2 | 3 | def App(): 4 | val, setVal = useState("") 5 | 6 | def say_hello(): 7 | setVal("Hello React!") 8 | 9 | def clear_it(): 10 | setVal("") 11 | 12 | return [ 13 | el('button', {'onClick': say_hello}, "Click Me!"), 14 | el('button', {'onClick': clear_it}, "Clear"), 15 | el('div', None, val) 16 | ] 17 | 18 | render(App, None, 'root') 19 | -------------------------------------------------------------------------------- /ch10/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch11/README.md: -------------------------------------------------------------------------------- 1 | There are no code modules for Chapter 11. 2 | 3 | -------------------------------------------------------------------------------- /ch12/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import alert, useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | 6 | def handleSubmit(): 7 | alert(f"Item is : {newItem}") 8 | setNewItem("") 9 | 10 | def handleChange(event): 11 | target = event['target'] 12 | setNewItem(target['value']) 13 | 14 | return el('div', None, 15 | el('label', {'htmlFor': 'editBox'}, "New Item: "), 16 | el('input', {'id': 'editBox', 17 | 'onChange': handleChange, 18 | 'value': newItem 19 | } 20 | ), 21 | el('button', {'onClick': handleSubmit}, "Submit"), 22 | ) 23 | 24 | render(App, None, 'root') 25 | -------------------------------------------------------------------------------- /ch12/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch12", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch12/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | 9 | 10 | def render(root_component, props, container): 11 | def main(): 12 | ReactDOM.render( 13 | React.createElement(root_component, props), 14 | document.getElementById(container) 15 | ) 16 | 17 | document.addEventListener('DOMContentLoaded', main) 18 | 19 | 20 | # JavaScript function mappings 21 | alert = window.alert 22 | -------------------------------------------------------------------------------- /ch12/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch13/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | listItems, setListItems = useState([]) 6 | 7 | def handleSubmit(): 8 | new_list = list(listItems) # Make a copy 9 | new_list.append(newItem) # Add the new item 10 | setListItems(new_list) # Update our state 11 | setNewItem("") # Clear the new item value 12 | 13 | def handleChange(event): 14 | target = event['target'] 15 | setNewItem(target['value']) 16 | 17 | def ListItems(): 18 | items = [] 19 | for item in listItems: 20 | element = el('li', {'key': item}, item) 21 | items.append(element) 22 | 23 | return items 24 | 25 | return el('div', None, 26 | el('label', {'htmlFor': 'editBox'}, "New Item: "), 27 | el('input', {'id': 'editBox', 28 | 'onChange': handleChange, 29 | 'value': newItem 30 | } 31 | ), 32 | el('button', {'onClick': handleSubmit}, "Submit"), 33 | el('ol', None, 34 | el(ListItems, None) 35 | ), 36 | ) 37 | 38 | render(App, None, 'root') 39 | 40 | -------------------------------------------------------------------------------- /ch13/app_v1.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | listItems, setListItems = useState([]) 6 | 7 | def handleSubmit(): 8 | new_list = list(listItems) # Make a copy 9 | new_list.append(newItem) # Add the new item 10 | setListItems(new_list) # Update our state 11 | setNewItem("") # Clear the new item value 12 | 13 | def handleChange(event): 14 | target = event['target'] 15 | setNewItem(target['value']) 16 | 17 | def getListItems(): 18 | items = [] 19 | for item in listItems: 20 | element = el('li', {'key': item}, item) 21 | items.append(element) 22 | 23 | return items 24 | 25 | return el('div', None, 26 | el('label', {'htmlFor': 'editBox'}, "New Item: "), 27 | el('input', {'id': 'editBox', 28 | 'onChange': handleChange, 29 | 'value': newItem 30 | } 31 | ), 32 | el('button', {'onClick': handleSubmit}, "Submit"), 33 | el('ol', None, getListItems()), 34 | ) 35 | 36 | render(App, None, 'root') 37 | 38 | -------------------------------------------------------------------------------- /ch13/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch13", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch13/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | 9 | 10 | def render(root_component, props, container): 11 | def main(): 12 | ReactDOM.render( 13 | React.createElement(root_component, props), 14 | document.getElementById(container) 15 | ) 16 | 17 | document.addEventListener('DOMContentLoaded', main) 18 | 19 | 20 | # JavaScript function mappings 21 | alert = window.alert 22 | -------------------------------------------------------------------------------- /ch13/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch14/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | listItems, setListItems = useState([]) 6 | 7 | def handleSubmit(event): 8 | event.preventDefault() 9 | new_list = list(listItems) # Make a copy 10 | new_list.append(newItem) # Add the new item 11 | setListItems(new_list) # Update our state 12 | setNewItem("") # Clear the new item value 13 | 14 | def handleChange(event): 15 | target = event['target'] 16 | setNewItem(target['value']) 17 | 18 | def ListItems(): 19 | items = [] 20 | for item in listItems: 21 | element = el('li', {'key': item}, item) 22 | items.append(element) 23 | 24 | return items 25 | 26 | return el('form', {'onSubmit': handleSubmit}, 27 | el('label', {'htmlFor': 'editBox'}, "New Item: "), 28 | el('input', {'id': 'editBox', 29 | 'onChange': handleChange, 30 | 'value': newItem 31 | } 32 | ), 33 | el('input', {'type': 'submit'}), 34 | el('ol', None, 35 | el(ListItems, None) 36 | ), 37 | ) 38 | 39 | render(App, None, 'root') 40 | 41 | -------------------------------------------------------------------------------- /ch14/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch14/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch14", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch14/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | 9 | 10 | def render(root_component, props, container): 11 | def main(): 12 | ReactDOM.render( 13 | React.createElement(root_component, props), 14 | document.getElementById(container) 15 | ) 16 | 17 | document.addEventListener('DOMContentLoaded', main) 18 | 19 | 20 | # JavaScript function mappings 21 | alert = window.alert 22 | -------------------------------------------------------------------------------- /ch14/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch15/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | from listItems import ListItems 3 | 4 | def App(): 5 | newItem, setNewItem = useState("") 6 | editItem, setEditItem = useState("") 7 | listItems, setListItems = useState([]) 8 | 9 | def handleSubmit(event): 10 | event.preventDefault() 11 | new_list = list(listItems) # Make a copy 12 | if len(editItem) > 0: # In edit mode 13 | new_list[new_list.index(editItem)] = newItem 14 | else: # In add mode 15 | new_list.append(newItem) # Add the new item 16 | setListItems(new_list) # Update our state 17 | setNewItem("") # Clear the new item value 18 | setEditItem("") # Clear the edit item value 19 | 20 | def handleChange(event): 21 | target = event['target'] 22 | setNewItem(target['value']) 23 | 24 | def handleDelete(item): 25 | new_list = list(listItems) # Make a copy 26 | new_list.remove(item) # Remove the specified item 27 | setListItems(new_list) # Update our state 28 | 29 | def handleEdit(item): 30 | setNewItem(item) # Set the new item value 31 | setEditItem(item) # Set the edit item value 32 | 33 | return el('form', {'onSubmit': handleSubmit}, 34 | el('label', {'htmlFor': 'editBox'}, 35 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 36 | ), 37 | el('input', {'id': 'editBox', 38 | 'onChange': handleChange, 39 | 'value': newItem 40 | } 41 | ), 42 | el('input', {'type': 'submit'}), 43 | el('ol', None, 44 | el(ListItems, {'listItems': listItems, 45 | 'handleDelete': handleDelete, 46 | 'handleEdit': handleEdit} 47 | ) 48 | ), 49 | ) 50 | 51 | render(App, None, 'root') 52 | 53 | -------------------------------------------------------------------------------- /ch15/app_v1.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | listItems, setListItems = useState([]) 6 | 7 | def handleSubmit(event): 8 | event.preventDefault() 9 | new_list = list(listItems) # Make a copy 10 | new_list.append(newItem) # Add the new item 11 | setListItems(new_list) # Update our state 12 | setNewItem("") # Clear the new item value 13 | 14 | def handleChange(event): 15 | target = event['target'] 16 | setNewItem(target['value']) 17 | 18 | def handleDelete(item): 19 | new_list = list(listItems) # Make a copy 20 | new_list.remove(item) # Remove the specified item 21 | setListItems(new_list) # Update our state 22 | 23 | def ListItem(props): 24 | return el('li', None, 25 | props['item'] + " ", 26 | el('button', {'type': 'button', 27 | 'onClick': lambda: handleDelete(props['item']) 28 | }, "Delete"), 29 | ) 30 | 31 | def ListItems(): 32 | items = [] 33 | for item in listItems: 34 | items.append(el(ListItem, {'key': item, 'item': item})) 35 | return items 36 | 37 | return el('form', {'onSubmit': handleSubmit}, 38 | el('label', {'htmlFor': 'editBox'}, "New Item: "), 39 | el('input', {'id': 'editBox', 40 | 'onChange': handleChange, 41 | 'value': newItem 42 | } 43 | ), 44 | el('input', {'type': 'submit'}), 45 | el('ol', None, 46 | el(ListItems, None) 47 | ), 48 | ) 49 | 50 | render(App, None, 'root') 51 | 52 | -------------------------------------------------------------------------------- /ch15/app_v2.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | editItem, setEditItem = useState("") 6 | listItems, setListItems = useState([]) 7 | 8 | def handleSubmit(event): 9 | event.preventDefault() 10 | new_list = list(listItems) # Make a copy 11 | if len(editItem) > 0: # In edit mode 12 | new_list[new_list.index(editItem)] = newItem 13 | else: # In add mode 14 | new_list.append(newItem) # Add the new item 15 | setListItems(new_list) # Update our state 16 | setNewItem("") # Clear the new item value 17 | setEditItem("") # Clear the edit item value 18 | 19 | def handleChange(event): 20 | target = event['target'] 21 | setNewItem(target['value']) 22 | 23 | def handleDelete(item): 24 | new_list = list(listItems) # Make a copy 25 | new_list.remove(item) # Remove the specified item 26 | setListItems(new_list) # Update our state 27 | 28 | def handleEdit(item): 29 | setNewItem(item) # Set the new item value 30 | setEditItem(item) # Set the edit item value 31 | 32 | def ListItem(props): 33 | return el('li', None, 34 | props['item'] + " ", 35 | el('button', {'type': 'button', 36 | 'onClick': lambda: handleDelete(props['item']) 37 | }, "Delete" 38 | ), 39 | el('button', {'type': 'button', 40 | 'onClick': lambda: handleEdit(props['item']) 41 | }, "Edit" 42 | ), 43 | ) 44 | 45 | def ListItems(): 46 | return [el(ListItem, {'key': item, 'item': item}) for item in listItems] 47 | 48 | return el('form', {'onSubmit': handleSubmit}, 49 | el('label', {'htmlFor': 'editBox'}, 50 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 51 | ), 52 | el('input', {'id': 'editBox', 53 | 'onChange': handleChange, 54 | 'value': newItem 55 | } 56 | ), 57 | el('input', {'type': 'submit'}), 58 | el('ol', None, 59 | el(ListItems, None) 60 | ), 61 | ) 62 | 63 | render(App, None, 'root') 64 | 65 | -------------------------------------------------------------------------------- /ch15/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch15/listItems.py: -------------------------------------------------------------------------------- 1 | from pyreact import createElement as el 2 | 3 | def ListItem(props): 4 | item = props['item'] 5 | handleDelete = props['handleDelete'] 6 | handleEdit = props['handleEdit'] 7 | 8 | return el('li', None, 9 | props['item'] + " ", 10 | el('button', {'type': 'button', 11 | 'onClick': lambda: handleDelete(item) 12 | }, "Delete" 13 | ), 14 | el('button', {'type': 'button', 15 | 'onClick': lambda: handleEdit(item) 16 | }, "Edit" 17 | ), 18 | ) 19 | 20 | def ListItems(props): 21 | return [el(ListItem, {'key': item, 22 | 'item': item, 23 | 'handleDelete': props['handleDelete'], 24 | 'handleEdit': props['handleEdit'] 25 | } 26 | ) for item in props['listItems']] 27 | 28 | -------------------------------------------------------------------------------- /ch15/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch15", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch15/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | 9 | 10 | def render(root_component, props, container): 11 | def main(): 12 | ReactDOM.render( 13 | React.createElement(root_component, props), 14 | document.getElementById(container) 15 | ) 16 | 17 | document.addEventListener('DOMContentLoaded', main) 18 | 19 | 20 | # JavaScript function mappings 21 | alert = window.alert 22 | -------------------------------------------------------------------------------- /ch15/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch16/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import setTitle, useEffect, useState, render, createElement as el 2 | 3 | def App(): 4 | newTask, setNewTask = useState("") 5 | editTask, setEditTask = useState(None) 6 | taskList, setTaskList = useState([]) 7 | taskCount, setTaskCount = useState(0) 8 | taskFilter, setTaskFilter = useState("all") 9 | 10 | def handleSubmit(event): 11 | event.preventDefault() 12 | new_list = list(taskList) # Make a copy 13 | if editTask is not None: # In edit mode 14 | taskIndex = new_list.index(editTask) # Get list position 15 | new_list[taskIndex].update({'name': newTask}) # Update name 16 | else: # In add mode 17 | new_list.append({'name': newTask, 'status': False}) # Add new item 18 | setTaskList(new_list) # Update our state 19 | setNewTask("") # Clear the new item value 20 | setEditTask(None) # Clear the edit item value 21 | 22 | def handleEdit(task): 23 | setNewTask(task['name']) # Set the new item value 24 | setEditTask(task) # Set the edit item value 25 | 26 | def handleDelete(task): 27 | new_list = list(taskList) # Make a copy 28 | new_list.remove(task) # Remove the specified item 29 | setTaskList(new_list) # Update our state 30 | 31 | def handleChange(event): 32 | target = event['target'] 33 | if target['name'] == 'taskFilter': 34 | setTaskFilter(target['value']) 35 | else: 36 | setNewTask(target['value']) 37 | 38 | def handleChangeStatus(event, task): 39 | target = event['target'] 40 | new_list = list(taskList) # Make a copy 41 | taskIndex = new_list.index(task) # Get list position 42 | new_list[taskIndex].update({'status': target['checked']}) # Update 43 | setTaskList(new_list) # Update our state 44 | 45 | def ListItem(props): 46 | task = props['task'] 47 | if taskFilter == "all" or \ 48 | (taskFilter == "open" and not task['status']) or \ 49 | (taskFilter == "closed" and task['status']): 50 | return el('li', None, 51 | task['name'] + " ", 52 | el('button', 53 | {'type': 'button', 54 | 'onClick': lambda: handleDelete(task) 55 | }, "Delete" 56 | ), 57 | el('button', 58 | {'type': 'button', 59 | 'onClick': lambda: handleEdit(task) 60 | }, "Edit" 61 | ), 62 | el('label', {'htmlFor': 'status'}, " Completed:"), 63 | el('input', 64 | {'type': 'checkbox', 65 | 'id': 'status', 66 | 'onChange': lambda e: handleChangeStatus(e, task), 67 | 'checked': task['status'] 68 | } 69 | ), 70 | ) 71 | else: 72 | return None 73 | 74 | def ListItems(): 75 | return [el(ListItem, {'key': task['name'], 'task': task}) for task in taskList] 76 | 77 | def updateCount(): 78 | if taskFilter == 'open': 79 | new_list = [task for task in taskList if not task['status']] 80 | elif taskFilter == 'closed': 81 | new_list = [task for task in taskList if task['status']] 82 | else: 83 | new_list = [task for task in taskList] 84 | 85 | setTaskCount(len(new_list)) 86 | 87 | useEffect(lambda: setTitle("ToDo List"), []) 88 | useEffect(updateCount, [taskList, taskFilter]) 89 | 90 | return el('form', {'onSubmit': handleSubmit}, 91 | el('div', None, f"Number of Tasks: {taskCount}"), 92 | el('div', None, 93 | el('label', {'htmlFor': 'all'}, "All Tasks:"), 94 | el('input', {'type': 'radio', 95 | 'name': 'taskFilter', 96 | 'id': 'all', 97 | 'value': 'all', 98 | 'onChange': handleChange, 99 | 'checked': taskFilter == 'all' 100 | } 101 | ), 102 | el('label', {'htmlFor': 'open'}, " Active:"), 103 | el('input', {'type': 'radio', 104 | 'name': 'taskFilter', 105 | 'id': 'open', 106 | 'value': 'open', 107 | 'onChange': handleChange, 108 | 'checked': taskFilter == 'open' 109 | } 110 | ), 111 | el('label', {'htmlFor': 'closed'}, " Completed:"), 112 | el('input', {'type': 'radio', 113 | 'name': 'taskFilter', 114 | 'id': 'closed', 115 | 'value': 'closed', 116 | 'onChange': handleChange, 117 | 'checked': taskFilter == 'closed' 118 | } 119 | ), 120 | ), 121 | el('label', {'htmlFor': 'editBox'}, 122 | "Edit Task: " if editTask is not None else "Add Task: " 123 | ), 124 | el('input', {'id': 'editBox', 125 | 'onChange': handleChange, 126 | 'value': newTask 127 | } 128 | ), 129 | el('input', {'type': 'submit'}), 130 | el('ol', None, 131 | el(ListItems, None) 132 | ), 133 | ) 134 | 135 | render(App, None, 'root') 136 | 137 | -------------------------------------------------------------------------------- /ch16/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch16/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch17", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch16/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | 10 | 11 | def render(root_component, props, container): 12 | def main(): 13 | ReactDOM.render( 14 | React.createElement(root_component, props), 15 | document.getElementById(container) 16 | ) 17 | 18 | document.addEventListener('DOMContentLoaded', main) 19 | 20 | 21 | # JavaScript function mappings 22 | alert = window.alert 23 | 24 | 25 | def setTitle(title): 26 | document.title = title 27 | 28 | -------------------------------------------------------------------------------- /ch16/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch16/todo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | class App extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | newTask: "", 9 | editTask: null, 10 | taskList: Array(), 11 | taskCount: 0, 12 | taskFilter: "all" 13 | }; 14 | } 15 | 16 | handleSubmit = (event) => { 17 | event.preventDefault(); 18 | const taskList = this.state.taskList.slice(); 19 | if (this.state.editTask) { 20 | const taskIndex = taskList.findIndex( 21 | (task => task.name === this.state.editTask.name) 22 | ); 23 | taskList[taskIndex].name = this.state.newTask; 24 | } else { 25 | taskList.push({name: this.state.newTask, status: false}); 26 | } 27 | this.setState({newTask: "", editTask: null, taskList: taskList}); 28 | } 29 | 30 | 31 | handleEdit = (task) => { 32 | this.setState({newTask: task.name, editTask: task}); 33 | } 34 | 35 | handleDelete = (task) => { 36 | const taskList = this.state.taskList.filter(function (item) { 37 | return item.name !== task.name; 38 | }); 39 | this.setState({taskList: taskList}); 40 | } 41 | 42 | handleChange = (event) => { 43 | if (event.target.name === "taskFilter") { 44 | this.setState({taskFilter: event.target.value}); 45 | } else { 46 | this.setState({newTask: event.target.value}); 47 | } 48 | } 49 | 50 | handleChangeStatus = (event, task) => { 51 | const taskList = this.state.taskList.slice(); 52 | const taskIndex = taskList.findIndex((item => item.name === task.name)); 53 | taskList[taskIndex].status = event.target.checked; 54 | this.setState({taskList: taskList}); 55 | } 56 | 57 | renderTask = (task) => { 58 | const taskFilter = this.state.taskFilter 59 | if (taskFilter === "all" || 60 | (taskFilter === "open" && !task.status) || 61 | (taskFilter === "closed" && task.status) 62 | ) { 63 | return ( 64 |
  3. {task.name} 65 | 70 | 75 | 76 | this.handleChangeStatus(event, task)} 79 | checked={task.status} 80 | /> 81 |
  4. 82 | ); 83 | } else { 84 | return null 85 | } 86 | 87 | } 88 | 89 | updateCount() { 90 | let taskList 91 | switch (this.state.taskFilter) { 92 | case "open": 93 | taskList = this.state.taskList.filter((task => !task.status)); 94 | break; 95 | case "closed": 96 | taskList = this.state.taskList.filter((task => task.status)); 97 | break; 98 | default: 99 | taskList = this.state.taskList.slice(); 100 | } 101 | 102 | const taskCount = taskList.length; 103 | this.setState({taskCount: taskCount}) 104 | } 105 | 106 | componentDidMount() { 107 | document.title = "ToDo List"; 108 | } 109 | 110 | componentDidUpdate(prevProps, prevState) { 111 | if (prevState.taskList !== this.state.taskList || 112 | prevState.taskFilter !== this.state.taskFilter 113 | ) { 114 | this.updateCount(); 115 | } 116 | } 117 | 118 | render() { 119 | const taskFilter = this.state.taskFilter; 120 | return ( 121 |
    122 |
    Number of Tasks: {this.state.taskCount}
    123 |
    124 | 125 | 132 | 133 | 140 | 141 | 148 |
    149 | 152 | 156 | 157 |
      158 | {this.state.taskList.map(this.renderTask)} 159 |
    160 |
    161 | ); 162 | } 163 | } 164 | 165 | ReactDOM.render(, document.getElementById('root')); 166 | 167 | -------------------------------------------------------------------------------- /ch17/app.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-family: Arial, sans-serif; 3 | } 4 | .submitBtn { 5 | margin: 10px; 6 | color: darkgreen; 7 | width: 60px; 8 | } 9 | .deleteBtn { 10 | color: darkred; 11 | } 12 | .editBtn { 13 | color: blue; 14 | } 15 | button { 16 | margin-right: 5px; 17 | width: 60px; 18 | } 19 | .editing { 20 | color: blue; 21 | } 22 | .adding { 23 | color: darkgreen; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ch17/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | editItem, setEditItem = useState("") 6 | listItems, setListItems = useState([]) 7 | 8 | def handleSubmit(event): 9 | event.preventDefault() 10 | new_list = list(listItems) # Make a copy 11 | if len(editItem) > 0: # In edit mode 12 | new_list[new_list.index(editItem)] = newItem 13 | else: # In add mode 14 | new_list.append(newItem) # Add the new item 15 | setListItems(new_list) # Update our state 16 | setNewItem("") # Clear the new item value 17 | setEditItem("") # Clear the edit item value 18 | 19 | def handleChange(event): 20 | target = event['target'] 21 | setNewItem(target['value']) 22 | 23 | def handleDelete(item): 24 | new_list = list(listItems) # Make a copy 25 | new_list.remove(item) # Remove the specified item 26 | setListItems(new_list) # Update our state 27 | 28 | def handleEdit(item): 29 | setNewItem(item) # Set the new item value 30 | setEditItem(item) # Set the edit item value 31 | 32 | def ListItem(props): 33 | return el('li', {'className': 'list-group-item p-1'}, 34 | el('button', 35 | {'onClick': lambda: handleDelete(props['item']), 36 | 'className': 'btn btn-danger btn-sm mr-2' 37 | }, 38 | "Delete" 39 | ), 40 | el('button', 41 | {'onClick': lambda: handleEdit(props['item']), 42 | 'className': 'btn btn-primary btn-sm mr-2' 43 | }, 44 | "Edit" 45 | ), 46 | props['item'], 47 | ) 48 | 49 | def ListItems(): 50 | return [el(ListItem, {'key': item, 'item': item}) for item in listItems] 51 | 52 | if len(editItem) == 0: 53 | editClass = 'text-success' 54 | else: 55 | editClass = 'text-primary' 56 | 57 | return el('div', {'className': 'container m-1'}, 58 | el('form', {'onSubmit': handleSubmit, 59 | 'className': 'form-inline col-10 my-2' 60 | }, 61 | el('label', 62 | {'htmlFor': 'editBox', 'className': editClass}, 63 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 64 | ), 65 | el('input', {'id': 'editBox', 66 | 'onChange': handleChange, 67 | 'value': newItem, 68 | 'className': 'form-control ml-2' 69 | } 70 | ), 71 | el('input', {'type': 'submit', 72 | 'className': 'btn btn-success ml-2' 73 | } 74 | ), 75 | ), 76 | el('ul', {'className': 'list-group col-10 ml-2'}, 77 | el(ListItems, None) 78 | ), 79 | ) 80 | 81 | render(App, None, 'root') 82 | 83 | -------------------------------------------------------------------------------- /ch17/app_v1.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | editItem, setEditItem = useState("") 6 | listItems, setListItems = useState([]) 7 | 8 | def handleSubmit(event): 9 | event.preventDefault() 10 | new_list = list(listItems) # Make a copy 11 | if len(editItem) > 0: # In edit mode 12 | new_list[new_list.index(editItem)] = newItem 13 | else: # In add mode 14 | new_list.append(newItem) # Add the new item 15 | setListItems(new_list) # Update our state 16 | setNewItem("") # Clear the new item value 17 | setEditItem("") # Clear the edit item value 18 | 19 | def handleChange(event): 20 | target = event['target'] 21 | setNewItem(target['value']) 22 | 23 | def handleDelete(item): 24 | new_list = list(listItems) # Make a copy 25 | new_list.remove(item) # Remove the specified item 26 | setListItems(new_list) # Update our state 27 | 28 | def handleEdit(item): 29 | setNewItem(item) # Set the new item value 30 | setEditItem(item) # Set the edit item value 31 | 32 | def ListItem(props): 33 | return el('li', None, 34 | el('button', {'type': 'button', 35 | 'onClick': lambda: handleDelete(props['item']), 36 | 'className': 'deleteBtn' 37 | }, "Delete" 38 | ), 39 | el('button', {'type': 'button', 40 | 'onClick': lambda: handleEdit(props['item']), 41 | 'className': 'editBtn' 42 | }, "Edit" 43 | ), 44 | props['item'], 45 | ) 46 | 47 | def ListItems(): 48 | return [el(ListItem, {'key': item, 'item': item}) for item in listItems] 49 | 50 | return el('form', {'onSubmit': handleSubmit}, 51 | el('label', 52 | {'htmlFor': 'editBox', 53 | 'className': 'adding' if len(editItem) == 0 else 'editing' 54 | }, 55 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 56 | ), 57 | el('input', {'id': 'editBox', 58 | 'onChange': handleChange, 59 | 'value': newItem 60 | } 61 | ), 62 | el('input', {'type': 'submit', 'className': 'submitBtn'}), 63 | el('ol', None, 64 | el(ListItems, None) 65 | ), 66 | ) 67 | 68 | render(App, None, 'root') 69 | 70 | -------------------------------------------------------------------------------- /ch17/app_v2.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | editItem, setEditItem = useState("") 6 | listItems, setListItems = useState([]) 7 | 8 | def handleSubmit(event): 9 | event.preventDefault() 10 | new_list = list(listItems) # Make a copy 11 | if len(editItem) > 0: # In edit mode 12 | new_list[new_list.index(editItem)] = newItem 13 | else: # In add mode 14 | new_list.append(newItem) # Add the new item 15 | setListItems(new_list) # Update our state 16 | setNewItem("") # Clear the new item value 17 | setEditItem("") # Clear the edit item value 18 | 19 | def handleChange(event): 20 | target = event['target'] 21 | setNewItem(target['value']) 22 | 23 | def handleDelete(item): 24 | new_list = list(listItems) # Make a copy 25 | new_list.remove(item) # Remove the specified item 26 | setListItems(new_list) # Update our state 27 | 28 | def handleEdit(item): 29 | setNewItem(item) # Set the new item value 30 | setEditItem(item) # Set the edit item value 31 | 32 | def ListItem(props): 33 | return el('li', None, 34 | el('button', { 35 | 'type': 'button', 36 | 'onClick': lambda: handleDelete(props['item']), 37 | 'style': {'color': 'darkred', 38 | 'marginRight': '5px', 39 | 'width': '60px' 40 | } 41 | }, "Delete" 42 | ), 43 | el('button', { 44 | 'type': 'button', 45 | 'onClick': lambda: handleEdit(props['item']), 46 | 'style': {'color': 'blue', 47 | 'marginRight': '5px', 48 | 'width': '60px' 49 | } 50 | }, "Edit" 51 | ), 52 | props['item'], 53 | ) 54 | 55 | def ListItems(): 56 | return [el(ListItem, {'key': item, 'item': item}) for item in listItems] 57 | 58 | if len(editItem) == 0: 59 | editStyle = {'color': 'darkgreen'} 60 | else: 61 | editStyle = {'color': 'blue'} 62 | 63 | return el('form', {'onSubmit': handleSubmit, 64 | 'style': {'fontFamily': 'Arial, sans-serif'} 65 | }, 66 | el('label', 67 | {'htmlFor': 'editBox', 'style': editStyle}, 68 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 69 | ), 70 | el('input', {'id': 'editBox', 71 | 'onChange': handleChange, 72 | 'value': newItem 73 | } 74 | ), 75 | el('input', {'type': 'submit', 76 | 'style': {'margin': '10px', 77 | 'color': 'darkgreen', 78 | 'width': '60px' 79 | } 80 | } 81 | ), 82 | el('ol', None, 83 | el(ListItems, None) 84 | ), 85 | ) 86 | 87 | render(App, None, 'root') 88 | 89 | -------------------------------------------------------------------------------- /ch17/app_v3.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | 3 | def App(): 4 | newItem, setNewItem = useState("") 5 | editItem, setEditItem = useState("") 6 | listItems, setListItems = useState([]) 7 | 8 | def handleSubmit(event): 9 | event.preventDefault() 10 | new_list = list(listItems) # Make a copy 11 | if len(editItem) > 0: # In edit mode 12 | new_list[new_list.index(editItem)] = newItem 13 | else: # In add mode 14 | new_list.append(newItem) # Add the new item 15 | setListItems(new_list) # Update our state 16 | setNewItem("") # Clear the new item value 17 | setEditItem("") # Clear the edit item value 18 | 19 | def handleChange(event): 20 | target = event['target'] 21 | setNewItem(target['value']) 22 | 23 | def handleDelete(item): 24 | new_list = list(listItems) # Make a copy 25 | new_list.remove(item) # Remove the specified item 26 | setListItems(new_list) # Update our state 27 | 28 | def handleEdit(item): 29 | setNewItem(item) # Set the new item value 30 | setEditItem(item) # Set the edit item value 31 | 32 | def Button(props): 33 | new_props = {'type': 'button'} 34 | new_props.update(props) 35 | new_style = new_props.pop('style', {}) 36 | new_style.update({'marginRight': '5px', 'width': '60px'}) 37 | new_props.update({'style': new_style}) 38 | return el('button', new_props) 39 | 40 | def ListItem(props): 41 | return el('li', None, 42 | el(Button, 43 | {'onClick': lambda: handleDelete(props['item']), 44 | 'style': {'color': 'darkred'} 45 | }, 46 | "Delete" 47 | ), 48 | el(Button, 49 | {'onClick': lambda: handleEdit(props['item']), 50 | 'style': {'color': 'blue'} 51 | }, 52 | "Edit" 53 | ), 54 | props['item'], 55 | ) 56 | 57 | def ListItems(): 58 | return [el(ListItem, {'key': item, 'item': item}) for item in listItems] 59 | 60 | if len(editItem) == 0: 61 | editStyle = {'color': 'darkgreen'} 62 | else: 63 | editStyle = {'color': 'blue'} 64 | 65 | return el('form', {'onSubmit': handleSubmit, 66 | 'style': {'fontFamily': 'Arial, sans-serif'} 67 | }, 68 | el('label', 69 | {'htmlFor': 'editBox', 'style': editStyle}, 70 | "Add Item: " if len(editItem) == 0 else "Edit Item: " 71 | ), 72 | el('input', {'id': 'editBox', 73 | 'onChange': handleChange, 74 | 'value': newItem 75 | } 76 | ), 77 | el('input', {'type': 'submit', 78 | 'style': {'margin': '10px', 79 | 'color': 'darkgreen', 80 | 'width': '60px' 81 | } 82 | } 83 | ), 84 | el('ol', None, 85 | el(ListItems, None) 86 | ), 87 | ) 88 | 89 | render(App, None, 'root') 90 | 91 | 92 | -------------------------------------------------------------------------------- /ch17/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 |
    11 | 12 | 13 | -------------------------------------------------------------------------------- /ch17/index_v1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ch17/index_v2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch17/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch18", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "react": "^16.14.0", 16 | "react-dom": "^16.14.0" 17 | }, 18 | "devDependencies": { 19 | "parcel-bundler": "^1.12.4", 20 | "parcel-plugin-transcrypt": "^1.0.20" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch17/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | 10 | 11 | def render(root_component, props, container): 12 | def main(): 13 | ReactDOM.render( 14 | React.createElement(root_component, props), 15 | document.getElementById(container) 16 | ) 17 | 18 | document.addEventListener('DOMContentLoaded', main) 19 | 20 | 21 | # JavaScript function mappings 22 | alert = window.alert 23 | 24 | 25 | def setTitle(title): 26 | document.title = title 27 | 28 | -------------------------------------------------------------------------------- /ch17/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch18/app.py: -------------------------------------------------------------------------------- 1 | from appTheme import theme, useStyle, ListButton, StyledButton 2 | from pyreact import useState, render, createElement as el 3 | from pymui import Button, List, ListItem, Typography, Box, TextField 4 | from pymui import Paper, Container, AppBar, ThemeProvider, useTheme 5 | 6 | def App(): 7 | newItem, setNewItem = useState("") 8 | editItem, setEditItem = useState("") 9 | listItems, setListItems = useState([]) 10 | 11 | def handleSubmit(event): 12 | event.preventDefault() 13 | new_list = list(listItems) # Make a copy 14 | if len(editItem) > 0: # In edit mode 15 | new_list[new_list.index(editItem)] = newItem 16 | else: # In add mode 17 | new_list.append(newItem) # Add the new item 18 | setListItems(new_list) # Update our state 19 | setNewItem("") # Clear the new item value 20 | setEditItem("") # Clear the edit item value 21 | 22 | def handleChange(event): 23 | target = event['target'] 24 | setNewItem(target['value']) 25 | 26 | def handleDelete(item): 27 | new_list = list(listItems) # Make a copy 28 | new_list.remove(item) # Remove the specified item 29 | setListItems(new_list) # Update our state 30 | 31 | def handleEdit(item): 32 | setNewItem(item) # Set the new item value 33 | setEditItem(item) # Set the edit item value 34 | 35 | def ItemVu(props): 36 | item = props['item'] 37 | theme = useTheme() 38 | specialColor = theme['palette']['special']['main'] 39 | classes = useStyle({'bgcolor': specialColor}) 40 | 41 | return el(ListItem, {'dense': True}, 42 | el(Button, 43 | {'color': 'secondary', 44 | 'className': classes.root, 45 | 'onClick': lambda: handleDelete(item) 46 | }, 47 | el('span', {'className': 'material-icons'}, 'delete'), 48 | "Delete" 49 | ), 50 | el(StyledButton, 51 | {'color': 'primary', 52 | 'onClick': lambda: handleEdit(item) 53 | }, 54 | el('span', {'className': 'material-icons'}, 'edit'), 55 | "Edit" 56 | ), 57 | el(Typography, {'style': {'color': specialColor}}, item) 58 | ) 59 | 60 | def ListItemsVu(): 61 | return [el(ItemVu, {'key': item, 'item': item}) for item in listItems] 62 | 63 | if len(editItem) == 0: 64 | editColor = 'secondary' 65 | editLabel = "Add Item:" 66 | else: 67 | editColor = 'primary' 68 | editLabel = "Edit Item:" 69 | 70 | return el(ThemeProvider, {'theme': theme}, 71 | el(Container, {'maxWidth': 'sm'}, 72 | el(AppBar, {'position': 'static', 73 | 'style': {'marginBottom': '0.5rem'} 74 | }, 75 | el(Box, {'width': '100%', 'marginLeft': '0.5rem'}, 76 | el(Typography, {'variant': 'h6'}, "React to Python") 77 | ) 78 | ), 79 | el(Paper, {'elevation': 2}, 80 | el('form', {'onSubmit': handleSubmit, 81 | 'style': {'marginLeft': '1rem'} 82 | }, 83 | el(TextField, {'InputLabelProps': {'color': editColor}, 84 | 'label': editLabel, 85 | 'value': newItem, 86 | 'onChange': handleChange, 87 | 'autoFocus': True 88 | } 89 | ), 90 | el(Button, {'type': 'submit', 91 | 'size': 'medium' 92 | }, "Submit"), 93 | ), 94 | el(List, None, 95 | el(ListItemsVu, None) 96 | ), 97 | ) 98 | ) 99 | ) 100 | 101 | render(App, None, 'root') 102 | 103 | -------------------------------------------------------------------------------- /ch18/appTheme.py: -------------------------------------------------------------------------------- 1 | from pymui import createMuiTheme, colors, makeStyles, styled, Button 2 | from pyreact import createElement as el 3 | 4 | theme = createMuiTheme({ 5 | 'palette': { 6 | 'primary': colors['teal'], 7 | 'secondary': colors['pink'], 8 | 'special': { 9 | 'main': colors['deepPurple'][600], 10 | 'contrastText': colors['common']['white'], 11 | }, 12 | }, 13 | 'overrides': { 14 | 'MuiButton': { 15 | 'root': { 16 | 'margin': '0.5rem' 17 | }, 18 | }, 19 | }, 20 | 'props': { 21 | 'MuiButton': { 22 | 'variant': 'contained', 23 | 'size': 'small', 24 | }, 25 | 'MuiTextField': { 26 | 'type': 'text', 27 | 'variant': 'outlined', 28 | 'InputLabelProps': {'shrink': True}, 29 | 'InputProps': {'margin': 'dense'}, 30 | 'margin': 'dense', 31 | }, 32 | }, 33 | }) 34 | 35 | StyledButton = styled(Button)({ 36 | 'minWidth': '6rem', 37 | 'margin': '0 0.5rem 0 0', 38 | '&:hover': {'backgroundColor': theme['palette']['special']['main']} 39 | }) 40 | 41 | useStyle = makeStyles({ 42 | 'root': { 43 | 'minWidth': '6rem', 44 | 'margin': '0 0.5rem 0 0', 45 | '&:hover': {'backgroundColor': lambda props: props['bgcolor']} 46 | } 47 | }) 48 | 49 | def ListButton(props): 50 | new_props = {'style': {'minWidth': '6rem', 'margin': '0 0.5rem 0 0'}} 51 | new_props.update(props) 52 | return el(Button, new_props) 53 | 54 | -------------------------------------------------------------------------------- /ch18/appTheme_v1.py: -------------------------------------------------------------------------------- 1 | from pymui import createMuiTheme, colors 2 | 3 | theme = createMuiTheme({ 4 | 'palette': { 5 | 'primary': colors['teal'], 6 | 'secondary': colors['pink'], 7 | 'special': { 8 | 'main': colors['deepPurple'][600], 9 | 'contrastText': colors['common']['white'], 10 | }, 11 | }, 12 | 'overrides': { 13 | 'MuiButton': { 14 | 'root': { 15 | 'margin': '0.5rem' 16 | }, 17 | }, 18 | }, 19 | 'props': { 20 | 'MuiButton': { 21 | 'variant': 'contained', 22 | 'size': 'small', 23 | }, 24 | 'MuiTextField': { 25 | 'type': 'text', 26 | 'variant': 'outlined', 27 | 'InputLabelProps': {'shrink': True}, 28 | 'InputProps': {'margin': 'dense'}, 29 | 'margin': 'dense', 30 | }, 31 | }, 32 | }) 33 | 34 | -------------------------------------------------------------------------------- /ch18/app_v1.py: -------------------------------------------------------------------------------- 1 | from pyreact import useState, render, createElement as el 2 | from pymui import Button, List, ListItem, Typography, InputLabel, Input, Box 3 | 4 | def App(): 5 | newItem, setNewItem = useState("") 6 | editItem, setEditItem = useState("") 7 | listItems, setListItems = useState([]) 8 | 9 | def handleSubmit(event): 10 | event.preventDefault() 11 | new_list = list(listItems) # Make a copy 12 | if len(editItem) > 0: # In edit mode 13 | new_list[new_list.index(editItem)] = newItem 14 | else: # In add mode 15 | new_list.append(newItem) # Add the new item 16 | setListItems(new_list) # Update our state 17 | setNewItem("") # Clear the new item value 18 | setEditItem("") # Clear the edit item value 19 | 20 | def handleChange(event): 21 | target = event['target'] 22 | setNewItem(target['value']) 23 | 24 | def handleDelete(item): 25 | new_list = list(listItems) # Make a copy 26 | new_list.remove(item) # Remove the specified item 27 | setListItems(new_list) # Update our state 28 | 29 | def handleEdit(item): 30 | setNewItem(item) # Set the new item value 31 | setEditItem(item) # Set the edit item value 32 | 33 | def ItemVu(props): 34 | return el(ListItem, {'dense': True}, 35 | el(Button, 36 | {'variant': 'contained', 37 | 'color': 'secondary', 38 | 'size': 'small', 39 | 'style': {'marginRight': '0.5rem'}, 40 | 'onClick': lambda: handleDelete(props['item']), 41 | }, 42 | "Delete" 43 | ), 44 | el(Button, 45 | {'variant': 'contained', 46 | 'color': 'primary', 47 | 'size': 'small', 48 | 'style': {'marginRight': '0.5rem'}, 49 | 'onClick': lambda: handleEdit(props['item']), 50 | }, 51 | "Edit" 52 | ), 53 | el(Typography, {'variant': 'body1'}, props['item']) 54 | ) 55 | 56 | def ListItemsVu(): 57 | return [el(ItemVu, {'key': item, 'item': item}) for item in listItems] 58 | 59 | if len(editItem) == 0: 60 | editColor = 'secondary' 61 | editLabel = "Add Item:" 62 | else: 63 | editColor = 'primary' 64 | editLabel = "Edit Item:" 65 | 66 | return el(Box, None, 67 | el('form', {'onSubmit': handleSubmit}, 68 | el(InputLabel, 69 | {'htmlFor': 'editBox', 'color': editColor}, 70 | editLabel 71 | ), 72 | el(Input, {'id': 'editBox', 73 | 'onChange': handleChange, 74 | 'value': newItem 75 | } 76 | ), 77 | el(Button, {'type': 'submit', 78 | 'variant': 'contained', 79 | 'style': {'marginLeft': '0.5rem'} 80 | }, "Submit"), 81 | ), 82 | el(List, None, 83 | el(ListItemsVu, None) 84 | ), 85 | ) 86 | 87 | render(App, None, 'root') 88 | 89 | -------------------------------------------------------------------------------- /ch18/app_v2.py: -------------------------------------------------------------------------------- 1 | from appTheme import theme 2 | from pyreact import useState, render, createElement as el 3 | from pymui import Button, List, ListItem, Typography, Box, TextField 4 | from pymui import Paper, Container, AppBar, ThemeProvider, useTheme 5 | 6 | def App(): 7 | newItem, setNewItem = useState("") 8 | editItem, setEditItem = useState("") 9 | listItems, setListItems = useState([]) 10 | 11 | def handleSubmit(event): 12 | event.preventDefault() 13 | new_list = list(listItems) # Make a copy 14 | if len(editItem) > 0: # In edit mode 15 | new_list[new_list.index(editItem)] = newItem 16 | else: # In add mode 17 | new_list.append(newItem) # Add the new item 18 | setListItems(new_list) # Update our state 19 | setNewItem("") # Clear the new item value 20 | setEditItem("") # Clear the edit item value 21 | 22 | def handleChange(event): 23 | target = event['target'] 24 | setNewItem(target['value']) 25 | 26 | def handleDelete(item): 27 | new_list = list(listItems) # Make a copy 28 | new_list.remove(item) # Remove the specified item 29 | setListItems(new_list) # Update our state 30 | 31 | def handleEdit(item): 32 | setNewItem(item) # Set the new item value 33 | setEditItem(item) # Set the edit item value 34 | 35 | def ItemVu(props): 36 | item = props['item'] 37 | current_theme = useTheme() 38 | specialColor = current_theme['palette']['special']['main'] 39 | button_style = {'margin': '0 0.5rem 0 0'} 40 | 41 | return el(ListItem, {'dense': True}, 42 | el(Button, 43 | {'color': 'secondary', 44 | 'style': button_style, 45 | 'onClick': lambda: handleDelete(item) 46 | }, 47 | el('span', {'className': 'material-icons'}, 'delete'), 48 | "Delete" 49 | ), 50 | el(Button, 51 | {'color': 'primary', 52 | 'style': button_style, 53 | 'onClick': lambda: handleEdit(item) 54 | }, 55 | el('span', {'className': 'material-icons'}, 'edit'), 56 | "Edit" 57 | ), 58 | el(Typography, {'style': {'color': specialColor}}, item) 59 | ) 60 | 61 | def ListItemsVu(): 62 | return [el(ItemVu, {'key': item, 'item': item}) for item in listItems] 63 | 64 | if len(editItem) == 0: 65 | editColor = 'secondary' 66 | editLabel = "Add Item:" 67 | else: 68 | editColor = 'primary' 69 | editLabel = "Edit Item:" 70 | 71 | return el(ThemeProvider, {'theme': theme}, 72 | el(Container, {'maxWidth': 'sm'}, 73 | el(AppBar, {'position': 'static', 74 | 'style': {'marginBottom': '0.5rem'} 75 | }, 76 | el(Box, {'width': '100%', 'marginLeft': '0.5rem'}, 77 | el(Typography, {'variant': 'h6'}, "React to Python") 78 | ) 79 | ), 80 | el(Paper, {'elevation': 2}, 81 | el('form', {'onSubmit': handleSubmit, 82 | 'style': {'marginLeft': '1rem'} 83 | }, 84 | el(TextField, {'InputLabelProps': {'color': editColor}, 85 | 'label': editLabel, 86 | 'value': newItem, 87 | 'onChange': handleChange, 88 | 'autoFocus': True 89 | } 90 | ), 91 | el(Button, {'type': 'submit', 92 | 'size': 'medium' 93 | }, "Submit"), 94 | ), 95 | el(List, None, 96 | el(ListItemsVu, None) 97 | ), 98 | ) 99 | ) 100 | ) 101 | 102 | render(App, None, 'root') 103 | 104 | -------------------------------------------------------------------------------- /ch18/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ch18/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch19", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@material-ui/core": "^4.11.0", 16 | "react": "^16.14.0", 17 | "react-dom": "^16.14.0" 18 | }, 19 | "devDependencies": { 20 | "parcel-bundler": "^1.12.4", 21 | "parcel-plugin-transcrypt": "^1.0.20" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch18/pymui.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | makeStyles = require('@material-ui/styles/makeStyles')['default'] 20 | styled = require('@material-ui/styles/styled')['default'] 21 | 22 | -------------------------------------------------------------------------------- /ch18/pymui_v1.py: -------------------------------------------------------------------------------- 1 | MaterialUI = require('@material-ui/core') 2 | 3 | # Basic MUI components 4 | Button = MaterialUI.Button 5 | List = MaterialUI.List 6 | ListItem = MaterialUI.ListItem 7 | Typography = MaterialUI.Typography 8 | Input = MaterialUI.Input 9 | InputLabel = MaterialUI.InputLabel 10 | Box = MaterialUI.Box 11 | 12 | -------------------------------------------------------------------------------- /ch18/pymui_v2.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | 10 | -------------------------------------------------------------------------------- /ch18/pymui_v3.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | 20 | -------------------------------------------------------------------------------- /ch18/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | 10 | 11 | def render(root_component, props, container): 12 | def main(): 13 | ReactDOM.render( 14 | React.createElement(root_component, props), 15 | document.getElementById(container) 16 | ) 17 | 18 | document.addEventListener('DOMContentLoaded', main) 19 | 20 | 21 | # JavaScript function mappings 22 | alert = window.alert 23 | 24 | 25 | def setTitle(title): 26 | document.title = title 27 | 28 | -------------------------------------------------------------------------------- /ch18/requirements.txt: -------------------------------------------------------------------------------- 1 | Transcrypt==3.7.16 2 | -------------------------------------------------------------------------------- /ch19/app.py: -------------------------------------------------------------------------------- 1 | from appTheme import theme, useStyle, ListButton, StyledButton 2 | from pyreact import useState, render, createElement as el 3 | from pymui import Button, List, ListItem, Typography, Box, TextField 4 | from pymui import Paper, Container, AppBar, ThemeProvider, useTheme 5 | 6 | def App(): 7 | newItem, setNewItem = useState("") 8 | editItem, setEditItem = useState("") 9 | listItems, setListItems = useState([]) 10 | 11 | def handleSubmit(event): 12 | event.preventDefault() 13 | new_list = list(listItems) # Make a copy 14 | if len(editItem) > 0: # In edit mode 15 | new_list[new_list.index(editItem)] = newItem 16 | else: # In add mode 17 | new_list.append(newItem) # Add the new item 18 | setListItems(new_list) # Update our state 19 | setNewItem("") # Clear the new item value 20 | setEditItem("") # Clear the edit item value 21 | 22 | def handleChange(event): 23 | target = event['target'] 24 | setNewItem(target['value']) 25 | 26 | def handleDelete(item): 27 | new_list = list(listItems) # Make a copy 28 | new_list.remove(item) # Remove the specified item 29 | setListItems(new_list) # Update our state 30 | 31 | def handleEdit(item): 32 | setNewItem(item) # Set the new item value 33 | setEditItem(item) # Set the edit item value 34 | 35 | def ItemVu(props): 36 | item = props['item'] 37 | theme = useTheme() 38 | specialColor = theme['palette']['special']['main'] 39 | classes = useStyle({'bgcolor': specialColor}) 40 | 41 | return el(ListItem, {'dense': True}, 42 | el(Button, 43 | {'color': 'secondary', 44 | 'className': classes.root, 45 | 'onClick': lambda: handleDelete(item) 46 | }, 47 | el('span', {'className': 'material-icons'}, 'delete'), 48 | "Delete" 49 | ), 50 | el(StyledButton, 51 | {'color': 'primary', 52 | 'onClick': lambda: handleEdit(item) 53 | }, 54 | el('span', {'className': 'material-icons'}, 'edit'), 55 | "Edit" 56 | ), 57 | el(Typography, {'style': {'color': specialColor}}, item) 58 | ) 59 | 60 | def ListItemsVu(): 61 | return [el(ItemVu, {'key': item, 'item': item}) for item in listItems] 62 | 63 | if len(editItem) == 0: 64 | editColor = 'secondary' 65 | editLabel = "Add Item:" 66 | else: 67 | editColor = 'primary' 68 | editLabel = "Edit Item:" 69 | 70 | return el(ThemeProvider, {'theme': theme}, 71 | el(Container, {'maxWidth': 'sm'}, 72 | el(AppBar, {'position': 'static', 73 | 'style': {'marginBottom': '0.5rem'} 74 | }, 75 | el(Box, {'width': '100%', 'marginLeft': '0.5rem'}, 76 | el(Typography, {'variant': 'h6'}, "React to Python") 77 | ) 78 | ), 79 | el(Paper, {'elevation': 2}, 80 | el('form', {'onSubmit': handleSubmit, 81 | 'style': {'marginLeft': '1rem'} 82 | }, 83 | el(TextField, {'InputLabelProps': {'color': editColor}, 84 | 'label': editLabel, 85 | 'value': newItem, 86 | 'onChange': handleChange, 87 | 'autoFocus': True 88 | } 89 | ), 90 | el(Button, {'type': 'submit', 91 | 'size': 'medium' 92 | }, "Submit"), 93 | ), 94 | el(List, None, 95 | el(ListItemsVu, None) 96 | ), 97 | ) 98 | ) 99 | ) 100 | 101 | render(App, None, 'root') 102 | 103 | -------------------------------------------------------------------------------- /ch19/appTheme.py: -------------------------------------------------------------------------------- 1 | from pymui import createMuiTheme, colors, makeStyles, styled, Button 2 | from pyreact import createElement as el 3 | 4 | theme = createMuiTheme({ 5 | 'palette': { 6 | 'primary': colors['teal'], 7 | 'secondary': colors['pink'], 8 | 'special': { 9 | 'main': colors['deepPurple'][600], 10 | 'contrastText': colors['common']['white'], 11 | }, 12 | }, 13 | 'overrides': { 14 | 'MuiButton': { 15 | 'root': { 16 | 'margin': '0.5rem' 17 | }, 18 | }, 19 | }, 20 | 'props': { 21 | 'MuiButton': { 22 | 'variant': 'contained', 23 | 'size': 'small', 24 | }, 25 | 'MuiTextField': { 26 | 'type': 'text', 27 | 'variant': 'outlined', 28 | 'InputLabelProps': {'shrink': True}, 29 | 'InputProps': {'margin': 'dense'}, 30 | 'margin': 'dense', 31 | }, 32 | }, 33 | }) 34 | 35 | StyledButton = styled(Button)({ 36 | 'minWidth': '6rem', 37 | 'margin': '0 0.5rem 0 0', 38 | '&:hover': {'backgroundColor': theme['palette']['special']['main']} 39 | }) 40 | 41 | useStyle = makeStyles({ 42 | 'root': { 43 | 'minWidth': '6rem', 44 | 'margin': '0 0.5rem 0 0', 45 | '&:hover': {'backgroundColor': lambda props: props['bgcolor']} 46 | } 47 | }) 48 | 49 | def ListButton(props): 50 | new_props = {'style': {'minWidth': '6rem', 'margin': '0 0.5rem 0 0'}} 51 | new_props.update(props) 52 | return el(Button, new_props) 53 | 54 | -------------------------------------------------------------------------------- /ch19/dev-server.js: -------------------------------------------------------------------------------- 1 | const Bundler = require('parcel-bundler'); 2 | const express = require('express'); 3 | const { createProxyMiddleware } = require('http-proxy-middleware'); 4 | 5 | 6 | const app = express(); 7 | 8 | const apiProxy = createProxyMiddleware('/api', { 9 | target: 'http://localhost:8000', 10 | pathRewrite: {'^/api': ''} 11 | }); 12 | app.use(apiProxy); 13 | 14 | // parcel options 15 | const options = {minify:false, cache: false, outDir: 'dist/dev', logLevel: 4}; 16 | 17 | const bundler = new Bundler('./index.html', options); 18 | app.use(bundler.middleware()); 19 | 20 | bundler.on('buildEnd', () => { 21 | console.log('Parcel proxy server has started at: http://localhost:8080'); 22 | }); 23 | 24 | app.listen(8080); 25 | 26 | -------------------------------------------------------------------------------- /ch19/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ch19/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch20", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@material-ui/core": "^4.11.0", 17 | "react": "^16.14.0", 18 | "react-dom": "^16.14.0" 19 | }, 20 | "devDependencies": { 21 | "express": "^4.17.1", 22 | "http-proxy-middleware": "^1.0.6", 23 | "parcel-bundler": "^1.12.4", 24 | "parcel-plugin-transcrypt": "^1.0.20" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch19/pymui.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | makeStyles = require('@material-ui/styles/makeStyles')['default'] 20 | styled = require('@material-ui/styles/styled')['default'] 21 | 22 | -------------------------------------------------------------------------------- /ch19/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | 10 | 11 | def render(root_component, props, container): 12 | def main(): 13 | ReactDOM.render( 14 | React.createElement(root_component, props), 15 | document.getElementById(container) 16 | ) 17 | 18 | document.addEventListener('DOMContentLoaded', main) 19 | 20 | 21 | # JavaScript function mappings 22 | alert = window.alert 23 | 24 | 25 | def setTitle(title): 26 | document.title = title 27 | 28 | -------------------------------------------------------------------------------- /ch19/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=2.0.0 2 | Transcrypt==3.7.16 3 | 4 | -------------------------------------------------------------------------------- /ch19/webserver.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | users = [ 4 | {"ID": 1, "FirstName": "Valeria", "LastName": "Lammerding", 5 | "Email": "vlammerding0@flickr.com", "JobTitle": "Geologist III", 6 | "Username": "vlammerding0", "Active": False}, 7 | {"ID": 2, "FirstName": "Bond", "LastName": "Tomczynski", 8 | "Email": "btomczynski1@ehow.com", "JobTitle": "Environmental Specialist", 9 | "Username": "btomczynski1", "Active": True}, 10 | {"ID": 3, "FirstName": "Nowell", "LastName": "Triplet", 11 | "Email": "ntriplet2@sciencedirect.com", "JobTitle": "Business Analyst", 12 | "Username": "ntriplet2", "Active": False}, 13 | {"ID": 4, "FirstName": "Patience", "LastName": "Boulds", 14 | "Email": "pboulds3@reverbnation.com", "JobTitle": "Assistant Manager", 15 | "Username": "pboulds3", "Active": True}, 16 | {"ID": 5, "FirstName": "Darelle", "LastName": "Lemonby", 17 | "Email": "dlemonby4@prweb.com", "JobTitle": "Staff Accountant I", 18 | "Username": "dlemonby4", "Active": True} 19 | ] 20 | 21 | app = Flask(__name__) 22 | 23 | @app.route('/user/') 24 | def get_user(userid): 25 | person = next((user for user in users if str(user['ID']) == userid), {}) 26 | return jsonify(person) 27 | 28 | @app.route('/users') 29 | def get_userlist(): 30 | user_list = [] 31 | for user in users: 32 | user_name = ', '.join([user['LastName'], user['FirstName']]) 33 | user_list.append([user['ID'], user_name]) 34 | return jsonify(user_list) 35 | 36 | if __name__ == "__main__": 37 | app.run(debug=True, port=8000) 38 | 39 | -------------------------------------------------------------------------------- /ch20/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import render, useState, useEffect, createElement as el 2 | from pymui import Box, TextField 3 | from jsutils import fetch 4 | 5 | 6 | def StyledTextField(props): 7 | new_props = {'type': 'text', 8 | 'fullWidth': True, 9 | 'variant': 'outlined', 10 | 'InputLabelProps': {'shrink': True}, 11 | 'InputProps': {'margin': 'dense'}, 12 | 'margin': 'dense', 13 | } 14 | 15 | new_props.update(props) 16 | return el(TextField, new_props) 17 | 18 | 19 | def UserVu(props): 20 | users = props['users'] if props['users'] else [] 21 | 22 | def userToRow(user): 23 | return el('option', {'key': user[0], 'value': user[0]}, user[1]) 24 | 25 | return [userToRow(user) for user in users] 26 | 27 | 28 | def App(): 29 | users, setUsers = useState([]) 30 | userID, setUserID = useState("") 31 | firstName, setFirstName = useState("") 32 | lastName, setLastName = useState("") 33 | username, setUsername = useState("") 34 | 35 | def handleChange(event): 36 | target = event['target'] 37 | setUserID(target['value']) 38 | setFirstName("") 39 | setLastName("") 40 | setUsername("") 41 | 42 | def getUser(): 43 | def _getUser(data): 44 | user_info = data if data else {} 45 | if len(user_info) > 0: 46 | setFirstName(user_info['FirstName']) 47 | setLastName(user_info['LastName']) 48 | setUsername(user_info['Username']) 49 | else: 50 | setFirstName("") 51 | setLastName("") 52 | setUsername("") 53 | 54 | if len(userID) > 0: 55 | fetch(f"/api/user/{userID}", _getUser) 56 | 57 | def getUsers(): 58 | def _getUsers(data): 59 | user_list = data if data else [] 60 | user_list.sort(key=lambda user: user[1]) 61 | setUsers(user_list) 62 | setUserID("") 63 | 64 | fetch("/api/users", _getUsers) 65 | 66 | useEffect(getUser, [userID]) 67 | useEffect(getUsers, []) 68 | 69 | return el(Box, {'key': 'App', 'style': {'width': '200px'}}, 70 | el(Box, {'alignItems': 'center'}, 71 | el(StyledTextField, {'label': "Select User", 72 | 'value': userID, 73 | 'onChange': handleChange, 74 | 'select': True, 75 | 'SelectProps': {'native': True}, 76 | 'autoFocus': True, 77 | }, 78 | el('option', {'key': '', 'value': ''}), # Blank row 79 | el(UserVu, {'users': users}), 80 | ), 81 | ), 82 | el(StyledTextField, {'label': 'First Name', 83 | 'value': firstName, 84 | 'disabled': True, 85 | } 86 | ), 87 | el(StyledTextField, {'label': 'Last Name', 88 | 'value': lastName, 89 | 'disabled': True, 90 | } 91 | ), 92 | el(StyledTextField, {'label': 'Username', 93 | 'value': username, 94 | 'disabled': True, 95 | } 96 | ), 97 | ), 98 | 99 | render(App, None, 'root') 100 | 101 | -------------------------------------------------------------------------------- /ch20/dev-server.js: -------------------------------------------------------------------------------- 1 | const Bundler = require('parcel-bundler'); 2 | const express = require('express'); 3 | const { createProxyMiddleware } = require('http-proxy-middleware'); 4 | 5 | 6 | const app = express(); 7 | 8 | const apiProxy = createProxyMiddleware('/api', { 9 | target: 'http://localhost:8000', 10 | pathRewrite: {'^/api': ''} 11 | }); 12 | app.use(apiProxy); 13 | 14 | // parcel options 15 | const options = {minify:false, cache: false, outDir: 'dist/dev', logLevel: 4}; 16 | 17 | const bundler = new Bundler('./index.html', options); 18 | app.use(bundler.middleware()); 19 | 20 | bundler.on('buildEnd', () => { 21 | console.log('Parcel proxy server has started at: http://localhost:8080'); 22 | }); 23 | 24 | app.listen(8080); 25 | 26 | -------------------------------------------------------------------------------- /ch20/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ch20/jsutils.py: -------------------------------------------------------------------------------- 1 | console = window.console 2 | 3 | polyfill = require("@babel/polyfill") # required by async/await 4 | 5 | async def fetch(url, callback): 6 | try: 7 | response = await window.fetch(url) 8 | if response.status != 200: 9 | console.error('Fetch error - Status Code: ' + response.status) 10 | else: 11 | data = await response.json() 12 | callback(data) 13 | except object as e: 14 | console.error(e) 15 | -------------------------------------------------------------------------------- /ch20/jsutils_v1.py: -------------------------------------------------------------------------------- 1 | console = window.console 2 | 3 | def fetch(url, callback): 4 | def check_response(response): 5 | if response.status != 200: 6 | console.error('Fetch error - Status Code: ' + response.status) 7 | return None 8 | return response.json() 9 | 10 | try: 11 | promise = window.fetch(url) 12 | response = promise.then(check_response) 13 | response.then(callback) 14 | promise.catch(console.error) 15 | except object as e: 16 | console.error(e) 17 | 18 | -------------------------------------------------------------------------------- /ch20/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch21", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@babel/polyfill": "^7.12.1", 17 | "@material-ui/core": "^4.11.0", 18 | "react": "^16.14.0", 19 | "react-dom": "^16.14.0" 20 | }, 21 | "devDependencies": { 22 | "express": "^4.17.1", 23 | "http-proxy-middleware": "^1.0.6", 24 | "parcel-bundler": "^1.12.4", 25 | "parcel-plugin-transcrypt": "^1.0.20" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch20/pymui.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | makeStyles = require('@material-ui/styles/makeStyles')['default'] 20 | styled = require('@material-ui/styles/styled')['default'] 21 | 22 | -------------------------------------------------------------------------------- /ch20/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | 10 | 11 | def render(root_component, props, container): 12 | def main(): 13 | ReactDOM.render( 14 | React.createElement(root_component, props), 15 | document.getElementById(container) 16 | ) 17 | 18 | document.addEventListener('DOMContentLoaded', main) 19 | 20 | 21 | # JavaScript function mappings 22 | alert = window.alert 23 | 24 | 25 | def setTitle(title): 26 | document.title = title 27 | 28 | -------------------------------------------------------------------------------- /ch20/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=2.0.0 2 | Transcrypt==3.7.16 3 | 4 | -------------------------------------------------------------------------------- /ch20/webserver.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | users = [ 4 | {"ID": 1, "FirstName": "Valeria", "LastName": "Lammerding", 5 | "Email": "vlammerding0@flickr.com", "JobTitle": "Geologist III", 6 | "Username": "vlammerding0", "Active": False}, 7 | {"ID": 2, "FirstName": "Bond", "LastName": "Tomczynski", 8 | "Email": "btomczynski1@ehow.com", "JobTitle": "Environmental Specialist", 9 | "Username": "btomczynski1", "Active": True}, 10 | {"ID": 3, "FirstName": "Nowell", "LastName": "Triplet", 11 | "Email": "ntriplet2@sciencedirect.com", "JobTitle": "Business Analyst", 12 | "Username": "ntriplet2", "Active": False}, 13 | {"ID": 4, "FirstName": "Patience", "LastName": "Boulds", 14 | "Email": "pboulds3@reverbnation.com", "JobTitle": "Assistant Manager", 15 | "Username": "pboulds3", "Active": True}, 16 | {"ID": 5, "FirstName": "Darelle", "LastName": "Lemonby", 17 | "Email": "dlemonby4@prweb.com", "JobTitle": "Staff Accountant I", 18 | "Username": "dlemonby4", "Active": True} 19 | ] 20 | 21 | app = Flask(__name__) 22 | 23 | @app.route('/user/') 24 | def get_user(userid): 25 | person = next((user for user in users if str(user['ID']) == userid), {}) 26 | return jsonify(person) 27 | 28 | @app.route('/users') 29 | def get_userlist(): 30 | user_list = [] 31 | for user in users: 32 | user_name = ', '.join([user['LastName'], user['FirstName']]) 33 | user_list.append([user['ID'], user_name]) 34 | return jsonify(user_list) 35 | 36 | if __name__ == "__main__": 37 | app.run(debug=True, port=8000) 38 | 39 | -------------------------------------------------------------------------------- /ch21/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import render, useState, createElement as el 2 | from pyreact import useContext, createContext 3 | from pymui import Box, TextField 4 | 5 | Ctx = createContext() 6 | 7 | def ROTextField(props): 8 | new_props = {'fullWidth': True, 9 | 'variant': 'outlined', 10 | 'InputLabelProps': {'shrink': True}, 11 | 'InputProps': {'margin': 'dense'}, 12 | 'margin': 'dense', 13 | 'disabled': True 14 | } 15 | 16 | new_props.update(props) 17 | return el(TextField, new_props) 18 | 19 | def Component2(props): 20 | return el(Box, None, 21 | el(ROTextField, {'label': 'Row 2', 'value': 'Row Two'}), 22 | el(Component3, None) 23 | ) 24 | 25 | def Component3(props): 26 | return el(Box, None, 27 | el(ROTextField, {'label': 'Row 3', 'value': 'Row Three'}), 28 | el(Component4, None) 29 | ) 30 | 31 | def Component4(props): 32 | return el(Box, None, 33 | el(ROTextField, {'label': 'Row 4', 'value': 'Row Four'}), 34 | el(Component5, None) 35 | ) 36 | 37 | def Component5(props): 38 | ctx = useContext(Ctx) 39 | testVal = ctx['testVal'] 40 | return el(Box, None, 41 | el(ROTextField, {'label': 'Copy From Row 1', 42 | 'value': testVal} 43 | ), 44 | ) 45 | 46 | def App(): 47 | testVal, setTestVal = useState("") 48 | 49 | def handleChange(event): 50 | target = event['target'] 51 | setTestVal(target['value']) 52 | 53 | return el(Ctx.Provider, {'value': {'testVal': testVal, 'otherVal': 42}}, 54 | el(Box, {'key': 'App', 'style': {'width': '200px'}}, 55 | el(TextField, {'label': 'Row 1', 56 | 'value': testVal, 57 | 'onChange': handleChange} 58 | ), 59 | el(Component2, None) 60 | ) 61 | ) 62 | 63 | render(App, None, 'root') 64 | 65 | -------------------------------------------------------------------------------- /ch21/app_v1.py: -------------------------------------------------------------------------------- 1 | from pyreact import render, useState, createElement as el 2 | from pymui import Box, TextField 3 | 4 | def ROTextField(props): 5 | new_props = {'fullWidth': True, 6 | 'variant': 'outlined', 7 | 'InputLabelProps': {'shrink': True}, 8 | 'InputProps': {'margin': 'dense'}, 9 | 'margin': 'dense', 10 | 'disabled': True 11 | } 12 | 13 | new_props.update(props) 14 | return el(TextField, new_props) 15 | 16 | def Component2(props): 17 | return el(Box, None, 18 | el(ROTextField, {'label': 'Row 2', 'value': 'Row Two'}), 19 | el(Component3, {'testVal2': props['testVal1']}) 20 | ) 21 | 22 | def Component3(props): 23 | return el(Box, None, 24 | el(ROTextField, {'label': 'Row 3', 'value': 'Row Three'}), 25 | el(Component4, {'testVal3': props['testVal2']}) 26 | ) 27 | 28 | def Component4(props): 29 | return el(Box, None, 30 | el(ROTextField, {'label': 'Row 4', 'value': 'Row Four'}), 31 | el(Component5, {'testVal4': props['testVal3']}) 32 | ) 33 | 34 | def Component5(props): 35 | return el(Box, None, 36 | el(ROTextField, {'label': 'Copy From Row 1', 37 | 'value': props['testVal4']} 38 | ), 39 | ) 40 | 41 | def App(): 42 | testVal, setTestVal = useState("") 43 | 44 | def handleChange(event): 45 | target = event['target'] 46 | setTestVal(target['value']) 47 | 48 | return el(Box, {'key': 'App', 'style': {'width': '200px'}}, 49 | el(TextField, {'label': 'Row 1', 50 | 'value': testVal, 51 | 'onChange': handleChange} 52 | ), 53 | el(Component2, {'testVal1': testVal}) 54 | ) 55 | 56 | render(App, None, 'root') 57 | 58 | -------------------------------------------------------------------------------- /ch21/dev-server.js: -------------------------------------------------------------------------------- 1 | const Bundler = require('parcel-bundler'); 2 | const express = require('express'); 3 | const { createProxyMiddleware } = require('http-proxy-middleware'); 4 | 5 | 6 | const app = express(); 7 | 8 | const apiProxy = createProxyMiddleware('/api', { 9 | target: 'http://localhost:8000', 10 | pathRewrite: {'^/api': ''} 11 | }); 12 | app.use(apiProxy); 13 | 14 | // parcel options 15 | const options = {minify:false, cache: false, outDir: 'dist/dev', logLevel: 4}; 16 | 17 | const bundler = new Bundler('./index.html', options); 18 | app.use(bundler.middleware()); 19 | 20 | bundler.on('buildEnd', () => { 21 | console.log('Parcel proxy server has started at: http://localhost:8080'); 22 | }); 23 | 24 | app.listen(8080); 25 | 26 | -------------------------------------------------------------------------------- /ch21/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ch21/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch22", 3 | "version": "1.0.0", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "@babel/polyfill": "^7.12.1", 17 | "@material-ui/core": "^4.11.0", 18 | "react": "^16.14.0", 19 | "react-dom": "^16.14.0" 20 | }, 21 | "devDependencies": { 22 | "express": "^4.17.1", 23 | "http-proxy-middleware": "^1.0.6", 24 | "parcel-bundler": "^1.12.4", 25 | "parcel-plugin-transcrypt": "^1.0.20" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch21/pymui.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | makeStyles = require('@material-ui/styles/makeStyles')['default'] 20 | styled = require('@material-ui/styles/styled')['default'] 21 | 22 | -------------------------------------------------------------------------------- /ch21/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | 5 | # Map React javaScript objects to Python identifiers 6 | createElement = React.createElement 7 | useState = React.useState 8 | useEffect = React.useEffect 9 | createContext = React.createContext 10 | useContext = React.useContext 11 | 12 | 13 | def render(root_component, props, container): 14 | def main(): 15 | ReactDOM.render( 16 | React.createElement(root_component, props), 17 | document.getElementById(container) 18 | ) 19 | 20 | document.addEventListener('DOMContentLoaded', main) 21 | 22 | 23 | # JavaScript function mappings 24 | alert = window.alert 25 | 26 | 27 | def setTitle(title): 28 | document.title = title 29 | 30 | -------------------------------------------------------------------------------- /ch21/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=2.0.0 2 | Transcrypt==3.7.16 3 | 4 | -------------------------------------------------------------------------------- /ch22/jsutils.py: -------------------------------------------------------------------------------- 1 | console = window.console 2 | 3 | deepcopy = require('deepcopy') 4 | 5 | polyfill = require("@babel/polyfill") # required by async/await 6 | 7 | async def fetch(url, callback): 8 | try: 9 | response = await window.fetch(url) 10 | if response.status != 200: 11 | console.error('Fetch error - Status Code: ' + response.status) 12 | else: 13 | data = await response.json() 14 | callback(data) 15 | except object as e: 16 | console.error(e) 17 | -------------------------------------------------------------------------------- /ch23/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch24", 3 | "version": "1.0.1", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "version": "echo \"version = '$npm_package_version'\" > ./version.py;git add ./version.py", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@babel/polyfill": "^7.12.1", 18 | "@material-ui/core": "^4.11.0", 19 | "react": "^16.14.0", 20 | "react-dom": "^16.14.0" 21 | }, 22 | "devDependencies": { 23 | "express": "^4.17.1", 24 | "http-proxy-middleware": "^1.0.6", 25 | "parcel-bundler": "^1.12.4", 26 | "parcel-plugin-transcrypt": "^1.0.20" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ch23/version.py: -------------------------------------------------------------------------------- 1 | version = '1.0.1' 2 | -------------------------------------------------------------------------------- /ch24/app.py: -------------------------------------------------------------------------------- 1 | from pyreact import render, useState, useEffect, createElement as el 2 | from pyreact import ReactGA 3 | from pymui import Box, TextField 4 | from jsutils import fetch 5 | 6 | 7 | GAID = 'UA-100000000-1' # Substitute your own GA Tracking ID here 8 | ReactGA.initialize(GAID, {'titleCase': False, 'debug': False, 9 | 'gaOptions': {'siteSpeedSampleRate': 100}} 10 | ) 11 | 12 | 13 | def StyledTextField(props): 14 | new_props = {'type': 'text', 15 | 'fullWidth': True, 16 | 'variant': 'outlined', 17 | 'InputLabelProps': {'shrink': True}, 18 | 'InputProps': {'margin': 'dense'}, 19 | 'margin': 'dense', 20 | } 21 | 22 | new_props.update(props) 23 | return el(TextField, new_props) 24 | 25 | def UserVu(props): 26 | users = props['users'] if props['users'] else [] 27 | 28 | def userToRow(user): 29 | return el('option', {'key': user[0], 'value': user[0]}, user[1]) 30 | 31 | return [userToRow(user) for user in users] 32 | 33 | 34 | def App(): 35 | users, setUsers = useState([]) 36 | userID, setUserID = useState("") 37 | firstName, setFirstName = useState("") 38 | lastName, setLastName = useState("") 39 | username, setUsername = useState("") 40 | 41 | def handleChange(event): 42 | target = event['target'] 43 | setUserID(target['value']) 44 | setFirstName("") 45 | setLastName("") 46 | setUsername("") 47 | 48 | def getUser(): 49 | def _getUser(data): 50 | user_info = data if data else {} 51 | if len(user_info) > 0: 52 | setFirstName(user_info['FirstName']) 53 | setLastName(user_info['LastName']) 54 | setUsername(user_info['Username']) 55 | else: 56 | setFirstName("") 57 | setLastName("") 58 | setUsername("") 59 | 60 | if len(userID) > 0: 61 | ReactGA.event({'category': 'User', 62 | 'action': 'Select', 63 | 'label': userID} 64 | ) 65 | fetch(f"/api/user/{userID}", _getUser) 66 | 67 | def getUsers(): 68 | def _getUsers(data): 69 | user_list = data if data else [] 70 | user_list.sort(key=lambda user: user[1]) 71 | ReactGA.event({'category': 'App', 72 | 'action': 'Load', 73 | 'label': 'Users', 74 | 'nonInteraction': True} 75 | ) 76 | setUsers(user_list) 77 | setUserID("") 78 | 79 | fetch("/api/users", _getUsers) 80 | 81 | useEffect(getUser, [userID]) 82 | useEffect(getUsers, []) 83 | 84 | return el(Box, {'key': 'App', 'style': {'width': '200px'}}, 85 | el(Box, {'alignItems': 'center'}, 86 | el(StyledTextField, {'label': "Select User", 87 | 'value': userID, 88 | 'onChange': handleChange, 89 | 'select': True, 90 | 'SelectProps': {'native': True}, 91 | 'autoFocus': True, 92 | }, 93 | el('option', {'key': '', 'value': ''}), # Blank row 94 | el(UserVu, {'users': users}), 95 | ), 96 | ), 97 | el(StyledTextField, {'label': 'First Name', 98 | 'value': firstName, 99 | 'disabled': True, 100 | } 101 | ), 102 | el(StyledTextField, {'label': 'Last Name', 103 | 'value': lastName, 104 | 'disabled': True, 105 | } 106 | ), 107 | el(StyledTextField, {'label': 'Username', 108 | 'value': username, 109 | 'disabled': True, 110 | } 111 | ), 112 | ), 113 | 114 | render(App, None, 'root') 115 | 116 | -------------------------------------------------------------------------------- /ch24/dev-server.js: -------------------------------------------------------------------------------- 1 | const Bundler = require('parcel-bundler'); 2 | const express = require('express'); 3 | const { createProxyMiddleware } = require('http-proxy-middleware'); 4 | 5 | 6 | const app = express(); 7 | 8 | const apiProxy = createProxyMiddleware('/api', { 9 | target: 'http://localhost:8000', 10 | pathRewrite: {'^/api': ''} 11 | }); 12 | app.use(apiProxy); 13 | 14 | // parcel options 15 | const options = {minify:false, cache: false, outDir: 'dist/dev', logLevel: 4}; 16 | 17 | const bundler = new Bundler('./index.html', options); 18 | app.use(bundler.middleware()); 19 | 20 | bundler.on('buildEnd', () => { 21 | console.log('Parcel proxy server has started at: http://localhost:8080'); 22 | }); 23 | 24 | app.listen(8080); 25 | 26 | -------------------------------------------------------------------------------- /ch24/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ch24/jsutils.py: -------------------------------------------------------------------------------- 1 | import time 2 | from pyreact import ReactGA 3 | 4 | 5 | console = window.console 6 | 7 | deepcopy = require('deepcopy') 8 | 9 | polyfill = require("@babel/polyfill") # required by async/await 10 | 11 | async def fetch(url, callback): 12 | t_start = time.time() 13 | try: 14 | response = await window.fetch(url) 15 | if response.status != 200: 16 | console.error('Fetch error - Status Code: ' + response.status) 17 | else: 18 | data = await response.json() 19 | t_elapsed = time.time() - t_start 20 | ReactGA.timing({'category': 'API', 21 | 'variable': 'fetch', 22 | 'value': int(t_elapsed * 1000), 23 | 'label': url} 24 | ) 25 | callback(data) 26 | except object as e: 27 | console.error(e) 28 | 29 | -------------------------------------------------------------------------------- /ch24/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch25", 3 | "version": "1.0.1", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "version": "echo \"version = '$npm_package_version'\" > ./version.py;git add ./version.py", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@babel/polyfill": "^7.12.1", 18 | "@material-ui/core": "^4.11.0", 19 | "deepcopy": "^2.1.0", 20 | "react": "^16.14.0", 21 | "react-dom": "^16.14.0", 22 | "react-ga": "^3.2.0" 23 | }, 24 | "devDependencies": { 25 | "express": "^4.17.1", 26 | "http-proxy-middleware": "^1.0.6", 27 | "parcel-bundler": "^1.12.4", 28 | "parcel-plugin-transcrypt": "^1.0.20" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ch24/pymui.py: -------------------------------------------------------------------------------- 1 | # Basic MUI components 2 | Button = require('@material-ui/core/Button')['default'] 3 | List = require('@material-ui/core/List')['default'] 4 | ListItem = require('@material-ui/core/ListItem')['default'] 5 | Typography = require('@material-ui/core/Typography')['default'] 6 | Input = require('@material-ui/core/Input')['default'] 7 | InputLabel = require('@material-ui/core/InputLabel')['default'] 8 | Box = require('@material-ui/core/Box')['default'] 9 | TextField = require('@material-ui/core/TextField')['default'] 10 | Paper = require('@material-ui/core/Paper')['default'] 11 | AppBar = require('@material-ui/core/AppBar')['default'] 12 | Container = require('@material-ui/core/Container')['default'] 13 | 14 | # Theming 15 | ThemeProvider = require('@material-ui/styles/ThemeProvider')['default'] 16 | useTheme = require('@material-ui/styles/useTheme')['default'] 17 | createMuiTheme = require('@material-ui/core/styles/createMuiTheme')['default'] 18 | colors = require('@material-ui/core/colors') 19 | makeStyles = require('@material-ui/styles/makeStyles')['default'] 20 | styled = require('@material-ui/styles/styled')['default'] 21 | 22 | -------------------------------------------------------------------------------- /ch24/pyreact.py: -------------------------------------------------------------------------------- 1 | # Load React and ReactDOM JavaScript libraries into local namespace 2 | React = require('react') 3 | ReactDOM = require('react-dom') 4 | ReactGA = require('react-ga') 5 | 6 | # Map React javaScript objects to Python identifiers 7 | createElement = React.createElement 8 | useState = React.useState 9 | useEffect = React.useEffect 10 | createContext = React.createContext 11 | useContext = React.useContext 12 | 13 | 14 | def render(root_component, props, container): 15 | def main(): 16 | ReactDOM.render( 17 | React.createElement(root_component, props), 18 | document.getElementById(container) 19 | ) 20 | 21 | document.addEventListener('DOMContentLoaded', main) 22 | 23 | 24 | # JavaScript function mappings 25 | alert = window.alert 26 | 27 | 28 | def setTitle(title): 29 | document.title = title 30 | 31 | -------------------------------------------------------------------------------- /ch24/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask>=2.0.0 2 | Transcrypt==3.7.16 3 | 4 | -------------------------------------------------------------------------------- /ch24/version.py: -------------------------------------------------------------------------------- 1 | version = '1.0.1' 2 | -------------------------------------------------------------------------------- /ch24/webserver.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | users = [ 4 | {"ID": 1, "FirstName": "Valeria", "LastName": "Lammerding", 5 | "Email": "vlammerding0@flickr.com", "JobTitle": "Geologist III", 6 | "Username": "vlammerding0", "Active": False}, 7 | {"ID": 2, "FirstName": "Bond", "LastName": "Tomczynski", 8 | "Email": "btomczynski1@ehow.com", "JobTitle": "Environmental Specialist", 9 | "Username": "btomczynski1", "Active": True}, 10 | {"ID": 3, "FirstName": "Nowell", "LastName": "Triplet", 11 | "Email": "ntriplet2@sciencedirect.com", "JobTitle": "Business Analyst", 12 | "Username": "ntriplet2", "Active": False}, 13 | {"ID": 4, "FirstName": "Patience", "LastName": "Boulds", 14 | "Email": "pboulds3@reverbnation.com", "JobTitle": "Assistant Manager", 15 | "Username": "pboulds3", "Active": True}, 16 | {"ID": 5, "FirstName": "Darelle", "LastName": "Lemonby", 17 | "Email": "dlemonby4@prweb.com", "JobTitle": "Staff Accountant I", 18 | "Username": "dlemonby4", "Active": True} 19 | ] 20 | 21 | app = Flask(__name__) 22 | 23 | @app.route('/user/') 24 | def get_user(userid): 25 | person = next((user for user in users if str(user['ID']) == userid), {}) 26 | return jsonify(person) 27 | 28 | @app.route('/users') 29 | def get_userlist(): 30 | user_list = [] 31 | for user in users: 32 | user_name = ', '.join([user['LastName'], user['FirstName']]) 33 | user_list.append([user['ID'], user_name]) 34 | return jsonify(user_list) 35 | 36 | if __name__ == "__main__": 37 | app.run(debug=True, port=8000) 38 | 39 | -------------------------------------------------------------------------------- /ch25/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ch26", 3 | "version": "1.0.1", 4 | "description": "React to Python", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development parcel --log-level 4 index.html --out-dir dist/dev", 8 | "build": "NODE_ENV=production parcel --log-level 4 build index.html --no-source-maps --out-dir dist/prod", 9 | "dev": "node dev-server.js", 10 | "version": "echo \"version = '$npm_package_version'\" > ./version.py;git add ./version.py", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@babel/polyfill": "^7.12.1", 18 | "@material-ui/core": "^4.11.0", 19 | "deepcopy": "^2.1.0", 20 | "react": "^16.14.0", 21 | "react-dom": "^16.14.0", 22 | "react-ga": "^3.2.0" 23 | }, 24 | "devDependencies": { 25 | "express": "^4.17.1", 26 | "http-proxy-middleware": "^1.0.6", 27 | "parcel-bundler": "^1.12.4", 28 | "parcel-plugin-bundle-visualiser": "^1.2.0", 29 | "parcel-plugin-transcrypt": "^1.0.20" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch26/README.md: -------------------------------------------------------------------------------- 1 | There are no code modules for Chapter 26. 2 | 3 | --------------------------------------------------------------------------------