├── .github └── workflows │ ├── main.yml │ └── size.yml ├── .gitignore ├── .vscode └── settings.json ├── CONTRIBUTION.md ├── LICENSE ├── README.md ├── README_API_CHECKLIST.md ├── banner ├── Cover.png ├── example-1.gif └── high-res-example.gif ├── example ├── .npmignore ├── img │ ├── Vector.png │ └── flutter.png ├── index.css ├── index.html ├── index.tsx ├── package-lock.json ├── package.json ├── sample.json ├── tsconfig.json └── yarn.lock ├── package-lock.json ├── package.json ├── src ├── addProperty.tsx ├── buildDartASTfromAST.tsx ├── clearProperties.tsx ├── config │ ├── flutter-widgets.ts │ ├── index.ts │ ├── layout-props.ts │ └── text-props.ts ├── index.tsx └── utils │ ├── arr.js │ ├── camel.ts │ ├── converter.tsx │ ├── getAlignmentAxis.tsx │ ├── getBorder.tsx │ ├── getBorderRadius.tsx │ ├── getExpanded.tsx │ ├── getFlex.tsx │ ├── getFlexDirection.tsx │ ├── getFontFamily.tsx │ ├── getFontStyle.tsx │ ├── getFontWeight.tsx │ ├── getMargin.tsx │ ├── getPadding.tsx │ ├── getPositioned.tsx │ ├── getTextAlign.tsx │ ├── num.ts │ ├── pos.js │ ├── pushPropToWidget.tsx │ ├── str.js │ └── unit.ts ├── test └── blah.test.tsx ├── tsconfig.json └── yarn.lock /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} 6 | 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | node: ['10.x', '12.x', '14.x'] 11 | os: [ubuntu-latest, windows-latest, macOS-latest] 12 | 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v2 16 | 17 | - name: Use Node ${{ matrix.node }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Install deps and build (with cache) 23 | uses: bahmutov/npm-install@v1 24 | 25 | - name: Lint 26 | run: yarn lint 27 | 28 | - name: Test 29 | run: yarn test --ci --coverage --maxWorkers=2 30 | 31 | - name: Build 32 | run: yarn build 33 | -------------------------------------------------------------------------------- /.github/workflows/size.yml: -------------------------------------------------------------------------------- 1 | name: size 2 | on: [pull_request] 3 | jobs: 4 | size: 5 | runs-on: ubuntu-latest 6 | env: 7 | CI_JOB_NUMBER: 1 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: andresz1/size-limit-action@v1 11 | with: 12 | github_token: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | .cache 5 | dist 6 | .vercel 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "flexbox", 4 | "Funit" 5 | ] 6 | } -------------------------------------------------------------------------------- /CONTRIBUTION.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We want to make contributing to this project as easy and transparent as possible and we are grateful for, any contributions made by the community. 4 | 5 | ## Reporting Issues and Asking Questions 6 | 7 | Before opening an issue, please search the [issue tracker](https://github.com/GeekyAnts/react-native-to-flutter/issues) to make sure your issue hasn't already been reported. 8 | 9 | ### Bugs and Improvements 10 | 11 | We use the issue tracker to keep track of bugs and improvements to React Native to Flutter Widgets itself, its examples, and the documentation. We encourage you to open issues to discuss improvements, architecture, theory, internal implementation, etc. If a topic has been discussed before, we will ask you to join the previous discussion. 12 | 13 | ## Development 14 | 15 | Visit the [issue tracker](https://github.com/GeekyAnts/react-native-to-flutter/issues) to find a list of open issues that need attention. 16 | 17 | ### Building 18 | 19 | 20 | Clone the repo, run 21 | 22 | ``` 23 | git clone https://github.com/GeekyAnts/react-native-to-flutter.git 24 | ``` 25 | 26 | Install Dependencies 27 | ``` 28 | yarn install 29 | ``` 30 | 31 | Run the below command in root folder of the project 32 | 33 | ``` 34 | yarn start 35 | ``` 36 | 37 | Now to run the example, open new terminal and change your pwd to example folder 38 | 39 | ``` 40 | cd example 41 | ``` 42 | and then run 43 | 44 | ``` 45 | yarn start 46 | ``` 47 | Now head to `http://localhost:1234/`, app should be working fine. 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ### Sending a Pull Request 56 | 57 | For non-trivial changes, please open an issue with a proposal for a new feature or refactoring before starting on the work. We don't want you to waste your efforts on a pull request that we won't want to accept. 58 | 59 | In general, the contribution workflow looks like this: 60 | 61 | - Open a new issue in the [Issue tracker](https://github.com/GeekyAnts/react-native-to-flutter/issues). 62 | - Fork the repo. 63 | - Create a new feature branch based off the `main` branch. 64 | - Make sure all tests pass and there are no linting errors. 65 | - Submit a pull request, referencing any issues it addresses. 66 | 67 | Please try to keep your pull request focused in scope and avoid including unrelated commits. 68 | 69 | After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements. 70 | 71 | Thank you for contributing! 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sanket Sahu 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native to Flutter Widgets 2 | 3 | ![alt text](https://github.com/GeekyAnts/react-native-to-flutter/blob/main/banner/Cover.png?raw=true) 4 | 5 | The goal of `React Native to Flutter Widgets` is to convert any React Native Component to Flutter Widget. This could really help the newbies of flutter who has web knowledge to understand the CSS to flutter equivalent code snippet. 6 | 7 | 8 | This tool will take the React Native styling props on the left hand side editor and convert that to the flutter widget on the right hand side. 9 | 10 | 11 | ### List of Working React Native Props 12 | 13 | The entire checklist of which props are being already supported is [here](https://github.com/GeekyAnts/nativebase-theme-to-flutter/blob/main/README_API_CHECKLIST.md) 14 | 15 | ### Working Example 16 | 17 | 18 | 19 | 20 | ### Folder Structure 21 | 22 | ``` 23 | . 24 | ├── LICENSE 25 | ├── README.md 26 | ├── README_API_CHECKLIST.md 27 | ├── package-lock.json 28 | ├── package.json 29 | ├── src 30 | │   ├── addProperty.tsx 31 | │   ├── buildDartASTfromAST.tsx 32 | │   ├── clearProperties.tsx 33 | │   ├── config 34 | │   │   ├── flutter-widgets.ts 35 | │   │   ├── index.ts 36 | │   │   ├── layout-props.ts 37 | │   │   └── text-props.ts 38 | │   ├── index.tsx 39 | │   └── utils 40 | │   ├── arr.js 41 | │   ├── camel.ts 42 | │   ├── converter.tsx 43 | │   ├── getAlignmentAxis.tsx 44 | │   ├── getBorder.tsx 45 | │   ├── getBorderRadius.tsx 46 | │   ├── getExpanded.tsx 47 | │   ├── getFlex.tsx 48 | │   ├── getFlexDirection.tsx 49 | │   ├── getFontFamily.tsx 50 | │   ├── getFontStyle.tsx 51 | │   ├── getFontWeight.tsx 52 | │   ├── getMargin.tsx 53 | │   ├── getPadding.tsx 54 | │   ├── getPositioned.tsx 55 | │   ├── getTextAlign.tsx 56 | │   ├── num.ts 57 | │   ├── pos.js 58 | │   ├── pushPropToWidget.tsx 59 | │   ├── str.js 60 | │   └── unit.ts 61 | ├── test 62 | │   └── blah.test.tsx 63 | ├── tsconfig.json 64 | └── yarn.lock 65 | 66 | 67 | ``` 68 | 69 | ### Run this project 70 | 71 | Clone the repo, run 72 | 73 | ``` 74 | git clone https://github.com/GeekyAnts/react-native-to-flutter.git 75 | 76 | ``` 77 | 78 | ### Dependencies 79 | 80 | ``` 81 | @babel/parser 82 | @babel/preset-react 83 | 84 | ``` 85 | 86 | Install Dependencies 87 | ``` 88 | yarn install 89 | ``` 90 | 91 | Run the below command in root folder of the project 92 | 93 | ``` 94 | yarn start 95 | ``` 96 | Now to run the example, open new terminal and change your pwd to example folder 97 | 98 | ``` 99 | cd example 100 | ``` 101 | and then run 102 | ``` 103 | yarn start 104 | ```` 105 | Now head to ```http://localhost:1234/``` app should be working fine. 106 | 107 | ### Know Issues 108 | ❌ Deep Nesting of Tags might not work as expected. 109 | ### How to Contribute 110 | 111 | Thank you for your interest in contributing to React Native to Flutter Widgets ! We are lucky to have you 🙂 Head over to [Contribution](https://github.com/GeekyAnts/react-native-to-flutter/blob/main/CONTRIBUTION.md) Guidelines and learn how you can be a part of a wonderful, growing community. 112 | 113 | ### Contributors 114 | 115 | 116 | 117 | 118 | 119 | ### License 120 | 121 | Licensed under the [MIT](https://github.com/GeekyAnts/react-native-to-flutter/blob/main/LICENSE) License, Copyright © 2023 GeekyAnts. See LICENSE for more information. 122 | 123 | 124 | Made with ❤️ by 125 | -------------------------------------------------------------------------------- /README_API_CHECKLIST.md: -------------------------------------------------------------------------------- 1 | # ReactNative to Flutter Widgets Checklist 2 | 3 | This is the list of React Native Styling props, as per the official [React Native reference](https://reactnative.dev/docs/layout-props). This checklist tracks and work as a road map. Checked Items are already ported and unchecked are yet to be ported to Flutter widgets. 4 | 5 | 6 | 7 | ##### Prop List (*click to expand*) 8 |
9 | Layout Props 10 | 11 | - [x] alignContent 12 | 13 | - [x] alignItems 14 | 15 | - [ ] alignSelf 16 | 17 | - [ ] aspectRatio 18 | 19 | - [x] borderBottomWidth 20 | 21 | - [x] borderEndWidth 22 | 23 | - [x] borderLeftWidth 24 | 25 | - [x] borderRightWidth 26 | 27 | - [x] borderStartWidth 28 | 29 | - [x] borderTopWidth 30 | 31 | - [x] borderWidth 32 | 33 | - [x] bottom 34 | 35 | - [x] direction 36 | 37 | - [ ] display 38 | 39 | - [ ] end 40 | 41 | - [ ] flex 42 | 43 | - [ ] flexBasis 44 | 45 | - [ ] flexDirection 46 | 47 | - [ ] flexGrow 48 | 49 | - [ ] flexShrink 50 | 51 | - [ ] flexWrap 52 | 53 | - [x] height 54 | 55 | - [x] justifyContent 56 | 57 | - [x] left 58 | 59 | - [x] margin 60 | 61 | - [x] marginBottom 62 | 63 | - [x] marginEnd 64 | 65 | - [x] marginHorizontal 66 | 67 | - [x] marginLeft 68 | 69 | - [x] marginRight 70 | 71 | - [x] marginStart 72 | 73 | - [x] marginTop 74 | 75 | - [x] marginVertical 76 | 77 | - [x] maxHeight 78 | 79 | - [x] maxWidth 80 | 81 | - [x] minHeight 82 | 83 | - [x] minWidth 84 | 85 | - [ ] overflow 86 | 87 | - [x] padding 88 | 89 | - [x] paddingBottom 90 | 91 | - [x] paddingEnd 92 | 93 | - [x] paddingHorizontal 94 | 95 | - [x] paddingLeft 96 | 97 | - [x] paddingRight 98 | 99 | - [x] paddingStart 100 | 101 | - [x] paddingTop 102 | 103 | - [x] paddingVertical 104 | 105 | - [x] position 106 | 107 | - [x] right 108 | 109 | - [ ] start 110 | 111 | - [x] top 112 | 113 | - [x] width 114 | 115 | - [ ] zIndex 116 | 117 |
118 | 119 |
120 | Text Props 121 | 122 | - [x] fontFamily 123 | 124 | - [x] fontSize 125 | 126 | - [x] fontStyle 127 | 128 | - [x] fontWeight 129 | 130 | - [ ] includeFontPaddingAndroid 131 | 132 | - [x] fontVariant 133 | 134 | - [x] letterSpacing 135 | 136 | - [x] lineHeight 137 | 138 | - [x] textAlign 139 | 140 | - [ ] textAlignVerticalAndroid 141 | 142 | - [ ] textDecorationColoriOS 143 | 144 | - [ ] textDecorationLine 145 | 146 | - [ ] textDecorationStyleiOS 147 | 148 | - [ ] textShadowColor 149 | 150 | - [ ] textShadowOffset 151 | 152 | - [ ] textShadowRadius 153 | 154 | - [ ] textTransform 155 | 156 | - [ ] writingDirection 157 | 158 |
159 | 160 |
161 | View Style Props 162 | 163 | - [ ] backfaceVisibility 164 | 165 | - [x] backgroundColor 166 | 167 | - [x] borderBottomColor 168 | 169 | - [x] borderBottomEndRadius 170 | 171 | - [x] borderBottomLeftRadius 172 | 173 | - [x] borderBottomRightRadius 174 | 175 | - [x] borderBottomStartRadius 176 | 177 | - [x] borderBottomWidth 178 | 179 | - [x] borderColor 180 | 181 | - [x] borderEndColor 182 | 183 | - [x] borderLeftColor 184 | 185 | - [x] borderLeftWidth 186 | 187 | - [x] borderRadius 188 | 189 | - [x] borderRightColor 190 | 191 | - [x] borderRightWidth 192 | 193 | - [x] borderStartColor 194 | 195 | - [x] borderStyle 196 | 197 | - [x] borderTopColor 198 | 199 | - [x] borderTopEndRadius 200 | 201 | - [x] borderTopLeftRadius 202 | 203 | - [x] borderTopRightRadius 204 | 205 | - [x] borderTopStartRadius 206 | 207 | - [x] borderTopWidth 208 | 209 | - [x] borderWidth 210 | 211 | - [ ] elevationAndroid 212 | 213 | - [ ] opacity 214 |
215 | 216 |
217 | 218 | Image Styles Props 219 | 220 | - [ ] backfaceVisibility 221 | 222 | - [ ] backgroundColor 223 | 224 | - [ ] borderBottomLeftRadius 225 | 226 | - [ ] borderBottomRightRadius 227 | 228 | - [ ] borderColor 229 | 230 | - [ ] borderRadius 231 | 232 | - [ ] borderTopLeftRadius 233 | 234 | - [ ] borderTopRightRadius 235 | 236 | - [ ] borderWidth 237 | 238 | - [ ] opacity 239 | 240 | - [ ] overflow 241 | 242 | - [ ] overlayColorAndroid 243 | 244 | - [ ] resizeMode 245 | 246 | - [ ] tintColor 247 | 248 |
249 | -------------------------------------------------------------------------------- /banner/Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeekyAnts/react-native-to-flutter/52379b7b7b0449c1ad21bea5fdcef5ee323d9d1a/banner/Cover.png -------------------------------------------------------------------------------- /banner/example-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeekyAnts/react-native-to-flutter/52379b7b7b0449c1ad21bea5fdcef5ee323d9d1a/banner/example-1.gif -------------------------------------------------------------------------------- /banner/high-res-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeekyAnts/react-native-to-flutter/52379b7b7b0449c1ad21bea5fdcef5ee323d9d1a/banner/high-res-example.gif -------------------------------------------------------------------------------- /example/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache 3 | dist -------------------------------------------------------------------------------- /example/img/Vector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeekyAnts/react-native-to-flutter/52379b7b7b0449c1ad21bea5fdcef5ee323d9d1a/example/img/Vector.png -------------------------------------------------------------------------------- /example/img/flutter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeekyAnts/react-native-to-flutter/52379b7b7b0449c1ad21bea5fdcef5ee323d9d1a/example/img/flutter.png -------------------------------------------------------------------------------- /example/index.css: -------------------------------------------------------------------------------- 1 | .ribbon { 2 | background-color: #a00; 3 | overflow: hidden; 4 | white-space: nowrap; 5 | position: absolute; 6 | right: -40px; 7 | top: 25px; 8 | -webkit-transform: rotate(45deg); 9 | -moz-transform: rotate(45deg); 10 | -ms-transform: rotate(45deg); 11 | -o-transform: rotate(45deg); 12 | transform: rotate(45deg); 13 | -webkit-box-shadow: 0 0 10px #888; 14 | -moz-box-shadow: 0 0 10px #888; 15 | box-shadow: 0 0 10px #888; 16 | } 17 | 18 | .switch-wrapper{ 19 | display: none; 20 | } 21 | 22 | .ribbon a { 23 | border: 1px solid #faa; 24 | color: #fff; 25 | display: block; 26 | font: bold 81.25% 'Helvetica Neue', Helvetica, Arial, sans-serif; 27 | margin: 1px 0; 28 | padding: 10px 30px; 29 | text-align: center; 30 | text-decoration: none; 31 | text-shadow: 0 0 5px #444; 32 | } 33 | 34 | .eclipse1 { 35 | position: absolute; 36 | width: 362px; 37 | height: 362px; 38 | top: -49px; 39 | background: #54C5F8; 40 | filter: blur(150px); 41 | left: -188px; 42 | z-index: 1; 43 | } 44 | 45 | .eclipse2 { 46 | position: absolute; 47 | width: 571px; 48 | height: 439px; 49 | bottom: -165px; 50 | right: -227px; 51 | 52 | 53 | background: #54C5F8; 54 | filter: blur(150px); 55 | } 56 | .switch-code{ 57 | display: flex; 58 | border: 1px solid #cfcfcf; 59 | font-size: 12px; 60 | border-radius: 60px; 61 | } 62 | 63 | 64 | 65 | .playground-navbar { 66 | display: flex; 67 | align-items: center; 68 | background-color: #000; 69 | padding:10px 0px; 70 | position: relative; 71 | z-index: 2; 72 | } 73 | 74 | .menu-wrapper { 75 | flex: 1; 76 | justify-content: end; 77 | display: flex; 78 | align-items: center; 79 | margin-right: 30px; 80 | } 81 | 82 | .playground-footer { 83 | display: flex; 84 | background-color: #000; 85 | z-index: 100; 86 | position: absolute; 87 | margin: 0; 88 | padding: 10px; 89 | left: 0; 90 | width: 100%; 91 | bottom: 0; 92 | } 93 | 94 | .playground-footer p { 95 | color: #B6B6B6; 96 | margin: auto; 97 | } 98 | 99 | .playground-footer>p>span { 100 | color: #CF2F2F 101 | } 102 | 103 | .logoName{ 104 | margin: 0; 105 | } 106 | 107 | .editor-container { 108 | height: calc(100vh - 295px); 109 | border: 1px solid #cfcfcf47; 110 | } 111 | 112 | .playground-heading { 113 | color: #FFFFFF; 114 | text-align: center; 115 | margin: auto; 116 | margin-top: 20px; 117 | margin-bottom: 20px; 118 | font-size: 24px; 119 | } 120 | 121 | .playground-subheading { 122 | margin: auto; 123 | text-align: center; 124 | max-width: 570px; 125 | color: #858181; 126 | margin-bottom: 20px 127 | } 128 | 129 | 130 | /* Extra small devices (phones, 600px and down) */ 131 | @media only screen and (max-width: 600px) { 132 | 133 | 134 | /* .menu-wrapper , a:nth-last-child(0) { 135 | display: none; 136 | } */ 137 | .issue { 138 | display: none; 139 | } 140 | .props { 141 | display: none; 142 | } 143 | 144 | .github{ 145 | display: block; 146 | } 147 | 148 | .eclipse2 { 149 | display: none; 150 | } 151 | 152 | .playground-heading { 153 | font-size: 14px; 154 | } 155 | .playground-subheading { 156 | display: none; 157 | } 158 | .switch-wrapper{ 159 | display: flex; 160 | align-items: center; 161 | justify-content: center; 162 | margin-bottom: 30px; 163 | 164 | } 165 | .active-code{ 166 | color: #000000; 167 | background-color: #fff; 168 | border-radius: 60px; 169 | } 170 | 171 | } 172 | 173 | /* Small devices (portrait tablets and large phones, 600px and up) */ 174 | @media only screen and (min-width: 600px) {} 175 | 176 | /* Medium devices (landscape tablets, 768px and up) */ 177 | @media only screen and (min-width: 768px) {} 178 | 179 | /* Large devices (laptops/desktops, 992px and up) */ 180 | @media only screen and (min-width: 992px) {} 181 | 182 | /* Extra large devices (large laptops and desktops, 1200px and up) */ 183 | @media only screen and (min-width: 1200px) {} -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Playground 10 | 12 | 13 | 14 | 16 | 18 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /example/index.tsx: -------------------------------------------------------------------------------- 1 | import { convertNativeBaseThemeToFlutterWidgets } from '../.'; 2 | 3 | import 'react-app-polyfill/ie11'; 4 | import * as ReactDOM from 'react-dom'; 5 | import * as React from 'react'; 6 | import { useState } from 'react'; 7 | import Editor from "@monaco-editor/react"; 8 | // @ts-ignore 9 | import flutter from '../example/img/flutter.png' 10 | 11 | //let styles: any = { 12 | 13 | // position:"absolute", 14 | // flexGrow:4, 15 | // minHeight:4, 16 | // width:3, 17 | // height:4, 18 | // borderRadius:4, 19 | // borderWidth:3, 20 | // borderColor:"#fcfcfc", 21 | // paddingHorizontal:30, 22 | // paddingRight:40, 23 | // paddingBottom:50, 24 | // paddingTop:40, 25 | // maxWidth:30, 26 | // minWidth:50, 27 | // maxHeight:50, 28 | // margin:30, 29 | // borderBottomWidth:1, 30 | // borderTopWidth:3, 31 | // borderLeftWidth:4, 32 | // borderRightWidth:5, 33 | // flexDirection:"column", 34 | // alignContent:"space-between", 35 | // alignItems:"stretch", 36 | // // position:"absolute", 37 | // top:10, 38 | // right:20, 39 | // bottom:30, 40 | // left:40, 41 | 42 | // color: "#ffffff", 43 | // fontSize: 23, 44 | // letterSpacing: 4, 45 | // lineHeight: 4, 46 | // fontStyle: "italic", 47 | // fontWeight: 300, 48 | // textAlign: "center", 49 | // fontFamily: "abc" 50 | 51 | //} 52 | let styles = (` 53 | 76 | This Widget is Made from React Native to Flutter Tool 86 | 87 | `) 88 | 89 | 90 | const theme = { 91 | base: 'vs', 92 | inherit: true, 93 | rules: [ 94 | { token: 'custom-info', foreground: 'a3a7a9', background: 'ffffff' }, 95 | { token: 'custom-error', foreground: 'ee4444' }, 96 | { token: 'custom-notice', foreground: '1055af' }, 97 | { token: 'custom-date', foreground: '20aa20' }, 98 | ], 99 | colors: { 100 | 'editor.foreground': '#FFFFFF', 101 | 'editor.background': '#CFCFCF', 102 | } 103 | } 104 | 105 | 106 | 107 | 108 | 109 | function App() { 110 | const [code, setCode] = useState(styles); 111 | const [output, setOutput]: any = useState(''); 112 | const [error, setError]: any = useState(false) 113 | const [isActiveReact,setIsActiveReact]:any = useState(true) 114 | const [isMobile,setIsMobile]:any = useState(false) 115 | const transpileCode = (code: string) => { 116 | setOutput(convertNativeBaseThemeToFlutterWidgets(code)); 117 | }; 118 | 119 | const editorRef: any = React.useRef(null); 120 | var myMonaco: any; 121 | 122 | // function handleEditorWillMount(monaco) { 123 | // // here is the monaco instance 124 | // // do something before editor is mounted 125 | // myMonaco = monaco; 126 | // monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true); 127 | // monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ 128 | // target: monaco.languages.typescript.ScriptTarget.ES2016, 129 | // allowNonTsExtensions: true, 130 | // moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs, 131 | // module: monaco.languages.typescript.ModuleKind.CommonJS, 132 | // noEmit: true, 133 | // typeRoots: ["node_modules/@types"] 134 | // }); 135 | // monaco.editor.defineTheme('myTheme', theme) 136 | // debugger 137 | 138 | // monaco.editor.EditorOptions.automaticLayout; 139 | // monaco.languages.typescript.typescriptDefaults.addExtraLib( 140 | // `export declare function next() : string`, 141 | // 'node_modules/@types/external/index.d.ts'); 142 | // monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ 143 | // noSemanticValidation: false, 144 | // noSyntaxValidation: false 145 | // }) 146 | 147 | 148 | 149 | // } 150 | 151 | function handleEditorDidMount(editor, monaco) { 152 | // here is the editor instance 153 | // you can store it in `useRef` for further usage 154 | editorRef.current = monaco; 155 | } 156 | 157 | 158 | 159 | React.useEffect(() => { 160 | setOutput('') 161 | debugger 162 | console.log(window.innerHeight); 163 | if(window.innerWidth <=600){ 164 | setIsMobile(true); 165 | } else { 166 | setIsMobile(false); 167 | } 168 | 169 | }, []); 170 | React.useEffect(() => { 171 | 172 | if (code && !error) { 173 | 174 | transpileCode(code) 175 | } 176 | }, [code]); 177 | 178 | return ( 179 | 180 |
181 |
182 |
183 |
184 |

Built with @GeekyAnts

185 |
186 |
187 | 188 |

RN2Flutter

189 |
190 | Report an issue 191 | Supported Props 192 | GitHub 193 |
194 | 195 |
196 | 197 |
198 | 199 |
209 | 210 |

React Native Component to Flutter Widgets (Alpha)

211 |

Helpful for developers who are familiar with React Native but new to Flutter, as it allows them to leverage their knowledge of React Native styling and apply it to Flutter.

212 |
213 |
214 |
{setIsActiveReact(!isActiveReact);console.log("hello")}} className={`${isActiveReact ? 'active-code':''}`} style={{flex:"1 1 0px" ,padding :"5px",whiteSpace:"nowrap",flexBasis:"100%",width:"100.00px",textAlign:"center",color:`${isActiveReact ?'#000':"#fff"}`}}>React Native
215 |
{setIsActiveReact(!isActiveReact);console.log("hello")}} className={`${!isActiveReact ? 'active-code':''}`} style={{flex:"1 1 0px",padding:"5px",flexBasis:"100%",width:"100.00px",textAlign:"center",color:`${!isActiveReact ?'#000':"#fff"}`}}>Flutter
216 | 217 |
218 |
219 | 220 |
221 | 222 | {isMobile ? isActiveReact? reactEditor():
:reactEditor()} 223 |
224 | {isMobile ? !isActiveReact ? flutterEditor():
:flutterEditor()} 225 | 226 | 227 |
228 | 229 |
230 |
231 |
232 | ); 233 | 234 | function flutterEditor(): string | number | boolean | {} | React.ReactElement> | React.ReactNodeArray | React.ReactPortal | null | undefined { 235 | return
236 | 237 |

Flutter Widget

238 |
239 | 248 | 249 |
250 |
; 251 | } 252 | 253 | function reactEditor(): string | number | boolean | {} | React.ReactElement> | React.ReactNodeArray | React.ReactPortal | null | undefined { 254 | return
255 | 256 | 257 |

React Native Component

258 |
259 | { 270 | 271 | if (e.length > 1) { 272 | 273 | setError(true); 274 | } else { 275 | setError(false); 276 | } 277 | } } 278 | onChange={(e: string) => { 279 | if (!error) { 280 | setCode(e); 281 | setOutput(''); 282 | } 283 | 284 | 285 | } } /> 286 | 287 |
288 | 289 | 290 |
; 291 | } 292 | } 293 | 294 | ReactDOM.render(, document.getElementById('root')); 295 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "main": "./build/index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "parcel index.html", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": { 11 | "@monaco-editor/react": "^4.4.6", 12 | "@uiw/codemirror-extensions-langs": "^4.13.2", 13 | "@uiw/codemirror-theme-sublime": "^4.13.2", 14 | "@uiw/react-codemirror": "^4.13.2", 15 | "prismjs": "^1.29.0", 16 | "react-app-polyfill": "^1.0.0", 17 | "react-simple-code-editor": "^0.13.1" 18 | }, 19 | "alias": { 20 | "react": "../node_modules/react", 21 | "react-dom": "../node_modules/react-dom/profiling", 22 | "scheduler/tracing": "../node_modules/scheduler/tracing-profiling" 23 | }, 24 | "devDependencies": { 25 | "@babel/core": "^7.20.5", 26 | "@babel/preset-react": "^7.18.6", 27 | "@types/react": "^16.9.11", 28 | "@types/react-dom": "^16.8.4", 29 | "babel-core": "^7.0.0-bridge.0", 30 | "babel-jest": "^29.3.1", 31 | "parcel": "1.12.3", 32 | "regenerator-runtime": "^0.13.11", 33 | "typescript": "^3.4.5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "Button": { 4 | 5 | "baseStyle": { 6 | "borderRadius": "sm", 7 | 8 | "flexDirection": "row", 9 | "justifyContent": "center", 10 | "alignItems": "center", 11 | "_web": { 12 | "_disabled": { 13 | "cursor": "not-allowed" 14 | }, 15 | "_loading": { 16 | "cursor": "not-allowed" 17 | }, 18 | "cursor": "pointer", 19 | "userSelect": "none" 20 | }, 21 | "_focusVisible": { 22 | "_web": { 23 | "outlineWidth": "0", 24 | "style": { 25 | "boxShadow": "#22d3ee 0px 0px 0px 2px" 26 | } 27 | } 28 | }, 29 | "_dark": { 30 | "_focusVisible": { 31 | "_web": { 32 | "outlineWidth": "0", 33 | "style": { 34 | "boxShadow": "#06b6d4 0px 0px 0px 2px" 35 | } 36 | } 37 | } 38 | }, 39 | "_stack": { 40 | "space": "1.5", 41 | "alignItems": "center" 42 | }, 43 | "_loading": { 44 | "opacity": "40" 45 | }, 46 | "_disabled": { 47 | "opacity": "40" 48 | }, 49 | "_spinner": { 50 | "size": "sm", 51 | "focusable": false 52 | } 53 | }, 54 | "variants": { 55 | "ghost": { 56 | "_text": { 57 | "color": "primary.600" 58 | }, 59 | "_icon": { 60 | "color": "primary.600" 61 | }, 62 | "_spinner": { 63 | "color": "primary.600" 64 | }, 65 | "_hover": { 66 | "bg": "primary.600:alpha.10" 67 | }, 68 | "_pressed": { 69 | "bg": "primary.600:alpha.20" 70 | }, 71 | "_dark": { 72 | "_text": { 73 | "color": "primary.500" 74 | }, 75 | "_icon": { 76 | "color": "primary.500" 77 | }, 78 | "_spinner": { 79 | "color": "primary.500" 80 | }, 81 | "_hover": { 82 | "bg": "primary.500:alpha.10" 83 | }, 84 | "_pressed": { 85 | "bg": "primary.500:alpha.20" 86 | } 87 | } 88 | }, 89 | "outline": { 90 | "borderWidth": "1px", 91 | "borderColor": "muted.300", 92 | "_text": { 93 | "color": "primary.600" 94 | }, 95 | "_icon": { 96 | "color": "primary.600" 97 | }, 98 | "_spinner": { 99 | "color": "primary.600" 100 | }, 101 | "_hover": { 102 | "bg": "primary.600:alpha.10" 103 | }, 104 | "_pressed": { 105 | "bg": "primary.600:alpha.20" 106 | }, 107 | "_dark": { 108 | "borderColor": "muted.700", 109 | "_text": { 110 | "color": "primary.500" 111 | }, 112 | "_icon": { 113 | "color": "primary.500" 114 | }, 115 | "_spinner": { 116 | "color": "primary.500" 117 | }, 118 | "_hover": { 119 | "bg": "primary.500:alpha.10" 120 | }, 121 | "_pressed": { 122 | "bg": "primary.500:alpha.20" 123 | } 124 | } 125 | }, 126 | "solid": { 127 | "_text": { 128 | "color": "text.50" 129 | }, 130 | "_icon": { 131 | "color": "text.50" 132 | }, 133 | "_spinner": { 134 | "color": "text.50" 135 | }, 136 | "bg": "primary.600", 137 | "_hover": { 138 | "bg": "primary.700" 139 | }, 140 | "_pressed": { 141 | "bg": "primary.800" 142 | }, 143 | "_dark": { 144 | "bg": "primary.600", 145 | "_hover": { 146 | "bg": "primary.700" 147 | }, 148 | "_pressed": { 149 | "bg": "primary.800" 150 | } 151 | } 152 | }, 153 | "subtle": { 154 | "bg": "primary.100", 155 | "_text": { 156 | "color": "primary.900" 157 | }, 158 | "_icon": { 159 | "color": "primary.900" 160 | }, 161 | "_spinner": { 162 | "color": "primary.900" 163 | }, 164 | "_hover": { 165 | "bg": "primary.200" 166 | }, 167 | "_pressed": { 168 | "bg": "primary.300" 169 | }, 170 | "_dark": { 171 | "bg": "primary.300", 172 | "_hover": { 173 | "bg": "primary.200" 174 | }, 175 | "_pressed": { 176 | "bg": "primary.100" 177 | } 178 | } 179 | }, 180 | "link": { 181 | "_icon": { 182 | "color": "primary.600" 183 | }, 184 | "_spinner": { 185 | "color": "primary.600" 186 | }, 187 | "_hover": { 188 | "_text": { 189 | "textDecorationLine": "underline" 190 | } 191 | }, 192 | "_pressed": { 193 | "_text": { 194 | "color": "primary.800", 195 | "textDecorationLine": "underline" 196 | } 197 | }, 198 | "_text": { 199 | "color": "primary.600" 200 | }, 201 | "_dark": { 202 | "_text": { 203 | "color": "primary.500" 204 | }, 205 | "_pressed": { 206 | "_text": { 207 | "color": "primary.300" 208 | } 209 | } 210 | } 211 | } 212 | }, 213 | "sizes": { 214 | "lg": { 215 | "px": "3", 216 | "py": "3", 217 | "_text": { 218 | "fontSize": "md" 219 | }, 220 | "_icon": { 221 | "size": "md" 222 | } 223 | }, 224 | "md": { 225 | "px": "3", 226 | "py": "2.5", 227 | "_text": { 228 | "fontSize": "sm" 229 | }, 230 | "_icon": { 231 | "size": "sm" 232 | } 233 | }, 234 | "sm": { 235 | "px": "3", 236 | "py": "2", 237 | "_text": { 238 | "fontSize": "xs" 239 | }, 240 | "_icon": { 241 | "size": "sm" 242 | } 243 | }, 244 | "xs": { 245 | "px": "3", 246 | "py": "2", 247 | "_text": { 248 | "fontSize": "2xs" 249 | }, 250 | "_icon": { 251 | "size": "xs" 252 | } 253 | } 254 | }, 255 | "defaultProps": { 256 | "variant": "solid", 257 | "size": "md", 258 | "colorScheme": "primary" 259 | } 260 | } 261 | } 262 | } 263 | 264 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": false, 4 | "target": "es5", 5 | "module": "commonjs", 6 | "jsx": "react", 7 | "moduleResolution": "node", 8 | "noImplicitAny": false, 9 | "noUnusedLocals": false, 10 | "noUnusedParameters": false, 11 | "removeComments": true, 12 | "strictNullChecks": true, 13 | "preserveConstEnums": true, 14 | "sourceMap": true, 15 | "lib": ["es2015", "es2016", "dom"], 16 | "types": ["node"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "license": "MIT", 4 | "main": "dist/index.js", 5 | "typings": "dist/index.d.ts", 6 | "files": [ 7 | "dist", 8 | "src" 9 | ], 10 | "engines": { 11 | "node": ">=10" 12 | }, 13 | "scripts": { 14 | "start": "tsdx watch", 15 | "build": "tsdx build", 16 | "test": "tsdx test --passWithNoTests", 17 | "lint": "tsdx lint", 18 | "prepare": "tsdx build", 19 | "size": "size-limit", 20 | "analyze": "size-limit --why" 21 | }, 22 | "peerDependencies": { 23 | "react": ">=16" 24 | }, 25 | "husky": { 26 | "hooks": { 27 | "pre-commit": "tsdx lint" 28 | } 29 | }, 30 | "prettier": { 31 | "printWidth": 80, 32 | "semi": true, 33 | "singleQuote": true, 34 | "trailingComma": "es5" 35 | }, 36 | "name": "nativebase-theme-to-flutter", 37 | "author": "Sanket Sahu", 38 | "module": "dist/nativebase-theme-to-flutter.esm.js", 39 | "size-limit": [ 40 | { 41 | "path": "dist/nativebase-theme-to-flutter.cjs.production.min.js", 42 | "limit": "10 KB" 43 | }, 44 | { 45 | "path": "dist/nativebase-theme-to-flutter.esm.js", 46 | "limit": "10 KB" 47 | } 48 | ], 49 | "devDependencies": { 50 | "@babel/core": "^7.20.5", 51 | "@babel/parser": "^7.20.5", 52 | "@babel/plugin-proposal-class-properties": "^7.18.6", 53 | "@babel/plugin-syntax-jsx": "^7.18.6", 54 | "@babel/plugin-transform-runtime": "^7.19.6", 55 | "@babel/preset-env": "^7.20.2", 56 | "@babel/preset-flow": "^7.18.6", 57 | "@babel/preset-react": "^7.18.6", 58 | "@babel/preset-typescript": "^7.18.6", 59 | "@size-limit/preset-small-lib": "^8.1.0", 60 | "@types/react": "^18.0.25", 61 | "@types/react-dom": "^18.0.8", 62 | "babel-core": "^7.0.0-bridge.0", 63 | "babel-jest": "^29.3.1", 64 | "babel-preset-react": "^6.24.1", 65 | "husky": "^8.0.2", 66 | "ppo": "^1.3.5", 67 | "react": "^18.2.0", 68 | "react-dom": "^18.2.0", 69 | "regenerator-runtime": "^0.13.11", 70 | "size-limit": "^8.1.0", 71 | "tsdx": "^0.14.1", 72 | "tslib": "^2.4.1", 73 | "typescript": "^4.8.4" 74 | }, 75 | "dependencies": { 76 | "@babel/traverse": "^7.20.5", 77 | "@types/color": "^3.0.3", 78 | "@types/lodash": "^4.14.188", 79 | "color": "^4.2.3", 80 | "lodash-es": "^4.17.21" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/addProperty.tsx: -------------------------------------------------------------------------------- 1 | import { styleSystem } from "./config"; 2 | 3 | export function addProperty(myObject: any, val: any, prop: any, style: any, ast: any) { 4 | let newProp: any; 5 | if (styleSystem.hasOwnProperty(prop)) { 6 | if (myObject.type === "constructor" || myObject.type === "enum") { 7 | 8 | newProp = { ...styleSystem[prop].class, namedProp: styleSystem[prop].property }; 9 | if (typeof newProp.value === "object") { 10 | newProp.value = { ...newProp.value, value: val }; 11 | } else { 12 | if(newProp.hasOwnProperty("value")){ 13 | newProp.value = val; 14 | } 15 | 16 | } 17 | 18 | 19 | if (styleSystem[prop].transformer) { 20 | 21 | // newProp.properties = [] 22 | newProp = styleSystem[prop].transformer(style, newProp, ast); 23 | 24 | if (newProp.nested) { 25 | return newProp; 26 | } 27 | } 28 | 29 | 30 | 31 | 32 | } else { 33 | 34 | newProp = { ...myObject, value: val, namedProp: styleSystem[prop].property }; 35 | } 36 | } 37 | 38 | if (newProp.class !== myObject.class) { 39 | if (styleSystem[prop].hasOwnProperty("partOf")) { 40 | 41 | let index = myObject["properties"].findIndex((data: any) => { 42 | return data.namedProp === newProp.namedProp; 43 | 44 | }); 45 | 46 | if (index < 0) { 47 | myObject = { ...myObject, properties: myObject.properties }; 48 | myObject.properties.push(newProp); 49 | } 50 | } else { 51 | myObject = newProp; 52 | } 53 | 54 | } else { 55 | myObject = newProp; 56 | } 57 | 58 | 59 | return myObject; 60 | } 61 | -------------------------------------------------------------------------------- /src/buildDartASTfromAST.tsx: -------------------------------------------------------------------------------- 1 | import { buildDartAST } from "./index"; 2 | 3 | export function buildDartASTfromAST(expression: any, myDartAST: any, recursive: boolean = false) { 4 | 5 | 6 | 7 | if (!recursive) { 8 | if (expression.children.length < 2) { 9 | if (myDartAST?.class) { 10 | let index = myDartAST.properties.findIndex((data: any) => (data.namedProp === "child")); 11 | if (myDartAST.properties[index]?.class === "Row" || myDartAST.properties[index]?.class === "Column") { 12 | let i = myDartAST.properties[index].properties.findIndex((data: any) => (data.namedProp === "children")); 13 | 14 | if (i > -1) { 15 | myDartAST.properties[index].properties[i].values = []; 16 | } 17 | } 18 | } 19 | } 20 | 21 | let index = myDartAST?.properties?.findIndex((data: any) => (data.namedProp === "child")); 22 | if (index) { 23 | if (myDartAST?.properties[index]?.class === "Row" || myDartAST?.properties[index]?.class === "Column") { 24 | let i = myDartAST.properties[index].properties.findIndex((data: any) => (data.namedProp === "children")); 25 | if (i > -1) { 26 | myDartAST.properties[index].properties[i].values = []; 27 | } 28 | } 29 | } 30 | } 31 | 32 | 33 | 34 | Object.entries(expression.children).forEach(([k, v]: any) => { 35 | 36 | let a: any = {}; 37 | 38 | if (v.type === "JSXElement") { 39 | 40 | 41 | 42 | let style = {}; 43 | 44 | let name = v.openingElement.name.name; 45 | 46 | let attributes = v.openingElement.attributes[0]; 47 | 48 | 49 | 50 | let properties = attributes?.value?.expression?.properties; 51 | if (properties) { 52 | Object.entries(properties).forEach(([, v]: any) => { 53 | 54 | style = { ...style, [v.key.name]: v.value.value }; 55 | }); 56 | 57 | } 58 | 59 | if (myDartAST?.class) { 60 | let layout: any = { 61 | type: "constructor", 62 | properties: [] 63 | } 64 | 65 | 66 | a = buildDartAST(name, style); 67 | 68 | if (name === "View") { 69 | let index = a.properties.findIndex((data: any) => (data.class === "Row" || data.class === "Column")); 70 | if (index > -1) { 71 | 72 | // layout = { ...layout, "class": a.properties[index].class } 73 | // a.properties.splice(index, 1); 74 | } else { 75 | layout = { ...layout, "class": "Row" } 76 | } 77 | 78 | 79 | 80 | 81 | 82 | let childIndex = a.properties.findIndex((data: any) => (data.namedProp === "child")); 83 | if (childIndex > -1) { 84 | a.properties[childIndex].properties.push({ ...layout, "namedProp": "child" }) 85 | } else { 86 | a.properties.push({ ...layout, "namedProp": "child" }) 87 | } 88 | 89 | } 90 | if (name === 'Text') { 91 | 92 | a = { ...a, id: k, value: v.children[0]?.value ?? '' }; 93 | } else { 94 | a = { ...a, id: k }; 95 | } 96 | 97 | 98 | 99 | let index = myDartAST?.properties?.findIndex((data: any) => (data.namedProp === "child")); 100 | if (myDartAST.properties[index]?.class === "Row" || myDartAST.properties[index]?.class === "Column") { 101 | 102 | let i = myDartAST?.properties[index]?.properties.findIndex((data: any) => (data?.namedProp === "children")); 103 | 104 | if (i > -1) { 105 | let ii = myDartAST?.properties[index]?.properties[i]?.values?.findIndex((data: any) => (data.id === a.id)); 106 | if (ii > -1) { 107 | myDartAST?.properties[index].properties[i].values.splice(ii, 1); 108 | } 109 | myDartAST?.properties[index].properties[i].values.push(a); 110 | 111 | } else { 112 | myDartAST?.properties[index].properties.push({ namedProp: "children", type: "Array", values: [a] }); 113 | } 114 | 115 | } else { 116 | 117 | searchForDeepChildAndPush(myDartAST, a); 118 | 119 | // myDartAST?.properties.push({ "namedProp": "child", ...a }); 120 | } 121 | 122 | } 123 | 124 | console.log(style); 125 | console.log(myDartAST); 126 | 127 | 128 | } 129 | 130 | if (v.children) { 131 | if (v.children.length > 0) { 132 | console.log(v); 133 | buildDartASTfromAST(v, a); 134 | } 135 | } 136 | 137 | }); 138 | 139 | 140 | 141 | } 142 | 143 | export function searchForDeepChildAndPush(myDartAST: any, a: any) { 144 | 145 | let prop = myDartAST?.properties ?? myDartAST?.values; 146 | 147 | let namedPropIndex = prop.findIndex((data: any) => (data.namedProp === "child" || data.namedProp === "children")); 148 | console.log(namedPropIndex); 149 | if(namedPropIndex < 0){ 150 | 151 | if(myDartAST.hasOwnProperty("namedProp")){ 152 | Object.entries(prop).forEach(([, v]: any) => { 153 | 154 | 155 | if (v.namedProp === "child") { 156 | if (v.properties.length > 0) { 157 | searchForDeepChildAndPush(v, a); 158 | } else { 159 | pushChildToParent(v, a); 160 | } 161 | } if (v.namedProp === "children") { 162 | 163 | if(a.hasOwnProperty("namedProp")){ 164 | if (v.values.length > 0) { 165 | searchForDeepChildAndPush(v, a); 166 | } else { 167 | pushChildToParent(v, a); 168 | } 169 | } else { 170 | v.values.push(a) 171 | } 172 | 173 | 174 | } else { 175 | pushChildToParent(v, a); 176 | } 177 | }); 178 | 179 | } else { 180 | pushChildToParent(myDartAST, a); 181 | } 182 | } else { 183 | searchForContainer(myDartAST,a); 184 | } 185 | 186 | 187 | } 188 | 189 | export function pushChildToParent(v: any, a: any) { 190 | if (v.type == "constructor") { 191 | 192 | if (v.class === 'Row' || v.class === 'Column') { 193 | v.properties.push({ namedProp: "children", type: "Array", values: [a] }); 194 | } else { 195 | v.properties.push({ "namedProp": "child", ...a }); 196 | } 197 | 198 | } 199 | } 200 | 201 | 202 | function searchForContainer(_ast: any,widget:any) { 203 | let prop = _ast?.properties ?? _ast?.values; 204 | 205 | if (prop) { 206 | Object.entries(prop).forEach(([, v]: any) => { 207 | 208 | if (v.class === "Container") { 209 | if(v.hasOwnProperty("properties")){ 210 | if(v.properties.length>0){ 211 | let childIndex = v.properties.findIndex((data:any)=>data.namedProp==="child"||data.namedProp==="children"); 212 | if(childIndex>-1){ 213 | let index = v.properties[childIndex].properties.findIndex((data:any)=>data.namedProp==="children"); 214 | if(index >-1){ 215 | if(v.properties[childIndex].properties[index].hasOwnProperty("namedProp")){ 216 | 217 | v.properties[childIndex].properties[index].values.push(widget) 218 | 219 | } 220 | } 221 | else { 222 | v.properties[childIndex].properties.push({ namedProp: "children", type: "Array", values: [widget] }); 223 | } 224 | 225 | } 226 | } else { 227 | v.properties.push(widget) 228 | } 229 | 230 | 231 | } 232 | 233 | } else { 234 | searchForContainer(v,widget); 235 | } 236 | }); 237 | } 238 | 239 | } 240 | 241 | -------------------------------------------------------------------------------- /src/clearProperties.tsx: -------------------------------------------------------------------------------- 1 | import { styleSystem } from "./config"; 2 | 3 | export function clearProperties(theme: any) { 4 | Object.entries(theme).map(([k,]: any) => { 5 | if (styleSystem.hasOwnProperty(k)) { 6 | if (styleSystem[k].hasOwnProperty("partOf")) { 7 | styleSystem[k].partOf.class.properties = []; 8 | } 9 | } 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /src/config/flutter-widgets.ts: -------------------------------------------------------------------------------- 1 | import { getColor, toDouble, toInt } from "../utils/converter"; 2 | 3 | 4 | 5 | export const dartType = { 6 | double: { 7 | type: "double", 8 | transformer: toDouble, 9 | value: "", 10 | }, 11 | int: { 12 | type: "int", 13 | transformer: toInt, 14 | value: "" 15 | }, 16 | string :{ 17 | type:"string", 18 | value:"" 19 | } 20 | 21 | } 22 | 23 | export const flutterWidget = { 24 | Container: { 25 | type: "constructor", 26 | class: "Container", 27 | properties: [ 28 | 29 | 30 | ], 31 | 32 | }, 33 | 34 | Text: { 35 | type: "constructor", 36 | class: "Text", 37 | properties: [], 38 | value:"" 39 | }, 40 | 41 | MainAxisAlignment :{ 42 | type:"enum", 43 | class : "MainAxisAlignment", 44 | value : "", 45 | 46 | }, 47 | 48 | 49 | 50 | 51 | Flex :{ 52 | type:"constructor", 53 | class:"Flex", 54 | properties:[] 55 | }, 56 | 57 | CrossAxisAlignment :{ 58 | type:"enum", 59 | class : "CrossAxisAlignment", 60 | value : "", 61 | 62 | }, 63 | 64 | Column :{ 65 | type: "constructor", 66 | class: "Column", 67 | properties: [] 68 | }, 69 | 70 | 71 | Stack :{ 72 | type: "constructor", 73 | class: "Stack", 74 | properties: [] 75 | }, 76 | 77 | 78 | Row :{ 79 | type: "constructor", 80 | class: "Row", 81 | properties: [] 82 | }, 83 | Positioned:{ 84 | type: "constructor", 85 | class: "Positioned", 86 | properties: [] 87 | }, 88 | 89 | BoxDecoration: { 90 | type: "constructor", 91 | class: "BoxDecoration", 92 | namedProp: "decoration", 93 | properties: [] 94 | }, 95 | 96 | Color: { 97 | type: "constructor", 98 | class: "Color", 99 | namedProp: "color", 100 | value: dartType.int, 101 | transformer: getColor 102 | 103 | }, 104 | BoxConstraints: { 105 | type: "constructor", 106 | namedProp: "constraints", 107 | class: "BoxConstraints", 108 | properties: [] 109 | }, 110 | 111 | 112 | Expanded:{ 113 | type:"constructor", 114 | class:"Expanded", 115 | 116 | properties: [] 117 | }, 118 | 119 | 120 | 121 | 122 | 123 | EdgeInsets: { 124 | type: "constructor", 125 | class: "EdgeInsets.all", 126 | properties: [], 127 | value: dartType.double, 128 | }, 129 | 130 | EdgeInsetsDirectional: { 131 | type: "constructor", 132 | class: "EdgeInsetsDirectional.all", 133 | properties: [], 134 | value: dartType.double, 135 | }, 136 | 137 | RadiusCircular: { 138 | type: "constructor", 139 | class: "Radius.circular", 140 | value: dartType.double 141 | }, 142 | 143 | 144 | BorderBottomWidth: { 145 | type: "constructor", 146 | class: "BorderSide", 147 | properties: [ 148 | 149 | ], 150 | value: dartType.double, 151 | }, 152 | 153 | BorderStartWidth:{ 154 | type: "constructor", 155 | class: "BorderSide", 156 | properties: [ 157 | 158 | ], 159 | value: dartType.double, 160 | }, 161 | 162 | BorderEndWidth:{ 163 | type: "constructor", 164 | class: "BorderSide", 165 | properties: [ 166 | 167 | ], 168 | value: dartType.double, 169 | }, 170 | 171 | BorderTopWidth: { 172 | type: "constructor", 173 | class: "BorderSide", 174 | properties: [ 175 | 176 | ], 177 | value: dartType.double, 178 | }, 179 | 180 | BorderLeftWidth: { 181 | type: "constructor", 182 | class: "BorderSide", 183 | properties: [ 184 | 185 | ], 186 | value: dartType.double, 187 | }, 188 | 189 | BorderRightWidth: { 190 | type: "constructor", 191 | class: "BorderSide", 192 | properties: [ 193 | 194 | ], 195 | value: dartType.double, 196 | }, 197 | 198 | Border: { 199 | type: "constructor", 200 | class: "Border.all", 201 | properties: [ 202 | 203 | ], 204 | value: dartType.double, 205 | callee: "Border", 206 | 207 | }, 208 | 209 | 210 | 211 | BorderRadius: { 212 | type: "constructor", 213 | class: "BorderRadius.circular", 214 | namedProp: "borderRadius", 215 | properties: [ 216 | 217 | ], 218 | value: dartType.double, 219 | }, 220 | 221 | 222 | 223 | BorderTopLeftRadius: { 224 | type: "constructor", 225 | class: "BorderRadius.only", 226 | properties: [ 227 | 228 | ], 229 | value: dartType.double, 230 | }, 231 | 232 | 233 | 234 | 235 | 236 | 237 | BorderBottomLeftRadius: { 238 | type: "constructor", 239 | class: "BorderRadius.only", 240 | properties: [ 241 | 242 | ], 243 | value: dartType.double, 244 | }, 245 | 246 | 247 | TextStyle :{ 248 | type:"constructor", 249 | class:"TextStyle", 250 | namedProp:"style", 251 | properties: [ 252 | 253 | ], 254 | }, 255 | 256 | FontStyle:{ 257 | type:"enum", 258 | class : "FontStyle", 259 | value : "", 260 | }, 261 | FontWeight:{ 262 | type:"enum", 263 | class : "FontWeight", 264 | value : "", 265 | }, 266 | TextAlign :{ 267 | type:"enum", 268 | class:"TextAlign", 269 | value:"" 270 | }, 271 | 272 | FontFamily :{ 273 | type:"string", 274 | class:"FontFamily", 275 | value:"" 276 | } 277 | } as const 278 | -------------------------------------------------------------------------------- /src/config/index.ts: -------------------------------------------------------------------------------- 1 | import { layoutProps } from "./layout-props"; 2 | import { textProp } from "./text-props"; 3 | 4 | export const styleSystem : any = { 5 | ...layoutProps, 6 | ...textProp 7 | } -------------------------------------------------------------------------------- /src/config/layout-props.ts: -------------------------------------------------------------------------------- 1 | import { getAlignmentAxis } from "../utils/getAlignmentAxis" 2 | import { getBorder } from "../utils/getBorder" 3 | import { getBorderRadius } from "../utils/getBorderRadius" 4 | import { getExpanded } from "../utils/getExpanded" 5 | import { getMargin } from "../utils/getMargin" 6 | import { getPadding } from "../utils/getPadding" 7 | import { getPositioned } from "../utils/getPositioned" 8 | import { toDouble, toInt } from "../utils/converter" 9 | import { flutterWidget } from "./flutter-widgets" 10 | 11 | 12 | export const dartType = { 13 | double: { 14 | type: "double", 15 | transformer: toDouble, 16 | value: "", 17 | }, 18 | int: { 19 | type: "int", 20 | transformer: toInt, 21 | value: "" 22 | }, 23 | 24 | } as const 25 | 26 | 27 | export const layoutProps = { 28 | 29 | 30 | "minHeight": { 31 | widget: "Container", 32 | "property": "minHeight", 33 | class: dartType.double, 34 | "partOf": { 35 | "class": flutterWidget.BoxConstraints, 36 | "property": "constraints", 37 | } 38 | }, 39 | 40 | "minWidth": { 41 | widget: "Container", 42 | "property": "minWidth", 43 | class: dartType.double, 44 | "partOf": { 45 | "class": flutterWidget.BoxConstraints, 46 | "property": "constraints", 47 | } 48 | }, 49 | 50 | "maxHeight": { 51 | widget: "Container", 52 | "property": "maxHeight", 53 | class: dartType.double, 54 | "partOf": { 55 | "class": flutterWidget.BoxConstraints, 56 | "property": "constraints", 57 | } 58 | }, 59 | 60 | "maxWidth": { 61 | widget: "Container", 62 | "property": "maxWidth", 63 | class: dartType.double, 64 | "partOf": { 65 | "class": flutterWidget.BoxConstraints, 66 | "property": "constraints", 67 | } 68 | }, 69 | 70 | "width": { 71 | "widget": "Container", 72 | "property": "width", 73 | class: dartType.double 74 | 75 | }, 76 | 77 | 78 | "height": { 79 | "widget": "Container", 80 | "property": "height", 81 | class: dartType.double 82 | }, 83 | 84 | "backgroundColor": { 85 | "widget": "Container", 86 | "property": "color", 87 | class: flutterWidget.Color, 88 | "partOf": { 89 | "class": flutterWidget.BoxDecoration, 90 | "property": "decoration", 91 | } 92 | }, 93 | 94 | "borderRadius": { 95 | "widget": "Container", 96 | "property": "borderRadius", 97 | class: flutterWidget.BorderRadius, 98 | "partOf": { 99 | "class": flutterWidget.BoxDecoration, 100 | "property": "decoration", 101 | }, 102 | transformer: getBorderRadius 103 | }, 104 | 105 | "borderTopLeftRadius": { 106 | "widget": "Container", 107 | "property": "borderRadius", 108 | class: flutterWidget.BorderTopLeftRadius, 109 | "partOf": { 110 | "class": flutterWidget.BoxDecoration, 111 | "property": "decoration", 112 | }, 113 | transformer: getBorderRadius 114 | }, 115 | 116 | "borderTopRightRadius": { 117 | "widget": "Container", 118 | "property": "borderRadius", 119 | class: flutterWidget.BorderTopLeftRadius, 120 | "partOf": { 121 | "class": flutterWidget.BoxDecoration, 122 | "property": "decoration", 123 | }, 124 | transformer: getBorderRadius 125 | }, 126 | 127 | "borderBottomLeftRadius": { 128 | "widget": "Container", 129 | "property": "borderRadius", 130 | class: flutterWidget.BorderBottomLeftRadius, 131 | "partOf": { 132 | "class": flutterWidget.BoxDecoration, 133 | "property": "decoration", 134 | }, 135 | transformer: getBorderRadius 136 | }, 137 | 138 | 139 | borderWidth: { 140 | "widget": "Container", 141 | "property": "border", 142 | class: flutterWidget.Border, 143 | "partOf": { 144 | "class": flutterWidget.BoxDecoration, 145 | "property": "decoration", 146 | }, 147 | 148 | transformer: getBorder, 149 | }, 150 | 151 | 152 | borderStartWidth: { 153 | "widget": "Container", 154 | "property": "border", 155 | class: flutterWidget.Border, 156 | "partOf": { 157 | "class": flutterWidget.BoxDecoration, 158 | "property": "decoration", 159 | }, 160 | 161 | transformer: getBorder, 162 | }, 163 | 164 | borderEndWidth: { 165 | "widget": "Container", 166 | "property": "border", 167 | class: flutterWidget.Border, 168 | "partOf": { 169 | "class": flutterWidget.BoxDecoration, 170 | "property": "decoration", 171 | }, 172 | 173 | transformer: getBorder, 174 | }, 175 | 176 | borderBottomWidth :{ 177 | "widget": "Container", 178 | "property": "border", 179 | class: flutterWidget.Border, 180 | "partOf": { 181 | "class": flutterWidget.BoxDecoration, 182 | "property": "decoration", 183 | }, 184 | transformer: getBorder, 185 | }, 186 | 187 | borderTopWidth :{ 188 | "widget": "Container", 189 | "property": "border", 190 | class: flutterWidget.Border, 191 | "partOf": { 192 | "class": flutterWidget.BoxDecoration, 193 | "property": "decoration", 194 | }, 195 | transformer: getBorder, 196 | }, 197 | 198 | borderRightWidth :{ 199 | "widget": "Container", 200 | "property": "border", 201 | class: flutterWidget.Border, 202 | "partOf": { 203 | "class": flutterWidget.BoxDecoration, 204 | "property": "decoration", 205 | }, 206 | transformer: getBorder, 207 | }, 208 | 209 | borderLeftWidth :{ 210 | "widget": "Container", 211 | "property": "border", 212 | class: flutterWidget.Border, 213 | "partOf": { 214 | "class": flutterWidget.BoxDecoration, 215 | "property": "decoration", 216 | }, 217 | transformer: getBorder, 218 | }, 219 | 220 | borderColor: { 221 | "widget": "Container", 222 | "property": "border", 223 | class: flutterWidget.Border, 224 | "partOf": { 225 | "class": flutterWidget.BoxDecoration, 226 | "property": "decoration", 227 | }, 228 | transformer: getBorder, 229 | }, 230 | 231 | "padding": { 232 | "widget": "Container", 233 | "property": "padding", 234 | class: flutterWidget.EdgeInsets, 235 | transformer: getPadding, 236 | 237 | }, 238 | paddingLeft: { 239 | "widget": "Container", 240 | "property": "padding", 241 | class: flutterWidget.EdgeInsets, 242 | transformer: getPadding, 243 | }, 244 | 245 | paddingRight: { 246 | "widget": "Container", 247 | "property": "padding", 248 | class: flutterWidget.EdgeInsets, 249 | transformer: getPadding, 250 | }, 251 | 252 | paddingTop: { 253 | "widget": "Container", 254 | "property": "padding", 255 | class: flutterWidget.EdgeInsets, 256 | transformer: getPadding, 257 | }, 258 | 259 | paddingBottom: { 260 | "widget": "Container", 261 | "property": "padding", 262 | class: flutterWidget.EdgeInsets, 263 | transformer: getPadding, 264 | }, 265 | 266 | margin: { 267 | "widget": "Container", 268 | "property": "margin", 269 | class: flutterWidget.EdgeInsets, 270 | transformer: getMargin, 271 | }, 272 | 273 | marginLeft: { 274 | "widget": "Container", 275 | "property": "margin", 276 | class: flutterWidget.EdgeInsets, 277 | transformer: getMargin, 278 | }, 279 | 280 | 281 | marginStart: { 282 | "widget": "Container", 283 | "property": "margin", 284 | class: flutterWidget.EdgeInsetsDirectional, 285 | transformer: getMargin, 286 | }, 287 | marginEnd: { 288 | "widget": "Container", 289 | "property": "margin", 290 | class: flutterWidget.EdgeInsetsDirectional, 291 | transformer: getMargin, 292 | }, 293 | 294 | marginRight: { 295 | "widget": "Container", 296 | "property": "margin", 297 | class: flutterWidget.EdgeInsets, 298 | transformer: getMargin, 299 | }, 300 | 301 | marginTop: { 302 | "widget": "Container", 303 | "property": "margin", 304 | class: flutterWidget.EdgeInsets, 305 | transformer: getMargin, 306 | }, 307 | 308 | marginBottom: { 309 | "widget": "Container", 310 | "property": "margin", 311 | class: flutterWidget.EdgeInsets, 312 | transformer: getMargin, 313 | }, 314 | 315 | marginHorizontal :{ 316 | "widget": "Container", 317 | "property": "margin", 318 | class: flutterWidget.EdgeInsets, 319 | transformer: getMargin, 320 | }, 321 | 322 | marginVertical :{ 323 | "widget": "Container", 324 | "property": "margin", 325 | class: flutterWidget.EdgeInsets, 326 | transformer: getMargin, 327 | }, 328 | 329 | alignContent:{ 330 | widget:"Column", 331 | "property": "mainAxisAlignment", 332 | class : flutterWidget.MainAxisAlignment, 333 | transformer : getAlignmentAxis 334 | }, 335 | 336 | flexDirection:{ 337 | widget:"Row", 338 | class : flutterWidget.Row, 339 | transformer : getAlignmentAxis 340 | }, 341 | 342 | alignItems :{ 343 | widget:"Column", 344 | "property": "crossAxisAlignment", 345 | class : flutterWidget.CrossAxisAlignment, 346 | transformer : getAlignmentAxis 347 | }, 348 | 349 | justifyContent :{ 350 | widget:"Column", 351 | "property": "mainAxisAlignment", 352 | class : flutterWidget.MainAxisAlignment, 353 | transformer : getAlignmentAxis 354 | }, 355 | 356 | 357 | 358 | position :{ 359 | widget:"Positioned", 360 | class: flutterWidget.Positioned, 361 | transformer : getPositioned 362 | }, 363 | 364 | flexGrow:{ 365 | widget:"Expanded", 366 | class:flutterWidget.Expanded, 367 | transformer:getExpanded, 368 | }, 369 | 370 | flex:{ 371 | widget:"Flex", 372 | class: flutterWidget.Expanded, 373 | transformer:getExpanded 374 | }, 375 | 376 | top:{ 377 | widget:"Positioned", 378 | property:"top", 379 | class:dartType.double, 380 | }, 381 | 382 | bottom:{ 383 | widget:"Positioned", 384 | property:"bottom", 385 | class:dartType.double, 386 | }, 387 | 388 | right:{ 389 | widget:"Positioned", 390 | property:"right", 391 | class:dartType.double, 392 | }, 393 | 394 | left:{ 395 | widget:"Positioned", 396 | property:"left", 397 | class:dartType.double, 398 | }, 399 | 400 | 401 | "boxShadow": { 402 | "widget": "Container", 403 | "property": "boxShadow", 404 | "partOf": { 405 | "class": "BoxDecoration", 406 | "property": "decoration", 407 | 408 | } 409 | }, 410 | 411 | 412 | 413 | 414 | "fontSize": { 415 | "widget": "Text", 416 | "property": "fontSize", 417 | "partOf": { 418 | "class": "TextStyle", 419 | "property": "style" 420 | } 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /src/config/text-props.ts: -------------------------------------------------------------------------------- 1 | import { getFontStyle } from "../utils/getFontStyle"; 2 | import { getFontWeight } from "../utils/getFontWeight"; 3 | import { getFontFamily } from "../utils/getFontFamily"; 4 | import { getTextAlign } from "../utils/getTextAlign"; 5 | import { dartType, flutterWidget } from "./flutter-widgets"; 6 | 7 | export const textProp = { 8 | 9 | 10 | color: { 11 | widget: "Text", 12 | "property": "color", 13 | class: flutterWidget.Color, 14 | "partOf": { 15 | "class": flutterWidget.TextStyle, 16 | "property": "style", 17 | } 18 | }, 19 | 20 | 21 | fontSize: { 22 | widget: "Text", 23 | "property": "fontSize", 24 | class: dartType.double, 25 | "partOf": { 26 | "class": flutterWidget.TextStyle, 27 | "property": "style", 28 | } 29 | }, 30 | 31 | letterSpacing: { 32 | widget: "Text", 33 | "property": "letterSpacing", 34 | class: dartType.double, 35 | "partOf": { 36 | "class": flutterWidget.TextStyle, 37 | "property": "style", 38 | } 39 | }, 40 | 41 | lineHeight: { 42 | widget: "Text", 43 | "property": "height", 44 | class: dartType.double, 45 | "partOf": { 46 | "class": flutterWidget.TextStyle, 47 | "property": "style", 48 | } 49 | }, 50 | 51 | fontStyle :{ 52 | 53 | widget: "Text", 54 | "property": "fontStyle", 55 | class: flutterWidget.FontStyle, 56 | "partOf": { 57 | "class": flutterWidget.TextStyle, 58 | "property": "style", 59 | }, 60 | transformer:getFontStyle 61 | }, 62 | 63 | fontWeight :{ 64 | 65 | widget: "Text", 66 | "property": "fontWeight", 67 | class: flutterWidget.FontWeight, 68 | "partOf": { 69 | "class": flutterWidget.TextStyle, 70 | "property": "style", 71 | }, 72 | transformer:getFontWeight 73 | }, 74 | 75 | textAlign :{ 76 | widget:"Text", 77 | property:"textAlign", 78 | class : flutterWidget.TextAlign, 79 | transformer:getTextAlign 80 | }, 81 | fontFamily : { 82 | widget: "Text", 83 | "property": "fontFamily", 84 | class: flutterWidget.FontFamily, 85 | "partOf": { 86 | "class": flutterWidget.TextStyle, 87 | "property": "style", 88 | }, 89 | transformer:getFontFamily 90 | } 91 | } -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { styleSystem } from "./config"; 4 | import { flutterWidget } from "./config/flutter-widgets"; 5 | import { pushPropToWidget } from "./utils/pushPropToWidget"; 6 | 7 | import * as parser from '@babel/parser'; 8 | //@ts-ignore 9 | import xyz from '@babel/preset-react' 10 | import { buildDartASTfromAST, searchForDeepChildAndPush } from "./buildDartASTfromAST"; 11 | import { addProperty } from "./addProperty"; 12 | import { clearProperties } from "./clearProperties"; 13 | 14 | 15 | 16 | let mapReactComponentToFlutterWidgets: any = { 17 | "View": flutterWidget.Container, 18 | "Text": flutterWidget.Text 19 | }; 20 | 21 | 22 | let count = 0; 23 | 24 | 25 | export function buildDartAST(component: any, theme: any) { 26 | 27 | let dartAST: any = {} 28 | 29 | try { 30 | let widget: any = { ...mapReactComponentToFlutterWidgets[component] }; 31 | 32 | // delete widget.properties; 33 | widget.properties = [] 34 | let a = '' 35 | a = widget; 36 | 37 | clearProperties(theme); 38 | 39 | dartAST = loopStyle(theme, a); 40 | 41 | 42 | } catch (error) { 43 | console.error(error) 44 | return error 45 | } finally { 46 | return dartAST; 47 | // createFlutterWidget(dartAST,count) 48 | 49 | } 50 | 51 | 52 | 53 | } 54 | 55 | 56 | function loopStyle(theme: any, ast: any) { 57 | 58 | 59 | Object.entries(theme).map(([k, v]: any) => { 60 | 61 | 62 | 63 | if (styleSystem.hasOwnProperty(k)) { 64 | 65 | if (styleSystem[k].hasOwnProperty("partOf")) { 66 | if (ast["properties"]) { 67 | 68 | let newVal = { [styleSystem[k].partOf.property]: styleSystem[k].partOf.class }; 69 | let myObject = addProperty(newVal[styleSystem[k].partOf.property], v, k, theme, ast); 70 | let widget = styleSystem[k].widget; 71 | if (myObject.nested) { 72 | ast = myObject.object; 73 | } else { 74 | pushPropToWidget(ast, myObject, widget); 75 | } 76 | } 77 | } else { 78 | 79 | let newVal = { ...styleSystem[k].class }; 80 | let myObject = addProperty(newVal, v, k, theme, ast); 81 | let widget = styleSystem[k].widget; 82 | 83 | if (myObject.nested) { 84 | ast = myObject.object; 85 | } else { 86 | pushPropToWidget(ast, myObject, widget); 87 | } 88 | 89 | 90 | } 91 | } 92 | 93 | }); 94 | 95 | return ast; 96 | } 97 | 98 | let code: string = "" 99 | let tab: string = '\t'; 100 | // @ts-ignore 101 | 102 | export function createFlutterWidget(ast: any, c: number) { 103 | 104 | if (ast?.hasOwnProperty("namedProp")) { 105 | if (ast.type === "constructor") { 106 | // if (ast.hasOwnProperty("value")) { 107 | 108 | // code += `${tab.repeat(c)}${ast.namedProp}:${ast.class}('${ast.value}',\n` 109 | // } else { 110 | code += `${tab.repeat(c)}${ast.namedProp}:${ast.class}(\n` 111 | //} 112 | 113 | } else if (ast.type === "Array") { 114 | code += `${tab.repeat(c)}${ast.namedProp}:[\n` 115 | } 116 | 117 | } else { 118 | 119 | if (ast?.hasOwnProperty("value")) { 120 | 121 | code += `${tab.repeat(c)}${ast.class}('${ast.value}',\n` 122 | } else { 123 | 124 | code += `${tab.repeat(c)}${ast?.class}(\n` 125 | } 126 | 127 | } 128 | c++ 129 | if (ast?.hasOwnProperty("properties")) { 130 | Object.entries(ast?.properties).forEach(([, v]: any) => { 131 | 132 | if (v.hasOwnProperty("properties") || v.hasOwnProperty("widgets")) { 133 | createFlutterWidget(v, c); 134 | code += `${tab.repeat(c)}),\n` 135 | 136 | 137 | } else { 138 | 139 | 140 | let innerValue = v; 141 | let innerKey 142 | 143 | 144 | 145 | 146 | if (innerValue.class) { 147 | if (innerValue.type === "constructor" || innerValue.type === "enum" || innerValue.type === "string") { 148 | if (innerValue.hasOwnProperty("properties")) { 149 | createFlutterWidget(innerValue, c); 150 | 151 | } 152 | 153 | 154 | if (innerValue.value.transformer) { 155 | innerValue.value.value = innerValue.value.transformer(innerValue.value.value) 156 | } else { 157 | if (innerValue.transformer) { 158 | innerValue.value = innerValue.transformer(innerValue.value) 159 | } 160 | } 161 | 162 | if (innerValue.type === "constructor") { 163 | // Build class when its constrictor 164 | /// for eg Color(0xffffffff) 165 | 166 | code += `${tab.repeat(c)}${innerValue.namedProp}:${innerValue.class}(${innerValue.value.value ?? innerValue.value}),\n` 167 | } else if (innerValue.type === "enum") { 168 | // Build class when its constrictor 169 | /// for eg MainAxisAlignment.center 170 | code += `${tab.repeat(c)}${innerValue.namedProp}:${innerValue.class}.${innerValue.value.value ?? innerValue.value},\n` 171 | } else if (innerValue.type === "string") { 172 | 173 | code += `${tab.repeat(c)}${innerValue.namedProp}: "${innerValue.value.value ?? innerValue.value}", \n` 174 | } 175 | 176 | } 177 | 178 | 179 | } else { 180 | 181 | 182 | 183 | 184 | if (innerValue.type === "nameConstructor") { 185 | 186 | let args: string = '' 187 | 188 | if (innerValue.args) { 189 | Object.entries(innerValue.args[0]).forEach(([k, v]: any, index: number) => { 190 | 191 | if (index == 0) { 192 | args += `\n`; 193 | } 194 | if (v.transformer) { 195 | v.value = v.transformer(v.value); 196 | } 197 | args += `${tab.repeat(c + 1)}${k}:${v.value},\n` 198 | }) 199 | code += `${tab.repeat(c)}${innerKey}:${innerValue.callee}.${innerValue.name}(${args}${tab.repeat(c)}),\n` 200 | } else { 201 | code += `${tab.repeat(c)}${innerKey}:${innerValue.callee}.${innerValue.name}(\n${innerValue.value}),\n` 202 | } 203 | } else if (innerValue.type == "Array") { 204 | 205 | code += `${tab.repeat(c)}${innerValue.namedProp}:[\n` 206 | c++; 207 | Object.entries(innerValue.values).forEach(([, v]: any) => { 208 | 209 | createFlutterWidget(v, c); 210 | code += `${tab.repeat(c)}),\n` 211 | }); 212 | c--; 213 | code += `${tab.repeat(c)}],\n` 214 | } else { 215 | 216 | if (innerValue.transformer) { 217 | 218 | innerValue.value = innerValue.transformer(innerValue.value ?? innerValue) 219 | } 220 | code += `${tab.repeat(c)}${innerValue.namedProp}:${innerValue.value ?? innerValue},\n` 221 | } 222 | } 223 | } 224 | 225 | }); 226 | } 227 | 228 | 229 | 230 | } 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | export const convertNativeBaseThemeToFlutterWidgets = (styles: any): string => { 244 | 245 | 246 | 247 | 248 | 249 | 250 | try { 251 | 252 | let ast: any; 253 | code = ''; 254 | 255 | try { 256 | ast = parser.parse(styles, { 257 | plugins: [ 258 | // enable jsx and flow syntax 259 | "jsx", 260 | "flow", 261 | ], 262 | }); 263 | console.log(ast); 264 | 265 | let style: any = {}; 266 | let myDartAST: any; 267 | let expression = ast.program.body[0].expression; 268 | let name = expression.openingElement.name.name; 269 | 270 | if (expression.type === "JSXElement") { 271 | 272 | let attributes = expression.openingElement.attributes[0]; 273 | if (attributes) { 274 | if (attributes?.name?.name === "style") { 275 | 276 | let properties = attributes.value.expression.properties; 277 | Object.entries(properties).forEach(([, v]: any) => { 278 | style[v.key.name] = v.value.value 279 | }); 280 | myDartAST = buildDartAST(name, style) 281 | let layout: any = { 282 | type: "constructor", 283 | properties: [] 284 | } 285 | 286 | console.log(myDartAST); 287 | 288 | if (name === "View") { 289 | 290 | let index = myDartAST.properties.findIndex((data: any) => (data.class === "Row" || data.class === "Column")); 291 | if (index > -1) { 292 | 293 | // layout = {...layout,"class": myDartAST.properties[index].class} 294 | // myDartAST.properties.splice(index, 1); 295 | } else { 296 | layout = {...layout,"class": "Row"} 297 | } 298 | 299 | // myDartAST.properties.push({ ...layout, "namedProp": "child" }) 300 | 301 | searchForDeepChildAndPush(myDartAST,{...layout,"namedProp": "child" }); 302 | } 303 | 304 | 305 | } 306 | } else { 307 | myDartAST = buildDartAST(name, style) 308 | let layout: any = { 309 | type: "constructor", 310 | properties: [] 311 | } 312 | 313 | if (name === "View") { 314 | let index = myDartAST.properties.findIndex((data: any) => (data.class === "Row" || data.class === "Column")); 315 | if (index > -1) { 316 | // layout = {...layout,"class": myDartAST.properties[index].class} 317 | // myDartAST.properties.splice(index, 1); 318 | } else { 319 | layout = {...layout,"class": "Row"} 320 | } 321 | 322 | //searchForDeepChildAndPush(myDartAST,{}); 323 | 324 | searchForDeepChildAndPush(myDartAST,{...layout,"namedProp": "child" }); 325 | 326 | // myDartAST.properties.push({ ...layout, "namedProp": "child" }) 327 | 328 | } 329 | } 330 | 331 | } 332 | 333 | buildDartASTfromAST(expression, myDartAST); 334 | 335 | createFlutterWidget(myDartAST, count); 336 | } catch (error) { 337 | 338 | console.log(error); 339 | code = error as string; 340 | } 341 | code += ');\n' 342 | 343 | } catch (error) { 344 | code = error as string 345 | } 346 | return code; 347 | } 348 | 349 | -------------------------------------------------------------------------------- /src/utils/arr.js: -------------------------------------------------------------------------------- 1 | const split2Arr = (val, sign = ")") => { 2 | const arr = val.split(`${sign} `); 3 | for (let i = 0; i < arr.length; i++) { 4 | const str = arr[i]; 5 | const reg = new RegExp(`\\${sign}$`, "gi"); 6 | if (!reg.test(str)) arr[i] = str + sign; 7 | } 8 | return arr; 9 | }; 10 | 11 | export { split2Arr }; 12 | -------------------------------------------------------------------------------- /src/utils/camel.ts: -------------------------------------------------------------------------------- 1 | export const toCamel = (val:any) => { 2 | let re = /-(\w)/g; 3 | return val.replace(re, function ($1:any) { 4 | return $1.toUpperCase(); 5 | }); 6 | }; 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/utils/converter.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const getColor = (value: string) => { 4 | let color = value.replace("#", "0xff"); 5 | return color 6 | 7 | }; 8 | 9 | 10 | export const toDouble = (value: any) => { 11 | 12 | return parseFloat(value).toFixed(1) 13 | } 14 | 15 | export const toInt = (value: any) => { 16 | if(typeof value === "string"){ 17 | if (value.indexOf("#") === 0) { 18 | value = value.replace("#", "0xff"); 19 | return value 20 | } 21 | } else if(typeof value === "number"){ 22 | return value; 23 | } 24 | 25 | return parseInt(value); 26 | 27 | } 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/utils/getAlignmentAxis.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { flutterWidget } from "../config/flutter-widgets"; 3 | import { toCamel } from "./camel"; 4 | import { pushPropToWidget } from "./pushPropToWidget"; 5 | 6 | 7 | 8 | export const getAlignmentAxis = (styles: any, object: any, ast: any) => { 9 | 10 | let layoutWidget: any = { ...flutterWidget.Row }; 11 | //layoutWidget.properties = []; 12 | if (styles.hasOwnProperty("flexDirection")) { 13 | if (styles.flexDirection === "column") { 14 | 15 | layoutWidget = { ...flutterWidget.Column }; 16 | 17 | } 18 | } 19 | 20 | if (object.hasOwnProperty("value")) { 21 | object = { ...object, value: object.value.replace(/flex-/, "") }; 22 | 23 | object = { ...object, value: toCamel(object.value) }; 24 | object = { ...object, value: object.value.replace(/-/, "") }; 25 | } 26 | 27 | 28 | let index = layoutWidget.properties.findIndex((data: any) => (data.class === object.class)); 29 | if (index > -1) { 30 | 31 | layoutWidget.properties.splice(index, 1); 32 | } 33 | 34 | 35 | if (object.hasOwnProperty("value")) { 36 | layoutWidget.properties.push(object); 37 | } 38 | 39 | layoutWidget["namedProp"] = "child"; 40 | 41 | 42 | pushPropToWidget(ast, layoutWidget, flutterWidget.Container.class); 43 | 44 | 45 | object = ast; 46 | 47 | return { nested: true, object }; 48 | }; 49 | -------------------------------------------------------------------------------- /src/utils/getBorder.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | import { dartType } from "../config/layout-props"; 3 | 4 | 5 | 6 | 7 | export const getBorder = (styles: any, object: any) => { 8 | 9 | object.properties = []; 10 | if (styles.hasOwnProperty("borderWidth")) { 11 | 12 | 13 | let widget: any = dartType.double; 14 | widget.value = styles["borderWidth"]; 15 | widget = { ...widget, namedProp: "width" }; 16 | object.properties.push(widget); 17 | 18 | if (styles.hasOwnProperty("borderColor")) { 19 | let widget: any = flutterWidget.Color; 20 | widget.value = styles["borderColor"]; 21 | object.properties.push(widget); 22 | } 23 | 24 | } 25 | 26 | else if (styles.borderEndWidth || styles.borderStartWidth) { 27 | 28 | object.properties = []; 29 | if (styles.hasOwnProperty("borderEndWidth")) { 30 | 31 | object.class = "BorderDirectional"; 32 | let widget: any = flutterWidget.BorderEndWidth; 33 | widget.properties = []; 34 | widget = { ...widget, namedProp: "end" }; 35 | let prop: any = dartType.double; 36 | prop.value = styles["borderEndWidth"]; 37 | prop = { ...prop, namedProp: "width" }; 38 | 39 | if (styles.hasOwnProperty("borderColor")) { 40 | let color: any = flutterWidget.Color; 41 | color.value = styles["borderColor"]; 42 | widget.properties.push(color); 43 | } 44 | widget.properties.push(prop); 45 | object.properties.push(widget); 46 | } 47 | 48 | if (styles.hasOwnProperty("borderStartWidth")) { 49 | 50 | object.class = "BorderDirectional"; 51 | let widget: any = flutterWidget.BorderStartWidth; 52 | widget.properties = []; 53 | widget = { ...widget, namedProp: "start" }; 54 | let prop: any = dartType.double; 55 | prop.value = styles["borderStartWidth"]; 56 | prop = { ...prop, namedProp: "width" }; 57 | 58 | if (styles.hasOwnProperty("borderColor")) { 59 | let color: any = flutterWidget.Color; 60 | color.value = styles["borderColor"]; 61 | widget.properties.push(color); 62 | } 63 | widget.properties.push(prop); 64 | object.properties.push(widget); 65 | } 66 | 67 | if (styles.hasOwnProperty("borderTopWidth")) { 68 | 69 | 70 | object.class = "BorderDirectional"; 71 | let widget: any = flutterWidget.BorderTopWidth; 72 | widget.properties = []; 73 | widget = { ...widget, namedProp: "top" }; 74 | let prop: any = dartType.double; 75 | prop.value = styles["borderTopWidth"]; 76 | prop = { ...prop, namedProp: "width" }; 77 | 78 | if (styles.hasOwnProperty("borderColor")) { 79 | let color: any = flutterWidget.Color; 80 | color.value = styles["borderColor"]; 81 | widget.properties.push(color); 82 | } 83 | widget.properties.push(prop); 84 | object.properties.push(widget); 85 | } 86 | 87 | if (styles.hasOwnProperty("borderBottomWidth")) { 88 | 89 | 90 | object.class = "BorderDirectional"; 91 | let widget: any = flutterWidget.BorderBottomWidth; 92 | widget.properties = []; 93 | widget = { ...widget, namedProp: "bottom" }; 94 | let prop: any = dartType.double; 95 | prop.value = styles["borderBottomWidth"]; 96 | prop = { ...prop, namedProp: "width" }; 97 | 98 | if (styles.hasOwnProperty("borderColor")) { 99 | let color: any = flutterWidget.Color; 100 | color.value = styles["borderColor"]; 101 | widget.properties.push(color); 102 | } 103 | widget.properties.push(prop); 104 | object.properties.push(widget); 105 | } 106 | 107 | } else { 108 | 109 | if (styles.hasOwnProperty("borderBottomWidth")) { 110 | 111 | object.properties = []; 112 | object.class = "Border"; 113 | let widget: any = flutterWidget.BorderBottomWidth; 114 | widget.properties = []; 115 | widget = { ...widget, namedProp: "bottom" }; 116 | let prop: any = dartType.double; 117 | prop.value = styles["borderBottomWidth"]; 118 | prop = { ...prop, namedProp: "width" }; 119 | 120 | if (styles.hasOwnProperty("borderColor")) { 121 | let color: any = flutterWidget.Color; 122 | color.value = styles["borderColor"]; 123 | widget.properties.push(color); 124 | } 125 | widget.properties.push(prop); 126 | object.properties.push(widget); 127 | } 128 | 129 | if (styles.hasOwnProperty("borderTopWidth")) { 130 | 131 | 132 | object.class = "Border"; 133 | let widget: any = flutterWidget.BorderBottomWidth; 134 | widget.properties = []; 135 | widget = { ...widget, namedProp: "top" }; 136 | let prop: any = dartType.double; 137 | prop.value = styles["borderTopWidth"]; 138 | prop = { ...prop, namedProp: "width" }; 139 | 140 | if (styles.hasOwnProperty("borderColor")) { 141 | let color: any = flutterWidget.Color; 142 | color.value = styles["borderColor"]; 143 | widget.properties.push(color); 144 | } 145 | widget.properties.push(prop); 146 | object.properties.push(widget); 147 | } 148 | 149 | if (styles.hasOwnProperty("borderLeftWidth")) { 150 | 151 | 152 | object.class = "Border"; 153 | let widget: any = flutterWidget.BorderBottomWidth; 154 | widget.properties = []; 155 | widget = { ...widget, namedProp: "left" }; 156 | let prop: any = dartType.double; 157 | prop.value = styles["borderLeftWidth"]; 158 | prop = { ...prop, namedProp: "width" }; 159 | 160 | if (styles.hasOwnProperty("borderColor")) { 161 | let color: any = flutterWidget.Color; 162 | color.value = styles["borderColor"]; 163 | widget.properties.push(color); 164 | } 165 | widget.properties.push(prop); 166 | object.properties.push(widget); 167 | } 168 | 169 | if (styles.hasOwnProperty("borderRightWidth")) { 170 | 171 | 172 | object.class = "Border"; 173 | let widget: any = flutterWidget.BorderBottomWidth; 174 | widget.properties = []; 175 | widget = { ...widget, namedProp: "right" }; 176 | let prop: any = dartType.double; 177 | prop.value = styles["borderRightWidth"]; 178 | prop = { ...prop, namedProp: "width" }; 179 | 180 | if (styles.hasOwnProperty("borderColor")) { 181 | let color: any = flutterWidget.Color; 182 | color.value = styles["borderColor"]; 183 | widget.properties.push(color); 184 | } 185 | widget.properties.push(prop); 186 | object.properties.push(widget); 187 | } 188 | } 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | return object; 198 | }; 199 | -------------------------------------------------------------------------------- /src/utils/getBorderRadius.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | 3 | 4 | 5 | 6 | export const getBorderRadius = (styles: any, object: any) => { 7 | 8 | object.properties = []; 9 | 10 | if (styles.hasOwnProperty("borderRadius")) { 11 | 12 | delete object.properties; 13 | } else if (styles.hasOwnProperty("borderEndWidth") || styles.hasOwnProperty("borderEndWidth")) { 14 | } else { 15 | 16 | if (styles.hasOwnProperty("borderTopLeftRadius")) { 17 | let widget: any = {...flutterWidget.RadiusCircular}; 18 | widget = { ...widget, namedProp: "topLeft",value:{value:styles["borderTopLeftRadius"]} }; 19 | 20 | object.properties.push(widget); 21 | 22 | } 23 | if (styles.hasOwnProperty("borderTopRightRadius")) { 24 | 25 | let widget: any = flutterWidget.RadiusCircular; 26 | //widget.value.value = styles["borderTopRightRadius"]; 27 | 28 | widget = { ...widget, namedProp: "topRight",value:{value:styles["borderTopRightRadius"],...widget.value} }; 29 | object.properties.push(widget); 30 | } 31 | 32 | if (styles.hasOwnProperty("borderBottomRightRadius")) { 33 | let widget: any = flutterWidget.RadiusCircular; 34 | widget.value.value = styles["borderBottomRightRadius"]; 35 | widget["namedProp"] = "bottomRight"; 36 | object.properties.push(widget); 37 | 38 | } 39 | 40 | if (styles.hasOwnProperty("borderBottomLeftRadius")) { 41 | 42 | let widget: any = flutterWidget.RadiusCircular; 43 | widget.value.value = styles["borderBottomLeftRadius"]; 44 | widget = { ...widget, namedProp: "bottomLeft" }; 45 | object.properties.push(widget); 46 | } 47 | } 48 | 49 | 50 | return object; 51 | }; 52 | -------------------------------------------------------------------------------- /src/utils/getExpanded.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | import { dartType } from "../config/layout-props"; 3 | 4 | 5 | 6 | export const getExpanded = (styles: any, object: any, ast?: any) => { 7 | let widget: any = {}; 8 | if (styles.hasOwnProperty("flexGrow")) { 9 | 10 | widget = {...flutterWidget.Expanded}; 11 | widget.properties = []; 12 | let flex: any = {}; 13 | flex = dartType.int; 14 | flex = { ...flex, value: styles.flexGrow }; 15 | flex["namedProp"] = "flex"; 16 | 17 | let index = widget.properties.findIndex((data: any) => (data.class === widget.class)); 18 | if (index) 19 | if (index > -1) { 20 | 21 | widget.properties.splice(index, 1); 22 | } 23 | widget.properties.push(flex); 24 | console.log(object); 25 | console.log(ast); 26 | if (ast.class === "Container") { 27 | delete widget.namedProp; 28 | //ast = widget; 29 | widget.properties.push({namedProp:"child",...ast}) 30 | object = widget; 31 | return { nested: true, object }; 32 | } else { 33 | searchForContainer(ast); 34 | } 35 | 36 | ast.properties = []; 37 | ast.properties.push(widget); 38 | 39 | object = ast; 40 | return { nested: true, object }; 41 | 42 | } else { 43 | return object; 44 | } 45 | 46 | function searchForContainer(_ast: any) { 47 | if (_ast.properties) { 48 | Object.entries(_ast.properties).forEach(([, v]: any) => { 49 | 50 | if (v.class === "Container") { 51 | widget["namedProp"] = "child"; 52 | widget.properties.push(v); 53 | } else { 54 | searchForContainer(v); 55 | } 56 | }); 57 | } 58 | 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /src/utils/getFlex.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | import { dartType } from "../config/layout-props"; 3 | 4 | 5 | 6 | export const getFlex = (styles: any, object: any, ast?: any) => { 7 | 8 | let widget: any = {}; 9 | if (styles.hasOwnProperty("flex")) { 10 | widget = {...flutterWidget.Flex}; 11 | widget.properties = []; 12 | let flex: any = {}; 13 | flex = dartType.double; 14 | flex = { ...flex, value: styles.flex }; 15 | flex["namedProp"] = "flex1"; 16 | let index = widget.properties.findIndex((data: any) => (data.class === widget.class)); 17 | 18 | if (index > -1) { 19 | 20 | widget.properties.splice(index, 1); 21 | } 22 | widget.properties.push(flex); 23 | console.log(object); 24 | console.log(ast); 25 | if (ast.class === "Container") { 26 | delete widget.namedProp; 27 | ast = widget; 28 | object = ast; 29 | return { nested: true, object }; 30 | } else { 31 | searchForContainer(ast); 32 | } 33 | ast.properties = []; 34 | ast.properties.push(widget); 35 | 36 | object = ast; 37 | return { nested: true, object }; 38 | } else { 39 | return object; 40 | } 41 | 42 | function searchForContainer(_ast: any) { 43 | if (_ast.properties) { 44 | Object.entries(_ast.properties).forEach(([, v]: any) => { 45 | 46 | if (v.class === "Container") { 47 | widget["namedProp"] = "child"; 48 | widget.properties.push(v); 49 | } else { 50 | searchForContainer(v); 51 | } 52 | }); 53 | } 54 | 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/utils/getFlexDirection.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | import { pushPropToWidget } from "./pushPropToWidget"; 3 | 4 | export const getFlexDirection = (styles: any, object: any={}, ast: any) => { 5 | 6 | let layoutWidget: any = { ...flutterWidget.Row }; 7 | layoutWidget.properties = []; 8 | if (styles.hasOwnProperty("flexDirection")) { 9 | if (styles.flexDirection === "column") { 10 | 11 | layoutWidget = { ...flutterWidget.Column }; 12 | 13 | } 14 | } 15 | 16 | let index = layoutWidget.properties.findIndex((data: any) => (data.class === object.class)); 17 | if (index > -1) { 18 | 19 | layoutWidget.properties.splice(index, 1); 20 | } 21 | 22 | 23 | 24 | layoutWidget.properties.push(object); 25 | 26 | 27 | layoutWidget["namedProp"] = "child"; 28 | 29 | let rowOrColIndex = ast.properties.findIndex((data: any) => (data.class === "Row" || data.class === "Column")); 30 | console.log(rowOrColIndex); 31 | 32 | pushPropToWidget(ast, layoutWidget, flutterWidget.Container.class); 33 | 34 | 35 | object = ast; 36 | 37 | return { nested: true, object }; 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/getFontFamily.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const getFontFamily = (styles: any, object: any) => { 4 | 5 | 6 | object = { ...object, value: styles.fontFamily }; 7 | return object; 8 | }; 9 | -------------------------------------------------------------------------------- /src/utils/getFontStyle.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | export const getFontStyle = (styles: any, object: any) => { 8 | switch (styles.fontStyle) { 9 | case "italic": 10 | object = {...object,value:"italic"} 11 | 12 | break; 13 | case "normal": 14 | object = {...object,value:"normal"} 15 | 16 | 17 | break; 18 | default: 19 | object = {...object,value:"normal"} 20 | 21 | 22 | break; 23 | } 24 | 25 | return object; 26 | }; 27 | -------------------------------------------------------------------------------- /src/utils/getFontWeight.tsx: -------------------------------------------------------------------------------- 1 | import { isNumerical } from "./unit"; 2 | 3 | 4 | 5 | export const getFontWeight = (styles: any, object: any) => { 6 | 7 | if (isNumerical(styles.fontWeight)) { 8 | object.value = 'w' + styles.fontWeight; 9 | } else { 10 | object.value = styles.fontWeight; 11 | } 12 | return object; 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/getMargin.tsx: -------------------------------------------------------------------------------- 1 | import { dartType } from "../config/layout-props"; 2 | 3 | 4 | 5 | 6 | export const getMargin = (styles: any, object: any) => { 7 | object.properties = []; 8 | 9 | if (styles.hasOwnProperty("margin")) { 10 | 11 | delete object.properties; 12 | } else if(styles.marginStart || styles.marginEnd){ 13 | object.class = "EdgeInsetsDirectional.only"; 14 | if (styles.hasOwnProperty("marginStart")) { 15 | 16 | let widget: any = dartType.double; 17 | widget.value = styles["marginStart"]; 18 | widget = { ...widget, namedProp: "start" }; 19 | object.properties.push(widget); 20 | 21 | } 22 | 23 | if (styles.hasOwnProperty("marginEnd")) { 24 | 25 | let widget: any = dartType.double; 26 | widget.value = styles["marginEnd"]; 27 | widget = { ...widget, namedProp: "end" }; 28 | object.properties.push(widget); 29 | 30 | } 31 | 32 | if (styles.hasOwnProperty("marginTop")) { 33 | 34 | let widget: any = dartType.double; 35 | widget.value = styles["marginTop"]; 36 | widget = { ...widget, namedProp: "top" }; 37 | object.properties.push(widget); 38 | 39 | } 40 | 41 | if (styles.hasOwnProperty("marginBottom")) { 42 | 43 | let widget: any = dartType.double; 44 | widget.value = styles["marginBottom"]; 45 | widget = { ...widget, namedProp: "bottom" }; 46 | object.properties.push(widget); 47 | 48 | } 49 | 50 | } 51 | else { 52 | 53 | 54 | object.class = "EdgeInsets.only"; 55 | if (styles.hasOwnProperty("marginLeft") || styles.marginHorizontal) { 56 | 57 | let widget: any = dartType.double; 58 | widget.value = styles["marginLeft"] ?? styles.marginHorizontal; 59 | widget = { ...widget, namedProp: "left" }; 60 | object.properties.push(widget); 61 | 62 | } 63 | 64 | if (styles.hasOwnProperty("marginRight") || styles.marginHorizontal) { 65 | 66 | let widget: any = dartType.double; 67 | widget.value = styles["marginRight"] ?? styles.marginHorizontal; 68 | widget = { ...widget, namedProp: "right" }; 69 | object.properties.push(widget); 70 | 71 | } 72 | 73 | if (styles.hasOwnProperty("marginTop") || styles.marginVertical) { 74 | 75 | let widget: any = dartType.double; 76 | widget.value = styles["marginTop"] ?? styles.marginVertical; 77 | widget = { ...widget, namedProp: "top" }; 78 | object.properties.push(widget); 79 | 80 | } 81 | 82 | if (styles.hasOwnProperty("marginBottom") || styles.marginVertical) { 83 | 84 | let widget: any = dartType.double; 85 | widget.value = styles["marginBottom"] ?? styles.marginVertical; 86 | widget = { ...widget, namedProp: "bottom" }; 87 | object.properties.push(widget); 88 | 89 | } 90 | 91 | } 92 | 93 | return object; 94 | }; 95 | -------------------------------------------------------------------------------- /src/utils/getPadding.tsx: -------------------------------------------------------------------------------- 1 | import { dartType } from "../config/layout-props"; 2 | 3 | 4 | 5 | export const getPadding = (styles: any, object: any) => { 6 | object.properties = []; 7 | 8 | if (styles.hasOwnProperty("padding")) { 9 | 10 | delete object.properties; 11 | } 12 | else { 13 | 14 | object.class = "EdgeInsets.only"; 15 | if (styles.hasOwnProperty("paddingLeft") || styles.hasOwnProperty("paddingHorizontal")) { 16 | 17 | let widget: any = dartType.double; 18 | widget.value = styles["paddingLeft"] ?? styles["paddingHorizontal"]; 19 | widget = { ...widget, namedProp: "left" }; 20 | object.properties.push(widget); 21 | 22 | } 23 | 24 | if (styles.hasOwnProperty("paddingRight")|| styles.hasOwnProperty("paddingHorizontal")) { 25 | 26 | let widget: any = dartType.double; 27 | widget.value = styles["paddingRight"]?? styles["paddingHorizontal"];; 28 | widget = { ...widget, namedProp: "right" }; 29 | object.properties.push(widget); 30 | 31 | } 32 | 33 | if (styles.hasOwnProperty("paddingTop") || styles.hasOwnProperty("paddingVertical")) { 34 | 35 | let widget: any = dartType.double; 36 | widget.value = styles["paddingTop"] ?? styles["paddingVertical"];; 37 | widget = { ...widget, namedProp: "top" }; 38 | object.properties.push(widget); 39 | 40 | } 41 | 42 | if (styles.hasOwnProperty("paddingBottom") || styles.hasOwnProperty("paddingVertical")) { 43 | 44 | let widget: any = dartType.double; 45 | widget.value = styles["paddingBottom"]?? styles["paddingVertical"]; 46 | widget = { ...widget, namedProp: "bottom" }; 47 | object.properties.push(widget); 48 | 49 | } 50 | 51 | } 52 | 53 | return object; 54 | }; 55 | -------------------------------------------------------------------------------- /src/utils/getPositioned.tsx: -------------------------------------------------------------------------------- 1 | import { flutterWidget } from "../config/flutter-widgets"; 2 | import { dartType } from "../config/layout-props"; 3 | 4 | 5 | 6 | export const getPositioned = (styles: any, object: any, ast?: any) => { 7 | 8 | object.properties = []; 9 | if (styles.hasOwnProperty("position")) { 10 | if (styles["position"] === "absolute") { 11 | console.log(object); 12 | console.log(ast); 13 | ast["namedProp"] = "child"; 14 | 15 | delete object.namedProp; 16 | 17 | if (styles.top) { 18 | let top: any = dartType.double; 19 | 20 | 21 | top = { ...top, "namedProp": "top", value: styles.top }; 22 | object.properties.push(top); 23 | 24 | } 25 | if (styles.bottom) { 26 | let bottom: any = dartType.double; 27 | bottom = { ...bottom, "namedProp": "bottom", value: styles.bottom }; 28 | object.properties.push(bottom); 29 | 30 | } 31 | 32 | if (styles.left) { 33 | let left: any = dartType.double; 34 | 35 | left = { ...left, "namedProp": "left", value: styles.left }; 36 | object.properties.push(left); 37 | 38 | } 39 | if (styles.right) { 40 | let right: any = dartType.double; 41 | 42 | 43 | right = { ...right, "namedProp": "right", value: styles.right }; 44 | object.properties.push(right); 45 | 46 | } 47 | object.properties.push(ast); 48 | let stack:any = {...flutterWidget.Stack} 49 | stack.properties = []; 50 | stack.properties.push({ namedProp: "children", type: "Array", values: [object] }) 51 | object = stack 52 | return { nested: true, object }; 53 | } 54 | } else { 55 | return object; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /src/utils/getTextAlign.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const getTextAlign = (styles: any, object: any) => { 4 | object.value = styles.textAlign; 5 | return object; 6 | }; 7 | -------------------------------------------------------------------------------- /src/utils/num.ts: -------------------------------------------------------------------------------- 1 | import ppo from "ppo"; 2 | import toNumber from "lodash/toNumber"; 3 | import isNumber from "lodash/isNumber"; 4 | 5 | const isMulti = (key:any) => { 6 | if (key.indexOf("|") > 0) return true; 7 | else return false; 8 | }; 9 | 10 | const findSimilarNumber = (n:any, rule:any) => { 11 | if (rule[n + ""]) return n; 12 | 13 | const nums = []; 14 | for (let key in rule) { 15 | nums.push(parseInt(key)); 16 | } 17 | nums.sort((n1, n2) => n2 - n1); 18 | 19 | for (let i = 0; i < nums.length; i++) { 20 | const num = nums[i]; 21 | if (n > num) return num; 22 | } 23 | 24 | return 0; 25 | }; 26 | 27 | const isNone = (val:any) => { 28 | if (!val) return true; 29 | 30 | if (typeof val === "string") { 31 | if (val.trim() === "") return true; 32 | if (val === "null") return true; 33 | if (val === "none") return true; 34 | if (val === "inhert") return true; 35 | } 36 | 37 | return false; 38 | }; 39 | 40 | const toNum = (val:any) => { 41 | if (isNumber(val)) return val; 42 | 43 | const r = /([-0-9.]+)[a-zA-Z%]/gi.exec(`${val}c`); 44 | if (r && r.length >= 2) { 45 | val = r[1]; 46 | val = isNumber(val) ? val : parseFloat(val); 47 | return val; 48 | } else { 49 | return toNumber(val); 50 | } 51 | }; 52 | 53 | const toRadian = (val:any, fl = 3) => { 54 | let radian = val.toString().replace(/deg$/g, ""); 55 | radian = (radian * Math.PI) / 180; 56 | return ppo.floor(radian, fl); 57 | }; 58 | 59 | const toRound = (val:any, n = 3) => { 60 | const d = Math.pow(10, n); 61 | const num = Math.round(val * d); 62 | return num / d; 63 | }; 64 | 65 | export { isMulti, isNone, toNum, findSimilarNumber, toRadian, toRound }; 66 | -------------------------------------------------------------------------------- /src/utils/pos.js: -------------------------------------------------------------------------------- 1 | import toCamel from "./camel"; 2 | 3 | const isPercentage = val => { 4 | if (val.indexOf("%") > 0) { 5 | return true; 6 | } 7 | return false; 8 | }; 9 | 10 | const isName = val => { 11 | const keynames = "left|center|bottom|top|right".split("|"); 12 | for (let i = 0; i < keynames.length; i++) { 13 | if (val.indexOf(keynames[i]) === 0) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | }; 19 | 20 | // 0% 50% -> leftCenter 21 | // center left -> centerLeft 22 | const toNameVal = val => { 23 | let result = ""; 24 | if (isPercentage(val)) { 25 | const arr = val.split(" "); 26 | for (let i = 0; i < arr.length; i++) { 27 | if (i === 0) { 28 | if (arr[i] === "0%") { 29 | result += "top"; 30 | } else if (arr[i] === "50%") { 31 | result += "center"; 32 | } else { 33 | result += "bottom"; 34 | } 35 | } else { 36 | if (arr[i] === "0%") { 37 | result += "-left"; 38 | } else if (arr[i] === "50%") { 39 | result += "-center"; 40 | } else { 41 | result += "-right"; 42 | } 43 | } 44 | } 45 | } else { 46 | result.replace(/\s/gi, "-"); 47 | } 48 | 49 | result = toCamel(result); 50 | result = result === "centerCenter" ? "center" : result; 51 | return result; 52 | }; 53 | 54 | export { isPercentage, isName, toNameVal }; 55 | -------------------------------------------------------------------------------- /src/utils/pushPropToWidget.tsx: -------------------------------------------------------------------------------- 1 | 2 | export function pushPropToWidget(ast: any, layoutWidget: any,widget:string) { 3 | 4 | if(layoutWidget.nested){ 5 | ast = layoutWidget.object; 6 | return ast; 7 | }else { 8 | if (ast.class === widget) { 9 | let index = ast.properties.findIndex((data: any) => (data.namedProp === layoutWidget.namedProp)); 10 | if (index < 0) { 11 | ast.properties.push(layoutWidget); 12 | } 13 | 14 | } else { 15 | searchWidgetAndPush(ast.properties); 16 | } 17 | } 18 | 19 | 20 | function searchWidgetAndPush(prop:any) { 21 | Object.entries(prop).forEach(([, v]: any) => { 22 | if (v.class === widget) { 23 | 24 | let index = v.properties.findIndex((data: any) => (data.namedProp === layoutWidget.namedProp)); 25 | if (index < 0) { 26 | v.properties.push(layoutWidget); 27 | } 28 | } else { 29 | if(v.hasOwnProperty("properties")){ 30 | searchWidgetAndPush(v.properties); 31 | } 32 | 33 | } 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/utils/str.js: -------------------------------------------------------------------------------- 1 | const addQuotes = str => { 2 | if (!/^("|')/gi.test(str)) { 3 | str = `"${str}"`; 4 | } 5 | return str; 6 | }; 7 | 8 | const getLast = str => { 9 | return str.charAt(str.length - 1); 10 | }; 11 | 12 | export { addQuotes, getLast }; 13 | -------------------------------------------------------------------------------- /src/utils/unit.ts: -------------------------------------------------------------------------------- 1 | const isNumerical = (val:string) => /^([0-9]+)$/gi.test(val.toString()) ; 2 | 3 | const isPercentage = (val:string) => /([0-9]+)%$/gi.test(val); 4 | 5 | const isPixel = (val:string) => /([0-9]+)(px|dpx)$/gi.test(val); 6 | 7 | const isEm = (val:string) => /([0-9]+)em$/gi.test(val); 8 | 9 | const isRem = (val:string) => /([0-9]+)rem$/gi.test(val); 10 | 11 | const isPt = (val:string) => /([0-9]+)pt$/gi.test(val); 12 | 13 | export { isNumerical, isPercentage, isPixel, isPt, isEm, isRem }; 14 | -------------------------------------------------------------------------------- /test/blah.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { Thing } from '../src'; 4 | 5 | describe('it', () => { 6 | it('renders without crashing', () => { 7 | const div = document.createElement('div'); 8 | ReactDOM.render(, div); 9 | ReactDOM.unmountComponentAtNode(div); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs 3 | "include": ["src", "types"], 4 | "compilerOptions": { 5 | "module": "esnext", 6 | "lib": ["dom", "esnext"], 7 | "importHelpers": true, 8 | // output .d.ts declaration files for consumers 9 | "declaration": true, 10 | // output .js.map sourcemap files for consumers 11 | "sourceMap": true, 12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index 13 | "rootDir": "./src", 14 | // stricter type-checking for stronger correctness. Recommended by TS 15 | "strict": true, 16 | // linter checks for common issues 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | // use Node's module resolution algorithm, instead of the legacy TS one 23 | "moduleResolution": "node", 24 | // transpile JSX to React.createElement 25 | "jsx": "react", 26 | // interop between ESM and CJS modules. Recommended by TS 27 | "esModuleInterop": true, 28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS 29 | "skipLibCheck": true, 30 | // error out if import and file system have a casing mismatch. Recommended by TS 31 | "forceConsistentCasingInFileNames": true, 32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` 33 | "noEmit": true, 34 | } 35 | } 36 | --------------------------------------------------------------------------------