├── .babelrc ├── .editorconfig ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-issue.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── .vscode └── launch.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __mocks__ └── node-qt.js ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── SVG │ ├── Artboard 1.svg │ └── proton native.ai ├── _coverpage.md ├── _sidebar.md ├── about.md ├── calculator.png ├── catapi_v2.png ├── components.md ├── components │ ├── View.md │ └── Window.md ├── debugging.md ├── external_functionality.md ├── hot_reloading.md ├── images │ ├── CatApi.gif │ ├── app_icon.svg │ ├── favicon.png │ ├── icon_black.svg │ ├── icon_white.svg │ ├── logo_black.svg │ ├── logo_white.svg │ ├── windows_example.png │ └── windows_packaging.png ├── index.html ├── js_example.js ├── main.js ├── packaging.md ├── python_example.py ├── quickstart.md ├── v2_changes.md └── wx_backend.md ├── examples ├── Calculator │ ├── .babelrc │ ├── app.js │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── webpack.config.js ├── CatApi │ ├── .babelrc │ ├── app.js │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── actions │ │ │ └── index.js │ │ ├── components │ │ │ └── main.js │ │ ├── consts │ │ │ └── index.js │ │ └── reducers │ │ │ └── index.js │ └── webpack.config.js └── Notepad │ ├── .babelrc │ ├── index.js │ ├── package-lock.json │ └── package.json ├── package-lock.json ├── package.json ├── src ├── backends │ ├── index.ts │ ├── qt.ts │ └── wx.ts ├── components │ ├── App.ts │ ├── Base.ts │ ├── Button.ts │ ├── Container.ts │ ├── Image.ts │ ├── PickerInternal.ts │ ├── Root.ts │ ├── RootText.ts │ ├── TextFuncs.ts │ ├── TextInput.ts │ ├── View.ts │ ├── VirtualText.ts │ ├── Window.ts │ ├── YogaComponent.ts │ └── index.ts ├── devtools.ts ├── index.ts ├── misc │ ├── hot.ts │ ├── index.ts │ ├── node-qt-napi.d.ts │ ├── node-wx-napi.ts │ ├── react-proxy.d.ts │ ├── styleSheet.ts │ └── yoga-layout-prebuilt.d.ts ├── react-components │ ├── Picker.tsx │ ├── Text.tsx │ ├── TouchableHighlight.tsx │ ├── TouchableOpacity.tsx │ ├── TouchableWithoutFeedback.tsx │ └── index.ts ├── reconciler │ └── index.ts ├── render │ └── index.ts └── utils │ ├── convertStyleSheet.ts │ ├── createElement.ts │ ├── propChecker.ts │ ├── propsUpdater.ts │ ├── requireImpl.ts │ └── yogaHelper.ts ├── test ├── components │ ├── Window.test.js │ └── __image_snapshots__ │ │ ├── window-test-js-window-basic-window-1-snap.png │ │ ├── window-test-js-window-multiple-windows-1-snap.png │ │ ├── window-test-js-window-window-add-state-1-snap.png │ │ ├── window-test-js-window-window-add-state-2-snap.png │ │ ├── window-test-js-window-window-insert-state-1-snap.png │ │ ├── window-test-js-window-window-insert-state-2-snap.png │ │ ├── window-test-js-window-window-removal-state-1-snap.png │ │ ├── window-test-js-window-window-removal-state-2-snap.png │ │ ├── window-test-js-window-window-size-1-snap.png │ │ ├── window-test-js-window-window-size-percent-1-snap.png │ │ ├── window-test-js-window-window-styling-1-snap.png │ │ ├── window-test-js-window-window-update-state-1-snap.png │ │ └── window-test-js-window-window-update-state-2-snap.png └── index.js ├── testprog.js ├── testyoga.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style = space 4 | indent_size = 2 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: kusti8 # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Include a minimal example of code that causes this bug. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Versions:** 23 | - OS: [e.g. Windows, Mac, Linux] 24 | - Version [e.g. 2.0.0] 25 | - Node version [eg. 12.0.1] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation Issue 3 | about: Found an error or something missing in the documentation? 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Link to the page** 11 | 12 | **Quote of Error** 13 | Preferably a quote of the error, if there is one. 14 | 15 | **Proposed Changes** 16 | Include what changes should be made [ex. add section on X, remove sentence about Y] 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # console.logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | bin 61 | dist/ 62 | 63 | # ide 64 | .idea/ 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: xenial 3 | cache: false 4 | node_js: 5 | - "9.3" 6 | - "10" 7 | - "11" 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - xvfb 14 | - qtbase5-dev 15 | - build-essential 16 | - qt5-default 17 | - g++-6 18 | - x11-apps 19 | - imagemagick 20 | before_install: 21 | - export CXX="g++-6" 22 | install: 23 | - npm install 24 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/testprog.js", 12 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/babel-node" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | ## Getting Started 4 | 5 | Clone the repository, and install dependencies with `npm i`. To test changes, make changes to `testprog.js` and run `npm run testprog`. Just don't commit any changes to this file. 6 | 7 | ### Docs 8 | 9 | All documentation is housed in `docs/`, and is written in Markdown. Follow the format for all other pages. If you're making a page that doesn't follow previous formats, ask me. Changes made to `index.html` will not be made lightly and 99% of cases don't need to change that. The format is set for documentation, so don't try and change it. 10 | 11 | ## Important Points 12 | 13 | Proton Native welcomes contributions to constantly improve. Contributions are accepted in the form of a PR, which has a few important points that should be followed. 14 | 15 | 1. Styling is done with prettier. A git-hook has been added for convience, but any PR that isn't styled won't be accepted. 16 | 17 | 2. Follow common sense. If there already exists a file similar, use it as a template. Don't make up your own style. 18 | 19 | 3. Minimize hacks. If there's a clean way to do it, do it. 20 | 21 | 4. **Document everything**! Every additional feature should be well documented. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gustav Hansen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | proton native 4 | 5 | Logo by @elisiri 6 |

7 | 8 | # Announcement 9 | **Sadly I don't have time to dedicate time to this project. Some others have created a fork here to continue the work: https://github.com/proton-nativejs/proton-native** 10 | 11 | [![npm](https://img.shields.io/npm/v/proton-native.svg)](https://www.npmjs.com/package/proton-native) 12 | [![npm](https://img.shields.io/npm/dm/proton-native.svg)](https://www.npmjs.com/package/proton-native) 13 | [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 14 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) 15 | [![MIT License](https://img.shields.io/github/license/kusti8/proton-native.svg)](https://github.com/kusti8/proton-native/blob/master/LICENSE) 16 | [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/Proton-Native) 17 | 18 | Create desktop applications through a React syntax, on all platforms. 19 | 20 | ## V2 is released! 21 | 22 | V2 has been released and it brings a whole host of improvements including new 23 | components that are identical to React Native, styling, flexbox, hot reloading, 24 | and more. You can read the full writeup [here](https://proton-native.js.org/#/v2_changes). 25 | To try it out, visit the documentation for instructions on how to get started! 26 | 27 | ## Features 28 | 29 | - Same syntax and components as React Native 30 | - Works with existing React libraries such as Redux 31 | - Cross platform 32 | - No more Electron 33 | - Compatible with all normal Node.js packages 34 | - Hot reloading 35 | 36 | ## Images 37 | 38 | 39 | 40 | 41 | 42 | 43 | ## [Documentation](https://proton-native.js.org) 44 | 45 | See the documentation for how to get started and details on all the components. 46 | 47 | ## Examples 48 | 49 | Examples can be found in [`examples/`](https://github.com/kusti8/proton-native/tree/master/examples). 50 | 51 | ## Contributing 52 | 53 | All contributions are welcome. Just make a PR. 54 | 55 | Accelerated by KeyCDN 56 | -------------------------------------------------------------------------------- /__mocks__/node-qt.js: -------------------------------------------------------------------------------- 1 | const qt = jest.genMockFromModule('node-qt-napi'); 2 | 3 | function desktopSize() { 4 | return { w: 1920, h: 1080 }; 5 | } 6 | 7 | qt.desktopSize = desktopSize; 8 | 9 | export default qt; 10 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | proton-native.js.org -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Proton Native 2 | 3 | > Create desktop applications with React Native components, on all platforms 4 | 5 | calculator 6 | catapi_v2 7 | 8 | ## What's new in V2? 9 | 10 | V2 brought along a complete overhaul, written from the ground up. The source code is better organized, we now support flexbox layout, CSS 11 | styling, the same components as React Native, hot reloading, and are working on unit testing. More components and features can now be added easily. It is easier to install, with no compiling required. 12 | 13 | For the user, 14 | you can now copy and paste your React Native code with minimal to no changes. For our collaborators, it should now be more easy and friendly to 15 | bring this project right in line as the desktop port of React Native. 16 | 17 | For more information and a full writeup, see the [V2 page](v2_changes.md). 18 | 19 | ## Native Components? 20 | 21 | Currently we use Qt, which does not ship with true native components. Performance is basically the same and the look is very similar on almost all 22 | platforms, but we realize there is still a large demand for true native components in this project. There is a current experimental 23 | backend for wxWidgets and is described [here](wx_backend.md). Please note this is very not complete and still needs a lot more work. 24 | 25 | ## Why? 26 | 27 | On mobile, it used to be hard to build beautiful cross-platform apps. Then React Native came along, giving us 28 | a seamless way to build user interfaces and manage state in code, all while doing it cross platform. 29 | 30 | On desktop, there is no such tool. You can create a GUI using something like Qt, but for people who are used to the React workflow and JSX, there currently isn't an alternative. 31 | 32 | Some of you might be saying that you could do it in Electron. It's a good tool, but it brings in a lot of overhead, running a full webbrowser 33 | to manage a small GUI, while Proton Native can do the same, using native tools, with a smaller size and with less resource usage. 34 | 35 | Proton Native does the same 36 | to desktop that React Native did to mobile. Build cross-platform apps for the desktop, all while never leaving the React eco-system. Popular 37 | React packages such as Redux still work. 38 | 39 | **Here's a simple example in Proton Native:** 40 | 41 | [js_example.js](js_example.js ':include :type=code jsx') 42 | 43 | ## Features 44 | 45 | - Same syntax and components as React Native 46 | - Works with existing React libraries such as Redux 47 | - Cross platform 48 | - No more Electron 49 | - Compatible with all normal Node.js packages 50 | - Hot reloading 51 | - Flexbox 52 | - CSS styling 53 | 54 | ## Examples 55 | 56 | Check out [the examples](https://github.com/kusti8/proton-native/tree/master/examples) to see more. 57 | 58 | Accelerated by KeyCDN 59 | -------------------------------------------------------------------------------- /docs/SVG/Artboard 1.svg: -------------------------------------------------------------------------------- 1 | Artboard 1 -------------------------------------------------------------------------------- /docs/SVG/proton native.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/SVG/proton native.ai -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | Create desktop applications
6 |
through a React syntax, on all platforms.
7 |
8 |
9 | 10 | 44 | 45 | Github 46 | Get Started 47 | 48 | 56 | 57 | ![color](linear-gradient(to left bottom, #2e4466 0%, #afc1e0 100%)) 58 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - [Home](/) 2 | - [Quick start](quickstart.md) 3 | - [V2 Changes](v2_changes.md) 4 | - [About](about.md) 5 | - [Components](components.md) 6 | - Different Components 7 | - [Window](components/Window.md) 8 | - Advanced 9 | - [Packaging](packaging.md) 10 | - [Debugging](debugging.md) 11 | - [Native Components](wx_backend.md) 12 | - [Hot Reloading](hot_reloading.md) 13 | - [External Functionality](external_functionality.md) 14 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | Proton Native is a small project created by kusti8 to try and create a React interface for desktop app building. 4 | Proton Native was designed as an alternative to Electron. Rather than building apps that use the overhead of Electron and web 5 | technologies, Proton Native allows you to use native widgets cross platform, all in a React environment that you would get with 6 | Electron. 7 | 8 | **Advantages** 9 | 10 | - No large web browser running your app 11 | - Better system compatibility 12 | - Simple React components that are the same as React Native components 13 | - Constantly being improved and added to 14 | 15 | **Disadvantages** 16 | 17 | - Currently smaller than Electron 18 | - Smaller community since Proton Native is newer 19 | 20 | If you've been using Qt or frameworks like that successfully, then you may do so. But if you love working with React like I do, 21 | then Proton Native may be your best alternate to a full Electron app. 22 | 23 | ## By the numbers 24 | 25 | The electron quickstart averages at about 6% CPU and 0.6% memory on a i7-8550U with 16GB memory laptop, running Linux. 26 | 27 | The Proton Native example uses 1% CPU and 0.8% memory. 28 | 29 | As your projects get bigger and bigger, you're going to notice more memory usage in Electron due to the fact that its going to render more if you don't put significant effort into making it more efficient. Because Proton Native uses your native OS library, it's going to be more efficient in the long run. 30 | 31 | (These are my unbiased numbers that I got from a quick run. Your numbers are going to vary depending on size of project and computer.) 32 | 33 | ## How it Works 34 | 35 | Under the hood, there are two main libraries that are being used. 36 | 37 | - [node-qt-napi](https://github.com/kusti8/node-qt-napi) 38 | - Bindings for QT to create the components 39 | - [React-reconciler](https://github.com/facebook/react/tree/master/packages/react-reconciler) 40 | - Manages state, rerendering, etc. 41 | 42 | Each component is defined in `src/components`. All of these are composed of other functions which you will find in the folder, 43 | which defines many common functions such as adding children, removing them, updating props, etc. Then, in `src/index.js`, we give 44 | each component a string identifier, so that you import the string, rather than the class itself. Then in `src/createElement.js.`, 45 | when the reconciler tells us to create the class, we look it up in a map, and return the corresponding instance of the class. 46 | 47 | Some components are extended in `src/react-components`. This is to merge widgets together that we need to do in React. 48 | 49 | The reconciler lives in `src/reconciler`. This defines functions that manage all functions, mostly adding/removing children, and updating 50 | props. 51 | 52 | Finally, in `src/render`, we finally render it, by creating a root component that sets up Qt, creates a container, and then renders it. 53 | 54 | ## Future plans 55 | 56 | Proton Native is going to be maintained and added to for the foreseeable future. A small community has developed to try and improve it, and if you have an interest in helping contribute, you're always welcome. 57 | 58 | Currently, this is being run by one person, kusti8. All contributions are welcome! 59 | -------------------------------------------------------------------------------- /docs/calculator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/calculator.png -------------------------------------------------------------------------------- /docs/catapi_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/catapi_v2.png -------------------------------------------------------------------------------- /docs/components.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | The advantage of Proton Native is that all components are the same as React Native. Currently 4 | many props are not implemented, but many important ones are. As time progresses this will change. 5 | 6 | ## App 7 | 8 | The root wrapper around your entire code. 9 | 10 | ## Window 11 | 12 | Takes the same props as View. Each window instance corresponds to a new window on the 13 | desktop. More detailed information can be seen [here](components/Window.md) 14 | 15 | ## Other components 16 | 17 | | Component | Implemented Props | 18 | | ------------------------ | --------------------------------------------------------- | 19 | | Button | style, onPress, title | 20 | | Image | style, resizeMode, source | 21 | | Picker | style, onValueChange, selectedValue | 22 | | Picker.Item | label, value | 23 | | Text | style | 24 | | TouchableHighlight | activeOpacity, underlayColor, style, onPress, onLongPress | 25 | | TouchableOpacity | activeOpacity, style, onPress, onLongPress | 26 | | TouchableWithoutFeedback | onPress, onLongPress | 27 | | View | style, onMouseMove, onMouseEnter, onMouseLeave | 28 | -------------------------------------------------------------------------------- /docs/components/View.md: -------------------------------------------------------------------------------- 1 | # View 2 | 3 | `View` is a generic view component similar to `
` on the web. Views should be used to construct the layout. 4 | 5 | The following example creates a generic button component that implements _mouse hover_ effect. 6 | 7 | ```jsx 8 | import React from 'react'; 9 | import { View } from 'proton-native'; 10 | 11 | function Button({ children, onPress }) { 12 | const [isHover, setHover] = React.useState(false); 13 | return ( 14 | 15 | setHover(true)} 18 | onMouseLeave={() => setHover(false)} 19 | > 20 | {children} 21 | 22 | 23 | ); 24 | } 25 | ``` 26 | 27 | ## Props 28 | 29 | - [style](#style) 30 | - [onMouseMove](#onMouseMove) 31 | - [onMouseEnter](#onMouseEnter) 32 | - [onMouseLeave](#onMouseLeave) 33 | 34 | ## Reference 35 | 36 | ### style 37 | 38 | Height and width can be specified as integers, where they are treated 39 | as pixel counts, or percentages, where they are treated as percentages of the entire desktop size. 40 | 41 | | **Type** | **Required** | **Default** | 42 | | -------- | ------------ | ----------- | 43 | | object | No | {} | 44 | 45 | ### onMouseMove 46 | 47 | Called when mouse cursor is moving above the view. An event object is passed into the handler function. 48 | 49 | | **Type** | **Required** | **Default** | 50 | | ------------------------------- | ------------ | ----------- | 51 | | (event: MouseMoveEvent) => void | No | () => {} | 52 | 53 | ```typescript 54 | interface Point { 55 | x: number; 56 | y: number; 57 | } 58 | 59 | interface MouseMoveEvent { 60 | point: Point; 61 | } 62 | ``` 63 | 64 | ### onMouseEnter 65 | 66 | Called every time mouse cursor enters the view. 67 | 68 | | **Type** | **Required** | **Default** | 69 | | ---------- | ------------ | ----------- | 70 | | () => void | No | () => {} | 71 | 72 | ### onMouseLeave 73 | 74 | Called every time mouse cursor goes out of the view. 75 | 76 | | **Type** | **Required** | **Default** | 77 | | ---------- | ------------ | ----------- | 78 | | () => void | No | () => {} | 79 | -------------------------------------------------------------------------------- /docs/components/Window.md: -------------------------------------------------------------------------------- 1 | # Window 2 | 3 | Window is currently a component that is different than React Native. We create this as a separate component rather than 4 | just creating a window for you in case you want to create multiple windows. 5 | 6 | The following creates a window that takes up 50% of the desktop in height, and 20% of the width. 7 | 8 | ```jsx 9 | import React, { Component } from 'react'; 10 | 11 | import { AppRegistry, Window, App } from 'proton-native'; 12 | 13 | class Example extends Component { 14 | render() { 15 | return ( 16 | 17 | 18 | 19 | ); 20 | } 21 | } 22 | 23 | AppRegistry.registerComponent('Test', ); 24 | ``` 25 | 26 | ## Props 27 | 28 | - [style](#style) 29 | - [onResize](#onResize) 30 | - [onMove](#onMove) 31 | 32 | ## Reference 33 | 34 | ### style 35 | 36 | Accepts all the same styles as View. Height and width can be specified as integers, where they are treated 37 | as pixel counts, or percentages, where they are treated as percentages of the entire desktop size. 38 | 39 | | **Type** | **Required** | **Default** | 40 | | -------- | ------------ | ----------- | 41 | | object | No | {} | 42 | 43 | ### onResize 44 | 45 | Called when the window is resized. An object is passed into the function, with the following 46 | object: `{w, h}` 47 | 48 | | **Type** | **Required** | **Default** | 49 | | -------------------------------- | ------------ | ----------- | 50 | | function({h: number, w: number}) | No | () => {}) | 51 | 52 | ### onMove 53 | 54 | Called when the window is moved. An object is passed into the function, with the following 55 | object: `{x, y}` 56 | 57 | | **Type** | **Required** | **Default** | 58 | | -------------------------------- | ------------ | ----------- | 59 | | function({x: number, y: number}) | No | () => {}) | 60 | -------------------------------------------------------------------------------- /docs/debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging 2 | 3 | ## react-devtools 4 | 5 | Currently, Proton Native allows you to use `react-devtools` to debug your code out of the box. 6 | 7 | It works automatically if you: 8 | 9 | - Have `react-devtools-core` installed (directly or as a dependency of `react-devtools`) 10 | - Have `react-devtools` running 11 | 12 | It will not work if `NODE_ENV` is set to `production`. 13 | -------------------------------------------------------------------------------- /docs/external_functionality.md: -------------------------------------------------------------------------------- 1 | # External Functionality 2 | 3 | Some functionality will probably never make it to Proton Native, but that doesn't mean that it isn't possible. 4 | This is a list of external tools found that help common tasks. **All of these are designed to be cross platform.** 5 | 6 | ## Tools 7 | 8 | - [System Tray](#System-Tray) 9 | - [Notifications](#Notifications) 10 | 11 | ## System Tray 12 | 13 | https://zaaack.github.io/node-systray/index.html 14 | 15 | ```jsx 16 | import React, { Component } from 'react'; 17 | import SysTray from 'systray'; 18 | import fs from 'fs'; 19 | 20 | import { AppRegistry, Window, App, View, TextInput } from 'proton-native'; 21 | 22 | const systray = new SysTray({ 23 | menu: { 24 | // you should using .png icon in macOS/Linux, but .ico format in windows 25 | icon: new Buffer(fs.readFileSync('/.../icon.png')).toString('base64'), 26 | title: 'Test', 27 | tooltip: 'Tips', 28 | items: [ 29 | { 30 | title: 'Item', 31 | tooltip: 'Item Tooltip', 32 | enabled: true, 33 | }, 34 | { 35 | title: 'Exit', 36 | tooltip: 'bb', 37 | enabled: true, 38 | }, 39 | ], 40 | }, 41 | debug: false, 42 | copyDir: true, 43 | }); 44 | 45 | systray.onClick(action => { 46 | if (action.seq_id === 0) { 47 | console.log('Hi!'); 48 | } else if (action.seq_id === 1) { 49 | systray.kill(); 50 | } 51 | }); 52 | 53 | const stop = () => { 54 | systray.kill(false); 55 | }; 56 | 57 | class Example extends Component { 58 | render() { 59 | return ( 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | AppRegistry.registerComponent('example', ); 72 | ``` 73 | 74 | ## Notifications 75 | 76 | https://github.com/mikaelbr/node-notifier 77 | -------------------------------------------------------------------------------- /docs/hot_reloading.md: -------------------------------------------------------------------------------- 1 | # Hot Reloading 2 | 3 | Proton Native now has support for hot reloading right out of the box! This allows you to edit code 4 | and see the results appear instantly, without modifying any of the state. 5 | 6 | ## Usage 7 | 8 | All of this is baked into your Proton Native application when it is created with the 9 | `proton-native-cli`. 10 | 11 | ```bash 12 | npm run dev # Starts the server and your application with it 13 | ``` 14 | 15 | ## How it works 16 | 17 | Knowing how hot reloading works can be useful if you want to use it in 18 | particularly advanced situations. 19 | 20 | Hot reloading revolves around webpack. Every Proton Native application is shipped 21 | with a default `webpack.config.js` that is suitable for most applications. It will package everything into 22 | one JS file in the `dist/` directory, and watch for any changes. 23 | 24 | Changes are communicated to your `index.js` file. This file renders your component, 25 | accepts any update notifications, and if so, pulls the latest version, and forces 26 | an update down the entire React tree. Using `react-proxy`, your state stays the same 27 | while all necessary components are updated. `react-proxy` is baked into Proton Native, 28 | and is only used in development mode (ie. setting `NODE_ENV` to `production` disables 29 | hot reloading). 30 | 31 | ## Gotchas 32 | 33 | - Don't register your component in `app.js`, only in `index.js` 34 | - Make sure your root component is the default export in `app.js` 35 | - This does not currently work with Redux (any help is appreciated) 36 | - Does not work with class instance properties (due to `react-proxy`) 37 | - To get around this, instead create a function which returns your value. More details can be seen inside the Calculator example. 38 | -------------------------------------------------------------------------------- /docs/images/CatApi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/images/CatApi.gif -------------------------------------------------------------------------------- /docs/images/app_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/images/favicon.png -------------------------------------------------------------------------------- /docs/images/icon_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | icon_white 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/images/icon_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | icon_white 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/images/logo_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | logo_black 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 28 | 35 | 48 | 53 | 63 | 66 | 72 | 77 | 87 | 91 | 98 | 102 | 109 | 113 | 120 | 123 | 129 | 131 | 135 | 139 | 146 | 150 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/images/logo_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | logo_white 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 27 | 32 | 36 | 41 | 45 | 49 | 53 | 57 | 60 | 64 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/images/windows_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/images/windows_example.png -------------------------------------------------------------------------------- /docs/images/windows_packaging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kusti8/proton-native/ab482b120542951628292211b989e504fa4a3985/docs/images/windows_packaging.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Proton Native - React Native for the desktop, cross compatible 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/js_example.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { AppRegistry, Window, App, Button, Picker, View } from 'proton-native'; 4 | 5 | class Example extends Component { 6 | render() { 7 | return ( 8 | 9 | 10 | 11 | 86 | 87 | {this.props.url} 88 | 89 | 90 | 91 | 92 | ); 93 | } 94 | } 95 | ``` 96 | 97 | After 2 years, some of the deficiencies of V1 started coming to light, which can mainly 98 | be summarized in the following categories. All the rest of the changes stem from these problems. 99 | 100 | - Lack of components 101 | - Difficult layout 102 | - Lack of styling 103 | - Difficult installation 104 | 105 | ## Lack of Components 106 | 107 | The Proton Native issue tracker was being flooded with requests for more components 108 | so that people could do more with the tool. Already, the decisions I made in the 109 | beginning were starting to show their effects. I used `libui-node` because at the 110 | time it was the best GUI bindings for Node.js that I could find. It is based on 111 | the `libui` library, a fantastic effort to create native components for all platforms. 112 | Yet it is in alpha, and `libui-node` is slow to get updates from upstream. 113 | 114 | I could not add more components because I was relying on an alpha library and was 115 | not in control of the bindings. I wish `libui` the best, but Proton Native needed 116 | a more mature library. The two major players in GUI libraries that offer good cross platform support and are very mature are Qt and wxWidgets. I chose to use Qt because of my familiarity with it, the ease of CSS styling, and the simple API. 117 | 118 | There are no maintained Qt bindings for Node.js that I can find, and my experience with 119 | `libui-node` left be a bit cautious about relying on other bindings. I decided 120 | to create my own bindings, called `node-qt-napi`. These bindings very thin, but not meant to be entirely general purpose. Some functions are not wrapped because they are not used in Proton Native. A couple other custom functions are added to the bindings (such as image tiling) for Proton Native. 121 | 122 | Yet this decision allowed development to be much faster because I could work with 123 | Qt itself instead of with bindings. It also meant I can mirror the components of 124 | React Native for a seamless transition to Proton Native. 125 | Once work was done, I added a general layer sothat other libraries can be 126 | seamessly added to Proton Native. 127 | 128 | ### Native Components? 129 | 130 | Different GUI designers have different priorities. Some want something that looks pretty while others 131 | want something that will ensure a great experience on every platform. Qt gives you the ability to 132 | customize everything, and still has a pretty good experience with its components. But those components 133 | are not native, meaning they are drawn by Qt instead of using the components provided by the OS. 134 | 135 | Proton Native was mainly built to emulate React Native, which doesn't use many native components 136 | for drawing. But native components on the desktop are important for some people and for that, 137 | Proton Native V2 has two backends: Qt and wxWidgets. 138 | 139 | Qt will always be the main backend, and right now the wxWidgets backend has very little components, 140 | customizability, and is still experimental. It is actively being worked on to bring it up to par 141 | with Qt (although it will never support the same easy styling as Qt). To use wxWidgets, see 142 | the [dedicated page](wx_backend.md), but remember that it is still experimental. 143 | 144 | ### Licensing? 145 | 146 | _Note that I am not a lawyer._ 147 | 148 | Licensing is always an issue when developing code. Qt is licensed under LGPL, a variation 149 | on GPL. GPL by itself means that any changes must be made public. LGPL is a bit more 150 | permissive, essentially saying that if the Qt binaries can be replaced your code can be closed source. 151 | Proton Native is licensed under MIT and makes sure that it is always dynamically links 152 | with Qt, so your code is free to be closed source if you so wish. 153 | 154 | ## Difficult layout 155 | 156 | Layout was difficult on V1 due to using `libui` with its own layout system. I proposed 157 | changes that would allow manual placement and resizing so that custom layout systems 158 | could be used. However, this change demanded careful thought and was not ready 159 | to be added at the time. 160 | 161 | Qt brings its own layout system as well, but allows manual placement as a fallback. 162 | With this available, I implemented `yoga-layout` so that users can place components 163 | with the Flexbox system that they are accustomed to. 164 | 165 | ## Lack of Styling 166 | 167 | V1 also lacked styling, so everything was themed basically. It was fine for basic 168 | applications, but for more complex ones it made Proton Native very difficult to use. 169 | Qt supports CSS styling, so this was relatively easy to implement, and now supports 170 | almost the entire `style` object that React Native does. 171 | 172 | ## Difficult Installation 173 | 174 | Almost a quarter of the bugs on the issue tracker stem from installation issues with 175 | `libui-node`, especially on Windows. This presented a great barrier to usage. V2 uses 176 | two C++ libaries, `yoga-layout` and `node-qt-napi`. Both of these come with prebuilt 177 | binaries so that installation is seamless (you can always compile it yourself if you 178 | so want). Proton Native uses `yoga-layout-prebuilt` for `yoga-layout` and compiles binaries for NAPI versions 2, 3, and 4 supporting all modern Node.js versions on 179 | Linux, Mac and Windows. 180 | 181 | ## And finally, a little treat... 182 | 183 | To make developing with Proton Native even easier, I've implemented hot reloading 184 | with Proton Native V2. This is built into every starter application, as an 185 | optional script that you can run. It's as easy as running `npm run dev` instead of 186 | `npm run start`. Together with `webpack` and `react-proxy`, this means that changes 187 | you make in the script will be immediately reflected in what you see, without changing 188 | the state. 189 | 190 | ## To get started 191 | 192 | Installation is simple with the `proton-native-cli` app. 193 | 194 | ```bash 195 | # install the cli app 196 | npm install -g proton-native-cli 197 | # create your project 198 | proton-native init my-app 199 | # move to your project directory 200 | cd my-app 201 | 202 | # run your app 203 | npm run start 204 | # OR to run with hot reloading 205 | npm run dev 206 | ``` 207 | 208 | ## Note on Macs 209 | 210 | Due to a bug in [libuv#2593](https://github.com/libuv/libuv/pull/2593) which Node.js uses ([reported in node#31328](https://github.com/nodejs/node/issues/31328)) Proton Native 211 | does not work on Macs with Node versions >12.13.1 and >13.0.1. Until this is fixed, 212 | it is recommended to use a Node version less than these (which can be easily 213 | installed with `nvm`). 214 | 215 | ## Changelog 216 | 217 | - Flexbox 218 | - Allows much easier styling and arrangement, that is the same as React Native 219 | - Uses yoga-layout 220 | - Styling 221 | - Styling is now supported through Qt. This allows you to make your app look however you want. 222 | - Qt instead of libui 223 | - Libui was moving slowly, new, and did not support many of the features needed 224 | - In the future, I will be moving towards true native components with wxWidgets, but it will take some time. 225 | - Composition instead of inheritance 226 | - The code was remodeled to be less confusing and easier to change in the future 227 | - Same components as React Native 228 | - We use the same components with the same props and the same look 229 | - This means that if you copy and paste your code, it should look the same 230 | - We still ensure that we don't make comprimises just for compatibility sake (like the ability to create multiple Windows) 231 | - Hot Reloading 232 | - Allows quick developing for your apps. 233 | - Improved Devtools support 234 | - The `react-devtool` support is now much more robust for better debugging. 235 | - `proton-native-cli` 236 | - An entirely new management utility which allows for future additions if needed as well. 237 | - Typescript 238 | - All of the code was converted over to Typescript to reduce bugs. The implementation needs to be better and more safe, but it works for now. 239 | 240 | ## Examples 241 | 242 | There are plenty of examples in the examples folder to showcase what Proton Native 243 | can do. Here's one of a calculator, modeled on the iOS calculator. The full code can be 244 | found in the examples folder. 245 | 246 | calculator 247 | 248 | ```jsx 249 | class Calculator extends Component { 250 | // ... 251 | render() { 252 | return ( 253 | 254 | 255 | 263 | 273 | {this.state.primary.toString().length >= 7 274 | ? this.state.primary.toExponential(4) 275 | : this.state.primary} 276 | 277 | 278 | {this.getButtons().map((buttonGroup, index1) => ( 279 | 287 | {buttonGroup.map((button, index2) => ( 288 | 295 | {button.text} 296 | 297 | ))} 298 | 299 | ))} 300 | 301 | 302 | ); 303 | } 304 | } 305 | ``` 306 | 307 | ## Proton Native vs. Others 308 | 309 | Since Proton Native started, a lot of other projects have started with the same 310 | objective. The goals of Proton Native are always to have an easy development 311 | experience for the user, with plenty of documentation, ability to use tools 312 | they are familiar with, and eventually be stable. 313 | 314 | The most notable projects similar to Proton Native are `react-nodegui` and 315 | `react-native-desktop`. 316 | 317 | - `react-nodegui` 318 | - Aims to port Qt to React. Features an API similar to Qt, not to React Native. 319 | - Uses `qode`, a fork of `node` 320 | - Relatively good documentation 321 | - `react-native-desktop` 322 | - A fork of React Native, to add desktop as a new target. 323 | - Means that React Native code should just work, but also means no support for windows, menus etc. 324 | - Relatively little documentation 325 | 326 | ## Contributions 327 | 328 | Currently, Proton Native is headed by one high school senior with not enough time. 329 | V2 took a lot longer than I would have liked it to. There is still a lot more work to 330 | be done. PRs are always welcomed and I would love to advance this project as quickly 331 | as possible. 332 | 333 | If you don't want to contribute with code, you can also [sponsor me through GitHub](https://github.com/sponsors/kusti8). 334 | However, there is no obligation on your part to sponsor. 335 | 336 | ## What's Next? 337 | 338 | I look forward to improving Proton Native so that there is an easy way to create 339 | apps with React on desktop. I am always open to suggestions, improvements, and 340 | anything that can be done to make this project better. With that, the following items 341 | are being planned. 342 | 343 | - More components 344 | - Keep on adding more and more components so users can create apps more easily 345 | - Add wxWidgets as a second backend 346 | - This will require serious work, due to the lack of CSS styling and my unfamiliarity with it, but this is an important improvement for user choice 347 | - More props 348 | - Right now only the barebones props are supported for all the components. I would like to bring this in line with what React Native has. 349 | 350 | Proton Native has a bright future, and I will continue to keep improving it. Thank you! 351 | -------------------------------------------------------------------------------- /docs/wx_backend.md: -------------------------------------------------------------------------------- 1 | # Native Components 2 | 3 | **This is still experimental!** 4 | 5 | Native components can be used by switching the backend that Proton Native uses to 6 | wxWidgets. Currently, only a few components are supported, although this list 7 | is constantly improving. 8 | 9 | ## Note on Macs 10 | 11 | Due to a bug in [libuv#2593](https://github.com/libuv/libuv/pull/2593) which Node.js uses ([reported in node#31328](https://github.com/nodejs/node/issues/31328)) Proton Native 12 | does not work on Macs with Node versions >12.13.1 and >13.0.1. Until this is fixed, 13 | it is recommended to use a Node version less than these (which can be easily 14 | installed with `nvm`). 15 | 16 | ## Getting Started 17 | 18 | Changing backends is relatively easy. 19 | 20 | First install the backend. 21 | 22 | ```bash 23 | npm i -S node-wx-napi # Install the backend 24 | ``` 25 | 26 | Then add the following to the top of your code. 27 | 28 | ```js 29 | import { setBackend } from 'proton-native'; 30 | 31 | setBackend('wx'); // Default is 'qt' 32 | ``` 33 | 34 | ## Supported Components 35 | 36 | Only some props of style are supported and as such are 37 | indicated in parenthesis. All sizing and placement props are supported, 38 | but visual props, such as fontWeight and stuff are not. 39 | 40 | | Component | Props | 41 | | --------- | --------------------------------------- | 42 | | App | | 43 | | Window | style (backgroundColor), onResize | 44 | | View | style (backgroundColor) | 45 | | Button | style (backgroundColor), onPress, title | 46 | -------------------------------------------------------------------------------- /examples/Calculator/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/Calculator/app.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | App, 4 | AppRegistry, 5 | Window, 6 | Text, 7 | View, 8 | TouchableOpacity, 9 | } from 'proton-native'; 10 | 11 | class CircleButton extends Component { 12 | render() { 13 | return ( 14 | 25 | 32 | {this.props.children} 33 | 34 | 35 | ); 36 | } 37 | } 38 | 39 | const buttonStyle = { 40 | primary: { 41 | backgroundColor: '#FC9E34', 42 | color: 'white', 43 | size: 40, 44 | }, 45 | secondary: { 46 | backgroundColor: '#A4A4A4', 47 | color: '#010101', 48 | size: 30, 49 | }, 50 | number: { 51 | backgroundColor: '#363636', 52 | color: 'white', 53 | size: 40, 54 | }, 55 | }; 56 | 57 | export default class Calculator extends Component { 58 | state = { 59 | secondary: 0, 60 | primary: 0, 61 | operator: '', 62 | justChanged: false, 63 | decimal: false, 64 | }; 65 | getButtons() { 66 | // this can't be an instance variable or else it won't get hot reloaded 67 | return [ 68 | [ 69 | { 70 | text: 'AC', 71 | type: 'secondary', 72 | onPress: () => 73 | this.setState({ 74 | primary: 0, 75 | secondary: 0, 76 | operator: '', 77 | decimal: false, 78 | justChanged: false, 79 | }), 80 | }, 81 | { 82 | text: '+/-', 83 | type: 'secondary', 84 | onPress: () => this.setState({ primary: -this.state.primary }), 85 | }, 86 | { 87 | text: '%', 88 | type: 'secondary', 89 | onPress: () => 90 | this.setState({ 91 | primary: this.state.primary / 100, 92 | }), 93 | }, 94 | { 95 | text: '÷', 96 | type: 'primary', 97 | onPress: () => this.changeOperator('/'), 98 | }, 99 | ], 100 | [ 101 | { 102 | text: '7', 103 | type: 'number', 104 | onPress: () => this.addDigit(7), 105 | }, 106 | { 107 | text: '8', 108 | type: 'number', 109 | onPress: () => this.addDigit(8), 110 | }, 111 | { 112 | text: '9', 113 | type: 'number', 114 | onPress: () => this.addDigit(9), 115 | }, 116 | { 117 | text: '×', 118 | type: 'primary', 119 | onPress: () => this.changeOperator('*'), 120 | }, 121 | ], 122 | [ 123 | { 124 | text: '4', 125 | type: 'number', 126 | onPress: () => this.addDigit(4), 127 | }, 128 | { 129 | text: '5', 130 | type: 'number', 131 | onPress: () => this.addDigit(5), 132 | }, 133 | { 134 | text: '6', 135 | type: 'number', 136 | onPress: () => this.addDigit(6), 137 | }, 138 | { 139 | text: '-', 140 | type: 'primary', 141 | onPress: () => this.changeOperator('-'), 142 | }, 143 | ], 144 | [ 145 | { 146 | text: '1', 147 | type: 'number', 148 | onPress: () => this.addDigit(1), 149 | }, 150 | { 151 | text: '2', 152 | type: 'number', 153 | onPress: () => this.addDigit(2), 154 | }, 155 | { 156 | text: '3', 157 | type: 'number', 158 | onPress: () => this.addDigit(3), 159 | }, 160 | { 161 | text: '+', 162 | type: 'primary', 163 | onPress: () => this.changeOperator('+'), 164 | }, 165 | ], 166 | [ 167 | { 168 | text: '0', 169 | type: 'number', 170 | width: 185, 171 | start: true, 172 | onPress: () => this.addDigit(0), 173 | }, 174 | { 175 | text: '.', 176 | type: 'number', 177 | onPress: () => this.setState({ decimal: true }), 178 | }, 179 | { 180 | text: '=', 181 | type: 'primary', 182 | onPress: () => this.changeOperator('+'), 183 | }, 184 | ], 185 | ]; 186 | } 187 | 188 | addDigit(new_digit) { 189 | if (this.state.justChanged) { 190 | if (this.state.decimal) { 191 | this.setState({ 192 | secondary: this.state.primary, 193 | primary: new_digit / 10, 194 | justChanged: false, 195 | }); 196 | } else { 197 | this.setState({ 198 | secondary: this.state.primary, 199 | primary: new_digit, 200 | justChanged: false, 201 | }); 202 | } 203 | } else if (!this.state.decimal) { 204 | this.setState({ 205 | primary: 10 * this.state.primary + new_digit, 206 | }); 207 | } else if (this.state.decimal) { 208 | if (this.state.primary.toString().indexOf('.') == -1) { 209 | this.setState({ 210 | primary: parseFloat( 211 | this.state.primary.toString() + '.' + new_digit.toString() 212 | ), 213 | }); 214 | } else { 215 | this.setState({ 216 | primary: parseFloat( 217 | this.state.primary.toString() + new_digit.toString() 218 | ), 219 | }); 220 | } 221 | } 222 | } 223 | 224 | changeOperator(new_operator) { 225 | if (this.state.operator === '+') { 226 | this.setState({ 227 | secondary: 0, 228 | primary: this.state.secondary + this.state.primary, 229 | operator: new_operator, 230 | justChanged: true, 231 | }); 232 | } else if (this.state.operator === '-') { 233 | this.setState({ 234 | secondary: 0, 235 | primary: this.state.secondary - this.state.primary, 236 | operator: new_operator, 237 | justChanged: true, 238 | }); 239 | } else if (this.state.operator === '/') { 240 | this.setState({ 241 | secondary: 0, 242 | primary: this.state.secondary / this.state.primary, 243 | operator: new_operator, 244 | justChanged: true, 245 | }); 246 | } else if (this.state.operator === '*') { 247 | this.setState({ 248 | secondary: 0, 249 | primary: this.state.secondary * this.state.primary, 250 | operator: new_operator, 251 | justChanged: true, 252 | }); 253 | } else { 254 | this.setState({ operator: new_operator, justChanged: true }); 255 | } 256 | } 257 | 258 | render() { 259 | return ( 260 | 261 | 262 | 270 | 280 | {this.state.primary.toString().length >= 7 281 | ? this.state.primary.toExponential(4) 282 | : this.state.primary} 283 | 284 | 285 | {this.getButtons().map((buttonGroup, index1) => ( 286 | 294 | {buttonGroup.map((button, index2) => ( 295 | 302 | {button.text} 303 | 304 | ))} 305 | 306 | ))} 307 | 308 | 309 | ); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /examples/Calculator/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AppRegistry } from 'proton-native'; 3 | import Calculator from './app'; 4 | 5 | AppRegistry.registerComponent('calculator', ); // and finally render your main component 6 | 7 | // ================================================================================ 8 | // This is for hot reloading (this will be stripped off in production by webpack) 9 | // THIS SHOULD NOT BE CHANGED 10 | if (module.hot) { 11 | module.hot.accept(['./app'], function() { 12 | const app = require('./app')['default']; 13 | AppRegistry.updateProxy(app); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /examples/Calculator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "calculator", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "babel-node index.js", 8 | "dev": "webpack --mode=development ", 9 | "webpackRun": "babel-node dist/index.out.js", 10 | "build": "babel index.js -d bin/" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "proton-native": "^2.0.0" 16 | }, 17 | "devDependencies": { 18 | "@babel/cli": "^7.4.4", 19 | "@babel/core": "^7.4.4", 20 | "@babel/node": "^7.2.2", 21 | "@babel/plugin-proposal-class-properties": "^7.4.4", 22 | "@babel/preset-env": "^7.4.4", 23 | "@babel/preset-react": "^7.0.0", 24 | "@babel/preset-stage-0": "^7.0.0", 25 | "babel-loader": "^8.0.6", 26 | "react-devtools": "^4.0.0", 27 | "webpack": "^4.41.5", 28 | "webpack-cli": "^3.3.10", 29 | "webpack-node-externals": "^1.7.2", 30 | "ws": "^7.2.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/Calculator/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const nodeExternals = require('webpack-node-externals'); 4 | const spawn = require('child_process').spawn; 5 | 6 | module.exports = (env, argv) => { 7 | const config = { 8 | mode: 'production', 9 | entry: ['./index.js'], 10 | target: 'node', 11 | output: { 12 | path: path.resolve(__dirname, 'dist'), 13 | filename: 'index.out.js', 14 | }, 15 | node: { 16 | __dirname: false, 17 | __filename: false, 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.(j|t)sx?$/, 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'babel-loader', 26 | options: { cacheDirectory: true, cacheCompression: false }, 27 | }, 28 | }, 29 | { 30 | test: /\.(png|jpe?g|gif|svg|bmp)$/i, 31 | use: [{ loader: 'file-loader' }], 32 | }, 33 | { 34 | test: /\.node/i, 35 | use: [{ loader: 'node-loader' }, { loader: 'file-loader' }], 36 | }, 37 | ], 38 | }, 39 | plugins: [ 40 | { 41 | apply: compiler => { 42 | let instance = null; 43 | compiler.hooks.afterEmit.tap('AfterEmitPlugin', compilation => { 44 | if (instance) { 45 | return; 46 | } 47 | instance = spawn('npm', ['run', 'webpackRun']); 48 | instance.stdout.on('data', function(data) { 49 | console.log(data.toString()); 50 | }); 51 | 52 | instance.stderr.on('data', function(data) { 53 | console.log(data.toString()); 54 | }); 55 | 56 | instance.on('exit', function(code) { 57 | console.log('child process exited with code ' + code.toString()); 58 | process.exit(code); 59 | }); 60 | }); 61 | }, 62 | }, 63 | ], 64 | resolve: { 65 | extensions: ['.tsx', '.ts', '.js', '.jsx', '.json'], 66 | }, 67 | externals: [ 68 | nodeExternals({ 69 | whitelist: ['webpack/hot/dev-server', 'webpack/hot/poll?100'], 70 | }), 71 | ], 72 | }; 73 | 74 | if (argv.mode === 'development') { 75 | config.mode = 'development'; 76 | config.plugins.push(new webpack.HotModuleReplacementPlugin()); 77 | config.devtool = 'source-map'; 78 | config.watch = true; 79 | config.stats = 'errors-only'; 80 | config.entry.unshift('webpack/hot/poll?100'); 81 | } 82 | 83 | return config; 84 | }; 85 | -------------------------------------------------------------------------------- /examples/CatApi/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } 5 | -------------------------------------------------------------------------------- /examples/CatApi/app.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; // import from react 2 | import { createStore, applyMiddleware } from 'redux'; 3 | import { Provider } from 'react-redux/lib/alternate-renderers'; 4 | import thunk from 'redux-thunk'; 5 | import rootReducer from './src/reducers'; 6 | import Main from './src/components/main'; 7 | 8 | const store = createStore(rootReducer, applyMiddleware(thunk)); 9 | 10 | export default class CatApi extends Component { 11 | render() { 12 | return ( 13 | 14 |
15 | 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/CatApi/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AppRegistry } from 'proton-native'; 3 | import CatApi from './app'; 4 | 5 | AppRegistry.registerComponent('CatApi', ); // and finally render your main component 6 | 7 | // ================================================================================ 8 | // This is for hot reloading (this will be stripped off in production by webpack) 9 | // THIS SHOULD NOT BE CHANGED 10 | if (module.hot) { 11 | module.hot.accept(['./app'], function() { 12 | const app = require('./app')['default']; 13 | AppRegistry.updateProxy(app); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /examples/CatApi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CatApi", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "babel-node index.js", 7 | "dev": "webpack --mode=development ", 8 | "webpackRun": "babel-node dist/index.out.js", 9 | "build": "babel index.js -d bin/" 10 | }, 11 | "dependencies": { 12 | "node-fetch": "^2.1.2", 13 | "opn": "^5.3.0", 14 | "proton-native": "^2.0.0", 15 | "react-redux": "^7.0.0", 16 | "redux": "^4.0.0", 17 | "redux-thunk": "^2.2.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/cli": "^7.4.4", 21 | "@babel/core": "^7.4.4", 22 | "@babel/node": "^7.2.2", 23 | "@babel/plugin-proposal-class-properties": "^7.4.4", 24 | "@babel/preset-env": "^7.4.4", 25 | "@babel/preset-react": "^7.0.0", 26 | "@babel/preset-stage-0": "^7.0.0", 27 | "webpack": "^4.41.5", 28 | "webpack-cli": "^3.3.10", 29 | "webpack-node-externals": "^1.7.2", 30 | "babel-loader": "^8.0.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/CatApi/src/actions/index.js: -------------------------------------------------------------------------------- 1 | import actionConsts from '../consts'; 2 | import fetch from 'node-fetch'; 3 | import querystring from 'querystring'; 4 | import opn from 'opn'; 5 | 6 | export const setCategory = category => ({ 7 | type: actionConsts.CATEGORY, 8 | category, 9 | }); 10 | 11 | export const setId = id => ({ 12 | type: actionConsts.SET_ID, 13 | id, 14 | }); 15 | 16 | export const setSize = size => ({ 17 | type: actionConsts.SIZE, 18 | size, 19 | }); 20 | 21 | export const setType = format => ({ 22 | type: actionConsts.TYPE, 23 | format, 24 | }); 25 | 26 | export const setUrl = url => ({ 27 | type: actionConsts.URL, 28 | url, 29 | }); 30 | 31 | export const setFetching = fetching => ({ 32 | type: actionConsts.FETCHING, 33 | fetching, 34 | }); 35 | 36 | const toParams = state => { 37 | let out = {}; 38 | for (let prop in state) { 39 | if (state[prop] != '' && prop != 'url') { 40 | out[prop] = state[prop]; 41 | } 42 | } 43 | return out; 44 | }; 45 | 46 | export const search = () => { 47 | return (dispatch, getState) => { 48 | const BASE_URL = 'http://api.thecatapi.com/api/images/get?'; 49 | const str = querystring.stringify(toParams(getState())); 50 | return fetch(BASE_URL + str, { redirect: 'manual' }) 51 | .then(res => res.headers.get('location')) 52 | .then(url => { 53 | dispatch(setUrl(url)); 54 | opn(url); 55 | }); 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /examples/CatApi/src/components/main.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | App, 4 | Window, 5 | Text, 6 | TextInput, 7 | View, 8 | Picker, 9 | Button, 10 | Image, 11 | } from 'proton-native'; 12 | import * as Actions from '../actions'; 13 | import { sizeConsts, typeConsts } from '../consts'; 14 | import { connect } from 'react-redux/lib/alternate-renderers'; 15 | import { bindActionCreators } from 'redux'; 16 | 17 | class Main extends Component { 18 | render() { 19 | return ( 20 | 21 | 22 | 23 | 30 | CatApi 31 | 32 | 33 | ID 34 | this.props.setId(id)} 36 | value={this.props.id} 37 | style={{ flex: 1 }} 38 | /> 39 | 40 | 41 | Size 42 | this.props.setSize(val)} 46 | > 47 | {sizeConsts.map((s, i) => ( 48 | 49 | ))} 50 | 51 | 52 | 53 | Type 54 | this.props.setType(val)} 58 | > 59 | {typeConsts.map((s, i) => ( 60 | 61 | ))} 62 | 63 | 64 | 71 |