├── .gitignore ├── README.md ├── moo-css-react ├── .babelrc ├── .prettierrc.js ├── README.md ├── __test__ │ ├── index.css │ ├── index.html │ ├── index.js │ ├── index.jsx │ ├── test2.json │ ├── virtualDom-2.json │ ├── virtualDom-3.json │ └── virtualDom.json ├── dist │ ├── handleJsx.js │ ├── handleVue.js │ ├── index.js │ ├── json2html.js │ └── utils │ │ └── handleImage.js ├── jest.config.js ├── package.json ├── src │ ├── handleJsx.ts │ ├── handleVue.ts │ ├── index.ts │ ├── json2html.ts │ └── types │ │ └── moo.d.ts └── tsconfig.json ├── moo-css-sketch ├── package.json └── tsconfig.json ├── moo-css-transformer ├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── README.md ├── build │ └── getMooDatas.js ├── config.js ├── index.js ├── jest.config.js ├── package.json ├── src │ ├── c2m.js │ ├── const.js │ ├── m2c.js │ ├── scaner.js │ └── utils.js ├── test │ ├── c2m.test.js │ └── m2c.test.js ├── types │ └── index.d.ts └── webpack.config.js ├── moo-css-weapp ├── package.json └── tsconfig.json ├── moo-css-web ├── .eslintignore ├── .gitignore ├── .prettierrc.js ├── dist │ ├── index.js │ ├── json2html.js │ ├── src │ │ ├── index.js │ │ └── json2html.js │ └── utils │ │ └── handleImage.js ├── package.json └── tsconfig.json └── vscode └── moo-css-plugin.dev.vsix /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | .DS_Store 4 | npm-debug.log 5 | lerna-debug.log 6 | npm-debug.log* 7 | lib/ 8 | es/ 9 | dist/ 10 | build/ 11 | coverage/ 12 | node_modules/ 13 | examples/test 14 | .eslintcache 15 | *.lock 16 | 17 | temp/ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moo-CSS plugins 2 | 3 | Style automatic development. 4 | 5 |

6 | Moo-CSS 7 |

8 | 9 | ## 1.[moo-css-transformer](./moo-css-transformer) 10 | 11 | MooCSS transform tool.mini name style <-> css style. Version: `0.1.0` 12 | 13 | Install: 14 | 15 | ``` sh 16 | npm i --save moo-css-transformer 17 | ``` 18 | 19 | 20 | 21 | for example: 22 | ``` 23 | f-tc <-> text-align: center 24 | ``` 25 | 26 | ## 2.[moo-css-base](https://github.com/MichealWayne/Moo-CSS/tree/master/moo-css-base) 27 | 28 | Moo-CSS base Layer demo, for less/sass/stylus. 29 | 30 | Install: 31 | 32 | ``` sh 33 | npm i --save moo-css-base 34 | ``` 35 | 36 | 37 | 38 | ## 3.[moo-css-sketch](./moo-css-sketch) 39 | 40 | analysis sketch file and get Moo-CSS's style sheet. 41 | 42 | ## 3.[moo-css-web](./moo-css-web) 43 | 44 | vritual dom data -> web files(HTML, CSS). 45 | 46 | ## 4.[moo-css-weapp](./moo-css-weapp) 47 | 48 | vritual dom data -> weapp files(wxml, wxss). 49 | 50 | ## 5.[moo-css-server](./moo-css-server) 51 | 52 | platform to handle sketch file. 53 | 54 | ## 6.[vscode](./vscode) 55 | 56 | ## 7.[moo-css-react](./moo-css-react) 57 | 58 | moo-css AST -> React component 59 | 60 | moo-css-base's vscode plugin. -------------------------------------------------------------------------------- /moo-css-react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "loose": true 7 | } 8 | ] 9 | ] 10 | } -------------------------------------------------------------------------------- /moo-css-react/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 100, 3 | tabWidth: 2, 4 | useTabs: false, 5 | singleQuote: true, 6 | semi: true, 7 | trailingComma: 'es5', 8 | bracketSpacing: true, 9 | arrowParens: 'avoid', 10 | }; 11 | -------------------------------------------------------------------------------- /moo-css-react/README.md: -------------------------------------------------------------------------------- 1 | # moo-css-react 2 | -------------------------------------------------------------------------------- /moo-css-react/__test__/index.css: -------------------------------------------------------------------------------- 1 | 2 | .g-pa { 3 | position:absolute 4 | } 5 | .g-t0 { 6 | top:0px 7 | } 8 | .g-l0 { 9 | left:0px 10 | } 11 | .u-w0 { 12 | width:0px 13 | } 14 | .u-h0 { 15 | height:0px 16 | } 17 | .u-bdw0 { 18 | border-width:0 19 | } 20 | .s-bgc_t { 21 | background-color:transparent 22 | } 23 | .u-w686 { 24 | width:686px 25 | } 26 | .u-h324 { 27 | height:324px 28 | } 29 | .f-ov_h { 30 | overflow:hidden 31 | } 32 | .s-bgc_ffffff { 33 | background-color:rgba(255,255,255,1) 34 | } 35 | .f-bdr16 { 36 | border-radius:16px 37 | } 38 | .u-w718 { 39 | width:718px 40 | } 41 | .u-h145 { 42 | height:145px 43 | } 44 | .z-o40 { 45 | opacity:0.4000000059604645 46 | } 47 | .g-t187 { 48 | top:187px 49 | } 50 | .g-l32 { 51 | left:32px 52 | } 53 | .u-w385 { 54 | width:385px 55 | } 56 | .u-h50 { 57 | height:50px 58 | } 59 | .s-cr_313131 { 60 | color:rgba(49,49,49,1) 61 | } 62 | .g-fs36 { 63 | font-size:36px 64 | } 65 | .f-ff_PM { 66 | font-family:PingFangSC-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif 67 | } 68 | .f-tl { 69 | text-align:left 70 | } 71 | .g-lh_n { 72 | line-height:normal 73 | } 74 | .g-t207 { 75 | top:207px 76 | } 77 | .g-l518 { 78 | left:518px 79 | } 80 | .u-w136 { 81 | width:136px 82 | } 83 | .u-h56 { 84 | height:56px 85 | } 86 | .s-bgc_fe5d4e { 87 | background-color:rgba(254,93,78,1) 88 | } 89 | .f-bdr8 { 90 | border-radius:8px 91 | } 92 | .g-t218 { 93 | top:218px 94 | } 95 | .g-l538 { 96 | left:538px 97 | } 98 | .u-w96 { 99 | width:96px 100 | } 101 | .u-h33 { 102 | height:33px 103 | } 104 | .s-cr_ffffff { 105 | color:rgba(255,255,255,1) 106 | } 107 | .g-fs24 { 108 | font-size:24px 109 | } 110 | .f-ff_PR { 111 | font-family:PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif 112 | } 113 | .g-pr { 114 | position:relative 115 | } 116 | .g-t24 { 117 | top:24px 118 | } 119 | .u-w209 { 120 | width:209px 121 | } 122 | .s-cr_364a7f { 123 | color:rgba(54,74,127,1) 124 | } 125 | .g-t39 { 126 | top:39px 127 | } 128 | .g-l641 { 129 | left:641px 130 | } 131 | .u-w13 { 132 | width:13px 133 | } 134 | .u-h22 { 135 | height:22px 136 | } 137 | .g-t81 { 138 | top:81px 139 | } 140 | .u-w78 { 141 | width:78px 142 | } 143 | .u-h37 { 144 | height:37px 145 | } 146 | .g-fs26 { 147 | font-size:26px 148 | } 149 | .g-l130 { 150 | left:130px 151 | } 152 | .u-w26 { 153 | width:26px 154 | } 155 | .s-cr_fe5d4e { 156 | color:rgba(254,93,78,1) 157 | } 158 | .g-l176 { 159 | left:176px 160 | } 161 | .u-w58 { 162 | width:58px 163 | } 164 | .g-l254 { 165 | left:254px 166 | } 167 | .u-w156 { 168 | width:156px 169 | } 170 | .g-l410 { 171 | left:410px 172 | } 173 | .u-w104 { 174 | width:104px 175 | } 176 | .g-t243 { 177 | top:243px 178 | } 179 | .u-w129 { 180 | width:129px 181 | } 182 | .u-h41 { 183 | height:41px 184 | } 185 | .g-fs34 { 186 | font-size:34px 187 | } 188 | .f-ff_DM { 189 | font-family:DIN-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif 190 | } 191 | .g-t249 { 192 | top:249px 193 | } 194 | .g-l178 { 195 | left:178px 196 | } 197 | .u-w120 { 198 | width:120px 199 | } 200 | .s-cr_999999 { 201 | color:rgba(153,153,153,1) 202 | } -------------------------------------------------------------------------------- /moo-css-react/__test__/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const testdata = require('./test2.json'); 4 | const test = require('../dist/'); 5 | 6 | let datas = test.default({ 7 | data: testdata, 8 | vueBool: true 9 | }); 10 | console.log(datas); 11 | fs.writeFileSync(path.join(__dirname, './index.jsx'), datas.jsx) 12 | fs.writeFileSync(path.join(__dirname, './index.css'), datas.css); -------------------------------------------------------------------------------- /moo-css-react/__test__/index.jsx: -------------------------------------------------------------------------------- 1 | 2 | import * as Vue from 'vue' 3 | import Component from 'vue-class-component' 4 | import './index.css' 5 | 6 | @Component({ 7 | props: {} 8 | }) 9 | export default class MyComponent extends Vue { 10 | render () { 11 | 12 | return ( 13 |
14 |
15 |
16 |
17 |

易方达沪深300RTF联接

18 |
19 |

立即购买

20 |
21 |
22 |

沪深300指数

23 |
24 |
25 |
26 |
27 |

性价比

28 |
29 |

30 |
31 |

88分

32 |
33 |

投资环境良好

34 |
35 |

值得买入

36 |
37 |
38 |

+34.12%

39 |
40 |

近一年涨幅

) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /moo-css-react/__test__/test2.json: -------------------------------------------------------------------------------- 1 | { 2 | "tagName": "body", 3 | "props": { 4 | "style": { 5 | "position": "absolute", 6 | "top": "0px", 7 | "left": "0px", 8 | "width": "0px", 9 | "height": "0px", 10 | "borderWidth": 0, 11 | "backgroundColor": "transparent" 12 | }, 13 | "children": [ 14 | { 15 | "tagName": "div", 16 | "props": { 17 | "style": { 18 | "position": "absolute", 19 | "top": "0px", 20 | "left": "0px", 21 | "width": "686px", 22 | "height": "324px", 23 | "borderWidth": 0, 24 | "backgroundColor": "transparent" 25 | }, 26 | "children": [ 27 | { 28 | "tagName": "div", 29 | "props": { 30 | "style": { 31 | "position": "absolute", 32 | "top": "0px", 33 | "left": "0px", 34 | "width": "686px", 35 | "height": "324px", 36 | "overflow": "hidden", 37 | "boxShadow": "0px 0px 10px 4px rgba(221,221,221,0.16)", 38 | "backgroundColor": "rgba(255,255,255,1)", 39 | "borderRadius": "16px" 40 | }, 41 | "children": [ 42 | { 43 | "tagName": "div", 44 | "props": { 45 | "style": { 46 | "position": "absolute", 47 | "top": "0px", 48 | "left": "0px", 49 | "width": "718px", 50 | "height": "145px", 51 | "opacity": 0.4000000059604645, 52 | "backgroundImage": "linear-gradient(213deg, rgba(219,225,243,1) 0%,rgba(181,192,234,1) 63.444924464826016%,rgba(139,155,215,1) 100%)", 53 | "borderRadius": "16px" 54 | }, 55 | "children": [] 56 | }, 57 | "id": "48F856A8-DDCF-45ED-9E15-32CBC9BFE734", 58 | "name": "矩形", 59 | "rect": { 60 | "x": 0.25, 61 | "y": 0, 62 | "width": 718.0810706886241, 63 | "height": 145 64 | } 65 | } 66 | ] 67 | }, 68 | "id": "1B3CA453-E627-47B8-AD7A-039074FF1736", 69 | "name": "蒙版", 70 | "rect": { 71 | "x": 0, 72 | "y": 0, 73 | "width": 686, 74 | "height": 324 75 | } 76 | } 77 | ] 78 | }, 79 | "id": "9F3F16A6-7FAD-43DB-94CF-05ADACE33783", 80 | "name": "矩形", 81 | "rect": { 82 | "x": 0, 83 | "y": 0, 84 | "width": 686, 85 | "height": 324, 86 | "mX": 343, 87 | "mY": 162, 88 | "x1": 686, 89 | "y1": 324 90 | } 91 | }, 92 | { 93 | "tagName": "p", 94 | "props": { 95 | "style": { 96 | "position": "absolute", 97 | "top": "187px", 98 | "left": "32px", 99 | "width": "385px", 100 | "height": "50px", 101 | "color": "rgba(49,49,49,1)", 102 | "fontSize": "36px", 103 | "fontFamily": "PingFangSC-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 104 | "textAlign": "left", 105 | "lineHeight": "normal", 106 | "whiteSpace": "nowrap" 107 | }, 108 | "text": "易方达沪深300RTF联接" 109 | }, 110 | "id": "2514F8C1-0511-4821-9A30-83931477359A", 111 | "name": "易方达沪深300RTF联接", 112 | "rect": { 113 | "x": 32, 114 | "y": 186.5, 115 | "width": 385, 116 | "height": 50, 117 | "mX": 224.5, 118 | "mY": 211.5, 119 | "x1": 417, 120 | "y1": 236.5 121 | } 122 | }, 123 | { 124 | "tagName": "div", 125 | "props": { 126 | "style": { 127 | "position": "absolute", 128 | "top": "207px", 129 | "left": "518px", 130 | "width": "136px", 131 | "height": "56px", 132 | "backgroundColor": "rgba(254,93,78,1)", 133 | "borderRadius": "8px" 134 | }, 135 | "children": [] 136 | }, 137 | "id": "18F57906-745F-4CDB-ABBE-BB98D0992F78", 138 | "name": "矩形", 139 | "rect": { 140 | "x": 517.5, 141 | "y": 206.5, 142 | "width": 136, 143 | "height": 56, 144 | "mX": 585.5, 145 | "mY": 234.5, 146 | "x1": 653.5, 147 | "y1": 262.5 148 | } 149 | }, 150 | { 151 | "tagName": "p", 152 | "props": { 153 | "style": { 154 | "position": "absolute", 155 | "top": "218px", 156 | "left": "538px", 157 | "width": "96px", 158 | "height": "33px", 159 | "color": "rgba(255,255,255,1)", 160 | "fontSize": "24px", 161 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 162 | "textAlign": "left", 163 | "lineHeight": "normal", 164 | "whiteSpace": "nowrap" 165 | }, 166 | "text": "立即购买" 167 | }, 168 | "id": "F808A800-86FB-4404-A042-08FB20ABDC2E", 169 | "name": "立即购买", 170 | "rect": { 171 | "x": 537.5, 172 | "y": 217.5, 173 | "width": 96, 174 | "height": 33, 175 | "mX": 585.5, 176 | "mY": 234, 177 | "x1": 633.5, 178 | "y1": 250.5 179 | } 180 | }, 181 | { 182 | "id": "-0A61-47F1-521BE4FDF", 183 | "name": "l-4沪深300指数l-5icon_list_forward", 184 | "direct": "y", 185 | "props": { 186 | "style": { 187 | "position": "relative" 188 | }, 189 | "children": [ 190 | { 191 | "id": "-1404C1E6F-0A61-47F1", 192 | "name": "l-1沪深300指数", 193 | "direct": "x", 194 | "props": { 195 | "style": { 196 | "position": "relative" 197 | }, 198 | "children": [ 199 | { 200 | "tagName": "p", 201 | "props": { 202 | "style": { 203 | "position": "absolute", 204 | "top": "24px", 205 | "left": "32px", 206 | "width": "209px", 207 | "height": "50px", 208 | "color": "rgba(54,74,127,1)", 209 | "fontSize": "36px", 210 | "fontFamily": "PingFangSC-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 211 | "textAlign": "left", 212 | "lineHeight": "normal", 213 | "whiteSpace": "nowrap" 214 | }, 215 | "text": "沪深300指数" 216 | }, 217 | "id": "404C1E6F-0A61-47F1-B7C3-709C624B93BE", 218 | "name": "沪深300指数", 219 | "rect": { 220 | "x": 32, 221 | "y": 24, 222 | "width": 209, 223 | "height": 50, 224 | "mX": 136.5, 225 | "mY": 49, 226 | "x1": 241, 227 | "y1": 74 228 | }, 229 | "leaf": true 230 | } 231 | ] 232 | }, 233 | "tagName": "div", 234 | "rect": { 235 | "x": 32, 236 | "y": 24, 237 | "x1": 241, 238 | "y1": 74, 239 | "mX": 136.5, 240 | "mY": 49, 241 | "width": 209, 242 | "height": 50 243 | }, 244 | "leafWrapper": true 245 | }, 246 | { 247 | "id": "-221BE4FDF-C8CE-4465", 248 | "name": "l-2icon_list_forward", 249 | "direct": "x", 250 | "props": { 251 | "style": { 252 | "position": "relative" 253 | }, 254 | "children": [ 255 | { 256 | "tagName": "div", 257 | "props": { 258 | "style": { 259 | "position": "absolute", 260 | "top": "39px", 261 | "left": "641px", 262 | "width": "13px", 263 | "height": "22px", 264 | "borderWidth": 0, 265 | "backgroundColor": "transparent" 266 | }, 267 | "children": null 268 | }, 269 | "id": "21BE4FDF-C8CE-4465-B0F3-1CF481CE974D", 270 | "name": "icon_list_forward", 271 | "rect": { 272 | "x": 641, 273 | "y": 39, 274 | "width": 13, 275 | "height": 22, 276 | "mX": 647.5, 277 | "mY": 50, 278 | "x1": 654, 279 | "y1": 61 280 | }, 281 | "leaf": true 282 | } 283 | ] 284 | }, 285 | "tagName": "div", 286 | "rect": { 287 | "x": 641, 288 | "y": 39, 289 | "x1": 654, 290 | "y1": 61, 291 | "mX": 647.5, 292 | "mY": 50, 293 | "width": 13, 294 | "height": 22 295 | }, 296 | "leafWrapper": true 297 | } 298 | ] 299 | }, 300 | "tagName": "div", 301 | "rect": { 302 | "x": 32, 303 | "y": 24, 304 | "x1": 654, 305 | "y1": 74, 306 | "mX": 343, 307 | "mY": 49, 308 | "width": 622, 309 | "height": 50 310 | } 311 | }, 312 | { 313 | "id": "A6E216F-DDDD-4FDAE5E7F1E8-7C3C-448F", 314 | "name": "l-3性价比投资环境良好高88分值得买入", 315 | "direct": "y", 316 | "props": { 317 | "style": { 318 | "position": "relative" 319 | }, 320 | "children": [ 321 | { 322 | "id": "-105895885-C3CA-442D", 323 | "name": "l-1性价比", 324 | "direct": "x", 325 | "props": { 326 | "style": { 327 | "position": "relative" 328 | }, 329 | "children": [ 330 | { 331 | "tagName": "p", 332 | "props": { 333 | "style": { 334 | "position": "absolute", 335 | "top": "81px", 336 | "left": "32px", 337 | "width": "78px", 338 | "height": "37px", 339 | "color": "rgba(54,74,127,1)", 340 | "fontSize": "26px", 341 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 342 | "textAlign": "left", 343 | "lineHeight": "normal", 344 | "whiteSpace": "nowrap" 345 | }, 346 | "text": "性价比" 347 | }, 348 | "id": "05895885-C3CA-442D-8CBA-AC64AF18BB11", 349 | "name": "性价比", 350 | "rect": { 351 | "x": 32, 352 | "y": 81.25, 353 | "width": 78, 354 | "height": 37, 355 | "mX": 71, 356 | "mY": 99.75, 357 | "x1": 110, 358 | "y1": 118.25 359 | }, 360 | "leaf": true 361 | } 362 | ] 363 | }, 364 | "tagName": "div", 365 | "rect": { 366 | "x": 32, 367 | "y": 81.25, 368 | "x1": 110, 369 | "y1": 118.25, 370 | "mX": 71, 371 | "mY": 99.75, 372 | "width": 78, 373 | "height": 37 374 | }, 375 | "leafWrapper": true 376 | }, 377 | { 378 | "id": "-33F4E49CB-5702-4B94", 379 | "name": "l-3高", 380 | "direct": "x", 381 | "props": { 382 | "style": { 383 | "position": "relative" 384 | }, 385 | "children": [ 386 | { 387 | "tagName": "p", 388 | "props": { 389 | "style": { 390 | "position": "absolute", 391 | "top": "81px", 392 | "left": "130px", 393 | "width": "26px", 394 | "height": "37px", 395 | "color": "rgba(254,93,78,1)", 396 | "fontSize": "26px", 397 | "fontFamily": "PingFangSC-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 398 | "textAlign": "left", 399 | "lineHeight": "normal", 400 | "whiteSpace": "nowrap" 401 | }, 402 | "text": "高" 403 | }, 404 | "id": "3F4E49CB-5702-4B94-878B-84A2AEB3F673", 405 | "name": "高", 406 | "rect": { 407 | "x": 130, 408 | "y": 81.25, 409 | "width": 26, 410 | "height": 37, 411 | "mX": 143, 412 | "mY": 99.75, 413 | "x1": 156, 414 | "y1": 118.25 415 | }, 416 | "leaf": true 417 | } 418 | ] 419 | }, 420 | "tagName": "div", 421 | "rect": { 422 | "x": 130, 423 | "y": 81.25, 424 | "x1": 156, 425 | "y1": 118.25, 426 | "mX": 143, 427 | "mY": 99.75, 428 | "width": 26, 429 | "height": 37 430 | }, 431 | "leafWrapper": true 432 | }, 433 | { 434 | "id": "-40A6E216F-DDDD-4FDA", 435 | "name": "l-488分", 436 | "direct": "x", 437 | "props": { 438 | "style": { 439 | "position": "relative" 440 | }, 441 | "children": [ 442 | { 443 | "tagName": "p", 444 | "props": { 445 | "style": { 446 | "position": "absolute", 447 | "top": "81px", 448 | "left": "176px", 449 | "width": "58px", 450 | "height": "37px", 451 | "color": "rgba(54,74,127,1)", 452 | "fontSize": "26px", 453 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 454 | "textAlign": "left", 455 | "lineHeight": "normal", 456 | "whiteSpace": "nowrap" 457 | }, 458 | "text": "88分" 459 | }, 460 | "id": "0A6E216F-DDDD-4FDA-8913-8F2B3BBAF023", 461 | "name": "88分", 462 | "rect": { 463 | "x": 176, 464 | "y": 81.25, 465 | "width": 58, 466 | "height": 37, 467 | "mX": 205, 468 | "mY": 99.75, 469 | "x1": 234, 470 | "y1": 118.25 471 | }, 472 | "leaf": true 473 | } 474 | ] 475 | }, 476 | "tagName": "div", 477 | "rect": { 478 | "x": 176, 479 | "y": 81.25, 480 | "x1": 234, 481 | "y1": 118.25, 482 | "mX": 205, 483 | "mY": 99.75, 484 | "width": 58, 485 | "height": 37 486 | }, 487 | "leafWrapper": true 488 | }, 489 | { 490 | "id": "-26E02EBA5-6260-4C46", 491 | "name": "l-2投资环境良好", 492 | "direct": "x", 493 | "props": { 494 | "style": { 495 | "position": "relative" 496 | }, 497 | "children": [ 498 | { 499 | "tagName": "p", 500 | "props": { 501 | "style": { 502 | "position": "absolute", 503 | "top": "81px", 504 | "left": "254px", 505 | "width": "156px", 506 | "height": "37px", 507 | "color": "rgba(54,74,127,1)", 508 | "fontSize": "26px", 509 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 510 | "textAlign": "left", 511 | "lineHeight": "normal", 512 | "whiteSpace": "nowrap" 513 | }, 514 | "text": "投资环境良好" 515 | }, 516 | "id": "6E02EBA5-6260-4C46-B07F-CA0C83DBF307", 517 | "name": "投资环境良好", 518 | "rect": { 519 | "x": 254, 520 | "y": 81.25, 521 | "width": 156, 522 | "height": 37, 523 | "mX": 332, 524 | "mY": 99.75, 525 | "x1": 410, 526 | "y1": 118.25 527 | }, 528 | "leaf": true 529 | } 530 | ] 531 | }, 532 | "tagName": "div", 533 | "rect": { 534 | "x": 254, 535 | "y": 81.25, 536 | "x1": 410, 537 | "y1": 118.25, 538 | "mX": 332, 539 | "mY": 99.75, 540 | "width": 156, 541 | "height": 37 542 | }, 543 | "leafWrapper": true 544 | }, 545 | { 546 | "id": "-5E5E7F1E8-7C3C-448F", 547 | "name": "l-5值得买入", 548 | "direct": "x", 549 | "props": { 550 | "style": { 551 | "position": "relative" 552 | }, 553 | "children": [ 554 | { 555 | "tagName": "p", 556 | "props": { 557 | "style": { 558 | "position": "absolute", 559 | "top": "81px", 560 | "left": "410px", 561 | "width": "104px", 562 | "height": "37px", 563 | "color": "rgba(54,74,127,1)", 564 | "fontSize": "26px", 565 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 566 | "textAlign": "left", 567 | "lineHeight": "normal", 568 | "whiteSpace": "nowrap" 569 | }, 570 | "text": "值得买入" 571 | }, 572 | "id": "E5E7F1E8-7C3C-448F-BFA0-828C1614CEBD", 573 | "name": "值得买入", 574 | "rect": { 575 | "x": 410, 576 | "y": 81.25, 577 | "width": 104, 578 | "height": 37, 579 | "mX": 462, 580 | "mY": 99.75, 581 | "x1": 514, 582 | "y1": 118.25 583 | }, 584 | "leaf": true 585 | } 586 | ] 587 | }, 588 | "tagName": "div", 589 | "rect": { 590 | "x": 410, 591 | "y": 81.25, 592 | "x1": 514, 593 | "y1": 118.25, 594 | "mX": 462, 595 | "mY": 99.75, 596 | "width": 104, 597 | "height": 37 598 | }, 599 | "leafWrapper": true 600 | } 601 | ] 602 | }, 603 | "tagName": "div", 604 | "rect": { 605 | "x": 32, 606 | "y": 81.25, 607 | "x1": 514, 608 | "y1": 118.25, 609 | "mX": 273, 610 | "mY": 99.75, 611 | "width": 482, 612 | "height": 37 613 | } 614 | }, 615 | { 616 | "id": "-3371-4935-284AE8842", 617 | "name": "l-1+34.12%l-2近一年涨幅", 618 | "direct": "y", 619 | "props": { 620 | "style": { 621 | "position": "relative" 622 | }, 623 | "children": [ 624 | { 625 | "id": "-190FD50B4-3371-4935", 626 | "name": "l-1+34.12%", 627 | "direct": "x", 628 | "props": { 629 | "style": { 630 | "position": "relative" 631 | }, 632 | "children": [ 633 | { 634 | "tagName": "p", 635 | "props": { 636 | "style": { 637 | "position": "absolute", 638 | "top": "243px", 639 | "left": "32px", 640 | "width": "129px", 641 | "height": "41px", 642 | "color": "rgba(254,93,78,1)", 643 | "fontSize": "34px", 644 | "fontFamily": "DIN-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 645 | "textAlign": "left", 646 | "lineHeight": "normal", 647 | "whiteSpace": "nowrap" 648 | }, 649 | "text": "+34.12%" 650 | }, 651 | "id": "90FD50B4-3371-4935-93B4-4D57A48FB558", 652 | "name": "+34.12%", 653 | "rect": { 654 | "x": 32, 655 | "y": 242.5, 656 | "width": 129, 657 | "height": 41, 658 | "mX": 96.5, 659 | "mY": 263, 660 | "x1": 161, 661 | "y1": 283.5 662 | }, 663 | "leaf": true 664 | } 665 | ] 666 | }, 667 | "tagName": "div", 668 | "rect": { 669 | "x": 32, 670 | "y": 242.5, 671 | "x1": 161, 672 | "y1": 283.5, 673 | "mX": 96.5, 674 | "mY": 263, 675 | "width": 129, 676 | "height": 41 677 | }, 678 | "leafWrapper": true 679 | }, 680 | { 681 | "id": "-284AE8842-3800-43B6", 682 | "name": "l-2近一年涨幅", 683 | "direct": "x", 684 | "props": { 685 | "style": { 686 | "position": "relative" 687 | }, 688 | "children": [ 689 | { 690 | "tagName": "p", 691 | "props": { 692 | "style": { 693 | "position": "absolute", 694 | "top": "249px", 695 | "left": "178px", 696 | "width": "120px", 697 | "height": "33px", 698 | "color": "rgba(153,153,153,1)", 699 | "fontSize": "24px", 700 | "fontFamily": "PingFangSC-Regular,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif", 701 | "textAlign": "left", 702 | "lineHeight": "normal", 703 | "whiteSpace": "nowrap" 704 | }, 705 | "text": "近一年涨幅" 706 | }, 707 | "id": "84AE8842-3800-43B6-B852-FAD8E51E8BF0", 708 | "name": "近一年涨幅", 709 | "rect": { 710 | "x": 178, 711 | "y": 248.5, 712 | "width": 120, 713 | "height": 33, 714 | "mX": 238, 715 | "mY": 265, 716 | "x1": 298, 717 | "y1": 281.5 718 | }, 719 | "leaf": true 720 | } 721 | ] 722 | }, 723 | "tagName": "div", 724 | "rect": { 725 | "x": 178, 726 | "y": 248.5, 727 | "x1": 298, 728 | "y1": 281.5, 729 | "mX": 238, 730 | "mY": 265, 731 | "width": 120, 732 | "height": 33 733 | }, 734 | "leafWrapper": true 735 | } 736 | ] 737 | }, 738 | "tagName": "div", 739 | "rect": { 740 | "x": 32, 741 | "y": 242.5, 742 | "x1": 298, 743 | "y1": 283.5, 744 | "mX": 165, 745 | "mY": 263, 746 | "width": 266, 747 | "height": 41 748 | } 749 | } 750 | ] 751 | }, 752 | "id": "12537FE2-C67F-4F0A-8776-8986DCCF2BD6", 753 | "name": "页面 1", 754 | "rect": { 755 | "x": 0, 756 | "y": 0, 757 | "width": 0, 758 | "height": 0 759 | } 760 | } -------------------------------------------------------------------------------- /moo-css-react/__test__/virtualDom.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | { 4 | "tagName": "body", 5 | "sketchInfo": { 6 | "type": "page" 7 | }, 8 | "props": { 9 | "style": "position:absolute;top:0px;left:0px;width:0px;height:0px;", 10 | "children": [ 11 | { 12 | "tagName": "div", 13 | "sketchInfo": { 14 | "type": "artboard" 15 | }, 16 | "props": { 17 | "style": "position:absolute;top:152px;left:257px;width:750px;height:1334px;", 18 | "children": [ 19 | { 20 | "tagName": "div", 21 | "sketchInfo": { 22 | "type": "symbolInstance" 23 | }, 24 | "props": { 25 | "style": "position:absolute;top:0px;left:0px;width:750px;height:128px;", 26 | "children": [] 27 | } 28 | }, 29 | { 30 | "tagName": "img", 31 | "sketchInfo": { 32 | "type": "bitmap" 33 | }, 34 | "props": { 35 | "style": "position:absolute;top:169px;left:121px;width:76px;height:93px;", 36 | "src": "images/9346ca49147854673f7e1ce3dfab9a09f848152b.png", 37 | "children": [] 38 | } 39 | }, 40 | { 41 | "tagName": "p", 42 | "sketchInfo": { 43 | "type": "text" 44 | }, 45 | "props": { 46 | "style": "position:absolute;top:369px;left:118px;width:64px;height:32px;color:rgba(84,84,84,1);font-size:32px;font-family:SourceHanSansCN-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;text-align:left;line-height:;", 47 | "children": [ 48 | "周报" 49 | ] 50 | } 51 | }, 52 | { 53 | "tagName": "p", 54 | "sketchInfo": { 55 | "type": "text" 56 | }, 57 | "props": { 58 | "style": "position:absolute;top:353px;left:316px;width:100px;height:50px;color:rgba(84,84,84,1);font-size:50px;font-family:SourceHanSansCN-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;text-align:left;line-height:;", 59 | "children": [ 60 | "周报" 61 | ] 62 | } 63 | }, 64 | { 65 | "tagName": "p", 66 | "sketchInfo": { 67 | "type": "text" 68 | }, 69 | "props": { 70 | "style": "position:absolute;top:341px;left:524px;width:128px;height:64px;color:rgba(84,84,84,1);font-size:64px;font-family:SourceHanSansCN-Medium,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;text-align:left;line-height:;", 71 | "children": [ 72 | "周报" 73 | ] 74 | } 75 | }, 76 | { 77 | "tagName": "div", 78 | "sketchInfo": { 79 | "type": "oval" 80 | }, 81 | "props": { 82 | "style": "position:absolute;top:474px;left:108px;width:102px;height:102px;border-color:rgba(151,151,151,1);border-width:1px;border-style:dash;", 83 | "children": [] 84 | } 85 | }, 86 | { 87 | "tagName": "div", 88 | "sketchInfo": { 89 | "type": "oval" 90 | }, 91 | "props": { 92 | "style": "position:absolute;top:807px;left:108px;width:102px;height:102px;border-color:rgba(151,151,151,1);border-width:1px;border-style:dash;", 93 | "children": [] 94 | } 95 | }, 96 | { 97 | "tagName": "div", 98 | "sketchInfo": { 99 | "type": "oval" 100 | }, 101 | "props": { 102 | "style": "position:absolute;top:1105px;left:108px;width:102px;height:102px;border-color:rgba(151,151,151,1);border-width:1px;border-style:dash;", 103 | "children": [] 104 | } 105 | }, 106 | { 107 | "tagName": "div", 108 | "sketchInfo": { 109 | "type": "oval" 110 | }, 111 | "props": { 112 | "style": "position:absolute;top:645px;left:108px;width:102px;height:102px;border-color:rgba(255,160,160,1);border-width:5px;border-style:dash;", 113 | "children": [] 114 | } 115 | }, 116 | { 117 | "tagName": "div", 118 | "sketchInfo": { 119 | "type": "rectangle" 120 | }, 121 | "props": { 122 | "style": "position:absolute;top:961px;left:0px;width:750px;height:373px;border-color:rgba(151,151,151,1);border-width:1px;border-style:dash;", 123 | "children": [] 124 | } 125 | }, 126 | { 127 | "tagName": "div", 128 | "sketchInfo": { 129 | "type": "star" 130 | }, 131 | "props": { 132 | "style": "position:absolute;top:474px;left:324px;width:102px;height:102px;border-color:rgba(151,151,151,1);border-width:1px;border-style:dash;", 133 | "children": [] 134 | } 135 | } 136 | ] 137 | } 138 | } 139 | ] 140 | } 141 | }, 142 | { 143 | "tagName": "div", 144 | "sketchInfo": {}, 145 | "props": { 146 | "style": "", 147 | "children": [] 148 | } 149 | } 150 | ] 151 | } -------------------------------------------------------------------------------- /moo-css-react/dist/handleJsx.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @utils handleJsx 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | function getReactComponent(renderStr, propsArr) { 7 | return ` 8 | import * as React from 'react' 9 | import './index.css' 10 | 11 | export default function Component (props) { 12 | ${propsArr && propsArr.length ? `let {${propsArr.join('')}} = props;` : ''} 13 | return (${renderStr.replace(/body/g, 'section').replace(/class=/g, 'className=')}) 14 | } 15 | `; 16 | } 17 | exports.getReactComponent = getReactComponent; 18 | -------------------------------------------------------------------------------- /moo-css-react/dist/handleVue.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @utils handleVue 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | function getVueComponent(renderStr, propsArr) { 7 | return ` 8 | import * as Vue from 'vue' 9 | import Component from 'vue-class-component' 10 | import './index.css' 11 | 12 | @Component({ 13 | props: {${propsArr && propsArr.length && propsArr.join(',') || ''}} 14 | }) 15 | export default class MyComponent extends Vue { 16 | render () { 17 | ${propsArr && propsArr.length ? `let {${propsArr.join('')}} = this;` : ''} 18 | return (${renderStr.replace(/body/g, 'section').replace(/class=/g, 'className=')}) 19 | } 20 | } 21 | `; 22 | } 23 | exports.getVueComponent = getVueComponent; 24 | -------------------------------------------------------------------------------- /moo-css-react/dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @namespace mvdom2web 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const json2html_1 = require("./json2html"); 7 | const handleJsx_1 = require("./handleJsx"); 8 | exports.getReactComponent = handleJsx_1.getReactComponent; 9 | const handleVue_1 = require("./handleVue"); 10 | exports.getVueComponent = handleVue_1.getVueComponent; 11 | const moo_css_transformer_1 = require("moo-css-transformer"); 12 | function humpToOther(value, symbol = '-') { 13 | return value.replace(/[A-Z]/g, (word) => { 14 | return `${symbol}${word.toLowerCase()}`; 15 | }); 16 | } 17 | function json2Arr(obj) { 18 | let arr = []; 19 | for (let i in obj) { 20 | arr.push(humpToOther(i) + ':' + obj[i]); 21 | } 22 | return arr; 23 | } 24 | function handleData(config) { 25 | let { data, handleImg, nostyle, viewport, vueBool, } = config; 26 | let cssTextObj = {}; 27 | const _style2MooSelector = (str) => { 28 | let _arr = str.split(':'); 29 | if (!_arr[1] || _arr[1] === 'undefined') 30 | return undefined; 31 | return moo_css_transformer_1.c2m.style2MooSelector(_arr[0], _arr[1]); 32 | }; 33 | const _handleStyleProps = (props) => { 34 | let styleList = json2Arr(props.style); 35 | let classList = []; 36 | if (!nostyle) { 37 | let newStyle = styleList.filter((item) => { 38 | if (viewport && ~item.indexOf('px')) { // mobile 39 | let arr = item.split(':'); 40 | item = `${arr[0]}:${(parseInt(arr[1]) / viewport * 100).toFixed(4)}vw`; 41 | } 42 | let moo = _style2MooSelector(item); 43 | if (moo) { 44 | classList.push(moo); 45 | if (!cssTextObj[moo]) 46 | cssTextObj[moo] = item; 47 | return false; 48 | } 49 | else if (moo !== undefined) { 50 | return item; 51 | } 52 | else 53 | return false; 54 | }).join(';'); 55 | props.style = newStyle; 56 | } 57 | else { 58 | let moduleClassList = []; 59 | styleList.forEach((item) => { 60 | if (viewport && ~item.indexOf('px')) { // mobile 61 | let arr = item.split(':'); 62 | item = `${arr[0]}:${(parseInt(arr[1]) / viewport * 100).toFixed(4)}vw`; 63 | } 64 | let moo = _style2MooSelector(item); 65 | if (moo) { 66 | classList.push(moo); 67 | if (!cssTextObj[moo]) 68 | cssTextObj[moo] = item; 69 | return false; 70 | } 71 | else if (moo !== undefined) { 72 | moduleClassList.push(item); 73 | return item; 74 | } 75 | else 76 | return false; 77 | }); 78 | if (moduleClassList.length) { 79 | props.className = 'm-' + ('' + Math.random()).slice(-6); 80 | cssTextObj[props.className] = moduleClassList.join(';'); 81 | } 82 | delete props.style; 83 | } 84 | if (classList.length) { 85 | let className = classList.join(' '); 86 | props.className = (props.className ? props.className + ' ' : '') + className; 87 | return className; 88 | } 89 | }; 90 | let propsList = []; 91 | let htmlTxt = json2html_1.default.build(data, { 92 | handleStyle: _handleStyleProps, 93 | handleImg, 94 | propsList, 95 | }); 96 | let cssTxt = ''; 97 | for (let selector in cssTextObj) { 98 | cssTxt += ` 99 | .${selector} { 100 | ${cssTextObj[selector]} 101 | }`; 102 | } 103 | return { 104 | jsx: vueBool ? handleVue_1.getVueComponent(htmlTxt, propsList) : handleJsx_1.getReactComponent(htmlTxt, propsList), 105 | css: cssTxt 106 | }; 107 | } 108 | exports.default = handleData; 109 | -------------------------------------------------------------------------------- /moo-css-react/dist/json2html.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @module json2html 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | class JSON2HTML { 7 | static get selfCloseTags() { 8 | return [ 9 | 'area', 'base', 'br', 'col', 'embed', 'hr', 10 | 'img', 'input', 'link', 'meta', 'param', 'source', 11 | 'track', 'wbr', 'command', 'keygen', 'menuitem', 12 | ]; 13 | } 14 | static build(json, handlers) { 15 | if (!json || !json.tagName) 16 | return ''; 17 | const props = JSON2HTMLBuilder.props(json, handlers); 18 | if (JSON2HTMLBuilder.isSelfCloseTag(json)) { 19 | return `<${json.tagName}${props}/>`; 20 | } 21 | const children = JSON2HTMLBuilder.children(json, handlers); 22 | return ` 23 | <${json.tagName}${props}>${children}`; 24 | } 25 | } 26 | exports.default = JSON2HTML; 27 | class JSON2HTMLBuilder { 28 | static props(json, handlers) { 29 | let props = json.props; 30 | if (!props) 31 | return ''; 32 | let html = ''; 33 | const { handleStyle, handleImg, } = handlers; 34 | if (props.style && handleStyle) { 35 | handleStyle(props); 36 | } 37 | if (props.src && handleImg && props.src.startsWith('data:image')) { 38 | handleImg(props); 39 | } 40 | const keys = Object.keys(props); 41 | for (const index in keys) { 42 | let key = keys[index]; 43 | if (key === 'children' || key === 'text') 44 | continue; 45 | else if (key === 'className') 46 | html += ` class="${props[key]}"`; 47 | else if ({}.hasOwnProperty.call(keys, index)) { 48 | if (props[key]) 49 | html += ` ${key}="${props[key]}"`; 50 | } 51 | } 52 | return html; 53 | } 54 | static children(json, handlers) { 55 | let children = json.props && json.props.children; 56 | if (!children) { 57 | let text = json.props.text; 58 | if (text && text.startsWith('{') && text.endsWith('}') && handlers && handlers.propsList) { 59 | handlers.propsList.push(text); 60 | } 61 | delete json.props.text; 62 | return text || ''; 63 | } 64 | let html = ''; 65 | for (const index in children) { 66 | if ({}.hasOwnProperty.call(children, index)) { 67 | if (typeof children[index] == 'object') { 68 | html += JSON2HTML.build(children[index], handlers); 69 | } 70 | else { 71 | html += children[index]; 72 | } 73 | } 74 | } 75 | return html; 76 | } 77 | static isSelfCloseTag(json) { 78 | return (JSON2HTML.selfCloseTags.indexOf(json.tag) > -1); 79 | } 80 | } 81 | exports.JSON2HTMLBuilder = JSON2HTMLBuilder; 82 | ; 83 | -------------------------------------------------------------------------------- /moo-css-react/dist/utils/handleImage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * handle image base64 4 | */ 5 | /* 6 | export default function handleImgBase64 (base64: string) { 7 | let base64Data = base64.replace(/^data:image\/\w+;base64,/, ''); 8 | let dataBuffer = new Buffer(base64Data, 'base64'); 9 | return dataBuffer; 10 | }*/ 11 | -------------------------------------------------------------------------------- /moo-css-react/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['__tests__'], 4 | testRegex: '__tests__/(.+)\\.test\\.(jsx?|tsx?)$', 5 | moduleFileExtensions: ['js', 'json', 'node'], 6 | }; 7 | -------------------------------------------------------------------------------- /moo-css-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moo-css-react", 3 | "version": "1.0.1", 4 | "author": "Wayne", 5 | "description": "mvdom data to jsx file.", 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "test": "node ./__test__/", 9 | "build": "tsc" 10 | }, 11 | "devDependencies": { 12 | "@types/node": "^13.13.12" 13 | }, 14 | "dependencies": { 15 | "moo-css-transformer": "^0.1.1" 16 | }, 17 | "keywords": [ 18 | "moo-css" 19 | ], 20 | "license": "ISC" 21 | } 22 | -------------------------------------------------------------------------------- /moo-css-react/src/handleJsx.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @utils handleReact 3 | * @author Wayne 4 | * @Date 2020-07-28 13:07:16 5 | * @LastEditTime 2023-04-25 10:36:12 6 | */ 7 | 8 | export function getReactComponent(renderStr: string, propsArr?: string[]): string { 9 | return ` 10 | import * as React from 'react' 11 | import './index.css' 12 | 13 | export default function Component (props) { 14 | ${propsArr?.length ? `let {${propsArr.join('')}} = props;` : ''} 15 | return (${renderStr.replace(/body/g, 'section').replace(/class=/g, 'className=')}) 16 | } 17 | `; 18 | } 19 | -------------------------------------------------------------------------------- /moo-css-react/src/handleVue.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @utils handleVue 3 | * @author Wayne 4 | * @Date 2020-07-30 13:58:02 5 | * @LastEditTime 2023-04-25 10:36:05 6 | */ 7 | 8 | export function getVueComponent(renderStr: string, propsArr?: string[]): string { 9 | return ` 10 | import * as Vue from 'vue' 11 | import Component from 'vue-class-component' 12 | import './index.css' 13 | 14 | @Component({ 15 | props: {${(propsArr?.length && propsArr.join(',')) || ''}} 16 | }) 17 | export default class MyComponent extends Vue { 18 | render () { 19 | ${propsArr?.length ? `let {${propsArr.join('')}} = this;` : ''} 20 | return (${renderStr.replace(/body/g, 'section').replace(/class=/g, 'className=')}) 21 | } 22 | } 23 | `; 24 | } 25 | -------------------------------------------------------------------------------- /moo-css-react/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace mvdom2web 3 | * @Date 2020-02-28 20:36:16 4 | * @LastEditTime 2023-04-25 10:39:38 5 | */ 6 | 7 | import JSON2HTML from './json2html'; 8 | import { getReactComponent } from './handleJsx'; 9 | import { getVueComponent } from './handleVue'; 10 | import { c2m } from 'moo-css-transformer'; 11 | 12 | function humpToOther(value: string, symbol: string = '-') { 13 | return value.replace(/[A-Z]/g, word => { 14 | return `${symbol}${word.toLowerCase()}`; 15 | }); 16 | } 17 | 18 | function json2Arr(obj: any) { 19 | const arr: string[] = []; 20 | for (const i in obj) { 21 | arr.push(humpToOther(i) + ':' + obj[i]); 22 | } 23 | return arr; 24 | } 25 | 26 | export { getVueComponent, getReactComponent }; 27 | 28 | /** 29 | * @function handleData 30 | * @description 处理样式数据 31 | * @param config 32 | * @returns 33 | */ 34 | export default function handleData(config: any) { 35 | const { data, handleImg, nostyle, viewport, vueBool } = config; 36 | const cssTextObj: any = {}; 37 | const _style2MooSelector = (str: string) => { 38 | const _arr = str.split(':'); 39 | if (!_arr[1] || _arr[1] === 'undefined') return undefined; 40 | return c2m.style2MooSelector(_arr[0], _arr[1]); 41 | }; 42 | 43 | const _handleStyleProps = (props: any) => { 44 | const styleList = json2Arr(props.style); 45 | const classList: any = []; 46 | 47 | if (!nostyle) { 48 | const newStyle = styleList 49 | .filter((item: any) => { 50 | if (viewport && ~item.indexOf('px')) { 51 | // mobile 52 | const arr = item.split(':'); 53 | 54 | item = `${arr[0]}:${((parseInt(arr[1]) / viewport) * 100).toFixed(4)}vw`; 55 | } 56 | const moo = _style2MooSelector(item); 57 | if (moo) { 58 | classList.push(moo); 59 | if (!cssTextObj[moo]) cssTextObj[moo] = item; 60 | return false; 61 | } else if (moo !== undefined) { 62 | return item; 63 | } else return false; 64 | }) 65 | .join(';'); 66 | props.style = newStyle; 67 | } else { 68 | const moduleClassList: string[] = []; 69 | styleList.forEach(item => { 70 | if (viewport && ~item.indexOf('px')) { 71 | // mobile 72 | const arr = item.split(':'); 73 | item = `${arr[0]}:${((parseInt(arr[1]) / viewport) * 100).toFixed(4)}vw`; 74 | } 75 | const moo = _style2MooSelector(item); 76 | if (moo) { 77 | classList.push(moo); 78 | 79 | if (!cssTextObj[moo]) cssTextObj[moo] = item; 80 | return false; 81 | } else if (moo !== undefined) { 82 | moduleClassList.push(item); 83 | return item; 84 | } else return false; 85 | }); 86 | if (moduleClassList.length) { 87 | props.className = 'm-' + ('' + Math.random()).slice(-6); 88 | cssTextObj[props.className] = moduleClassList.join(';'); 89 | } 90 | delete props.style; 91 | } 92 | 93 | if (classList.length) { 94 | const className = classList.join(' '); 95 | props.className = (props.className ? `${props.className} ` : '') + className; 96 | return className; 97 | } 98 | }; 99 | const propsList: any[] = []; 100 | const htmlTxt = JSON2HTML.build(data, { 101 | handleStyle: _handleStyleProps, 102 | handleImg, 103 | propsList, 104 | }); 105 | let cssTxt = ''; 106 | for (const selector in cssTextObj) { 107 | cssTxt += ` 108 | .${selector} { 109 | ${cssTextObj[selector]} 110 | }`; 111 | } 112 | return { 113 | jsx: vueBool ? getVueComponent(htmlTxt, propsList) : getReactComponent(htmlTxt, propsList), 114 | css: cssTxt, 115 | }; 116 | } 117 | -------------------------------------------------------------------------------- /moo-css-react/src/json2html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module json2html 3 | * @author Wayne 4 | * @Date 2020-02-28 20:36:16 5 | * @LastEditTime 2023-04-25 10:36:40 6 | */ 7 | 8 | export default class JSON2HTML { 9 | static get selfCloseTags() { 10 | return [ 11 | 'area', 12 | 'base', 13 | 'br', 14 | 'col', 15 | 'embed', 16 | 'hr', 17 | 'img', 18 | 'input', 19 | 'link', 20 | 'meta', 21 | 'param', 22 | 'source', 23 | 'track', 24 | 'wbr', 25 | 'command', 26 | 'keygen', 27 | 'menuitem', 28 | ]; 29 | } 30 | 31 | static build(json: any, handlers?: any) { 32 | if (!json || !json.tagName) return ''; 33 | const props = JSON2HTMLBuilder.props(json, handlers); 34 | if (JSON2HTMLBuilder.isSelfCloseTag(json)) { 35 | return `<${json.tagName}${props}/>`; 36 | } 37 | const children = JSON2HTMLBuilder.children(json, handlers); 38 | return ` 39 | <${json.tagName}${props}>${children}`; 40 | } 41 | } 42 | 43 | export class JSON2HTMLBuilder { 44 | static props(json: any, handlers: any) { 45 | let props = json.props; 46 | if (!props) return ''; 47 | let html = ''; 48 | const { handleStyle, handleImg } = handlers; 49 | 50 | if (props.style && handleStyle) { 51 | handleStyle(props); 52 | } 53 | if (props.src && handleImg && props.src.startsWith('data:image')) { 54 | handleImg(props); 55 | } 56 | 57 | const keys = Object.keys(props); 58 | // 属性处理 59 | for (const index in keys) { 60 | let key = keys[index]; 61 | if (key === 'children' || key === 'text') continue; 62 | else if (key === 'className') html += ` class="${props[key]}"`; 63 | else if ({}.hasOwnProperty.call(keys, index)) { 64 | if (props[key]) html += ` ${key}="${props[key]}"`; 65 | } 66 | } 67 | return html; 68 | } 69 | 70 | // 处理子元素 71 | static children(json: any, handlers?: any) { 72 | const children = json.props?.children; 73 | 74 | if (!children) { 75 | const text = json.props.text; 76 | if (text?.startsWith('{') && text.endsWith('}') && handlers && handlers.propsList) { 77 | handlers.propsList.push(text); 78 | } 79 | delete json.props.text; 80 | return text || ''; 81 | } 82 | let html = ''; 83 | for (const index in children) { 84 | if ({}.hasOwnProperty.call(children, index)) { 85 | if (typeof children[index] === 'object') { 86 | html += JSON2HTML.build(children[index], handlers); 87 | } else { 88 | html += children[index]; 89 | } 90 | } 91 | } 92 | return html; 93 | } 94 | 95 | static isSelfCloseTag(json: any) { 96 | return JSON2HTML.selfCloseTags.indexOf(json.tag) > -1; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /moo-css-react/src/types/moo.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Wayne 3 | * @Date 2020-02-24 20:13:10 4 | * @LastEditTime 2022-07-12 13:21:13 5 | */ 6 | 7 | // Type definitions for weapp 8 | declare module 'moo-css-transformer'; 9 | -------------------------------------------------------------------------------- /moo-css-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/"], 3 | "compilerOptions": { 4 | "outDir": "./dist/", 5 | "rootDir": "./src/", 6 | "sourceMap": false, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "module": "commonjs", 10 | "target": "es6", 11 | "allowJs": true, 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*": [ 15 | "src/*" 16 | ] 17 | }, 18 | "typeRoots": ["./src/types/"] 19 | } 20 | } -------------------------------------------------------------------------------- /moo-css-sketch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moo-css-sketch", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./dist/index.js", 6 | "dependencies": { 7 | "canvas": "^2.6.1", 8 | "jszip": "^3.2.2", 9 | "mime-types": "^2.1.26" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "Micheal Wang", 16 | "license": "ISC", 17 | "dependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /moo-css-sketch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "module": "commonjs", 8 | "target": "es5", 9 | "allowJs": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "@/*": [ 13 | "src/*" 14 | ] 15 | }, 16 | "typeRoots": ["./src/types/"], 17 | "rootDir": "./src/" 18 | } 19 | } -------------------------------------------------------------------------------- /moo-css-transformer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "loose": true 7 | } 8 | ] 9 | ] 10 | } -------------------------------------------------------------------------------- /moo-css-transformer/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/* 2 | src/js/lib/*.js 3 | lib/*.js 4 | test/*.js 5 | types/* -------------------------------------------------------------------------------- /moo-css-transformer/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es6: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | ], 10 | parserOptions: { 11 | sourceType: 'module', 12 | }, 13 | rules: { 14 | 'no-useless-escape': [0], 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /moo-css-transformer/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /yarn.lock 8 | # /package-lock.json 9 | /coverage 10 | 11 | # production 12 | /dist 13 | 14 | # datas 15 | /datas 16 | 17 | # misc 18 | .DS_Store 19 | 20 | # logs 21 | /*.log 22 | 23 | # vscode 24 | /.vscode 25 | 26 | # zip 27 | /*.zip 28 | -------------------------------------------------------------------------------- /moo-css-transformer/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 100, 3 | tabWidth: 2, 4 | useTabs: false, 5 | singleQuote: true, 6 | semi: true, 7 | trailingComma: 'es5', 8 | bracketSpacing: true, 9 | arrowParens: 'avoid', 10 | }; 11 | -------------------------------------------------------------------------------- /moo-css-transformer/README.md: -------------------------------------------------------------------------------- 1 | # moo-css-transformer 2 | 3 | 4 | 5 | MooCSS transform tool. 6 | 7 | 8 | 9 | ## Version 10 | 11 | 0.1.0 12 | 13 | 14 | 15 | ## Installation 16 | 17 | ``` sh 18 | npm install --save moo-css-transformer 19 | ``` 20 | 21 | or 22 | 23 | ``` sh 24 | yarn add moo-css-transformer 25 | ``` 26 | 27 | 28 | 29 | 30 | 31 | 32 | ## Use 33 | 34 | ``` js 35 | const { m2c, c2m, styleScaner } = require('moo-css-transformer'); 36 | console.log(m2c('g-mt20')); 37 | console.log(c2m('margin-top', '20px')); 38 | console.log(styleScaner('.d{color:red}.c{width: 50px}')); 39 | ``` 40 | 41 | ### API 42 | 43 | - m2c: MooCSS selector --> CSS values 44 | - c2m: CSS values --> MooCSS selector 45 | - styleScaner: CSS sheet --> CSS list 46 | 47 | 48 | 49 | #### c2m 50 | 51 | - params: 52 | - attribute: `{String}` css attribute; 53 | - value: `{String|Number} `css value.(if value is a number, it defaults to px, 70 -> 70px); 54 | - return: 55 | - `{String}`: if params can be moo-css selector, return selector string, else return false. 56 | 57 | for example: 58 | 59 | ``` js 60 | c2m('text-align', 'center'); // 'f-tc' 61 | c2m('line-height', '150%'); // 'g-lh150per' 62 | c2m('padding', '0 4% 50px'); // '' 63 | ``` 64 | 65 | 66 | 67 | #### m2c 68 | 69 | - params: 70 | - minName: `{String}` ,MooCSS selector, such as `u-w10` 71 | - lenUnit: `{String}`, css length unit`"vw"/"rem"/"px"`, default: `"vw"` 72 | - Viewport: `{Number}`, responsive mobile screen, default: `750` 73 | - return:`{Object}` 74 | - key: `{String}`, key name 75 | - attr: `{String}`, css style attribute 76 | - val: `{String | Number}`, css style value 77 | 78 | 79 | 80 | for example: 81 | 82 | ``` js 83 | m2c('g-mt10'); // key: 'g-mt10', attr: 'margin-top', val: '1.33333vw' 84 | m2c('u-w100', 'rem'); // key: 'u-w100', attr: 'width', val: '1.33333rem' 85 | m2c('u-w100', 'px'); // key: 'u-w100', attr: 'width', val: '100px' 86 | m2c('u-w100', 'rem', 500); // key: 'u-w100', attr: 'width', val: '2rem' 87 | ``` 88 | 89 | 90 | 91 | #### styleScaner 92 | 93 | - params: `{String}` css sheet 94 | - return: `{Array}` 95 | - item: `{String}` css style 96 | 97 | 98 | 99 | for example: 100 | 101 | ``` js 102 | styleScaner(` 103 | .test1 { 104 | color: red; 105 | line-height: 150%; 106 | } 107 | .test2 { 108 | width: 50px; 109 | height: 60px; 110 | line-height: 2; 111 | color: red; 112 | } 113 | `); // ['color:red', 'line-height:150%', 'width:50px', 'height:60px', 'line-height:2'] 114 | ``` 115 | 116 | 117 | 118 | 119 | 120 | ## Update 121 | 122 | 2022.05.14 -------------------------------------------------------------------------------- /moo-css-transformer/build/getMooDatas.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | /** 3 | * moo get moo-css.json (delete useless data)-> data.json 4 | * @author MichealWayne 5 | */ 6 | 7 | const fs = require('fs'); 8 | const { join } = require('path'); 9 | const http = require('http'); 10 | const utils = require('../src/utils'); 11 | 12 | function getMooList() { 13 | return new Promise((resolve, reject) => { 14 | http 15 | .get( 16 | { 17 | hostname: 'blog.michealwayne.cn', 18 | port: 80, 19 | path: '/fe-tools/datas/moo-css.json', 20 | agent: false, 21 | }, 22 | res => { 23 | let datas = ''; 24 | res.on('data', data => { 25 | datas += data; 26 | }); 27 | 28 | res.on('end', () => { 29 | resolve(JSON.parse(datas)); 30 | }); 31 | 32 | res.on('error', e => { 33 | reject(e); 34 | }); 35 | } 36 | ) 37 | .on('error', e => { 38 | reject(e); 39 | }); 40 | }); 41 | } 42 | 43 | const NUMBER_MAP = { 44 | NO_ZERO: 0, 45 | NO_TWO: 2, 46 | NO_LAST: -1, 47 | }; 48 | 49 | function handleStyleList(styleList) { 50 | const M2Cdata = {}; 51 | const C2Mdata = {}; 52 | 53 | utils.each(styleList, function (moduleitem) { 54 | const name = moduleitem.name || ''; 55 | const moduleName = name.split('-')[NUMBER_MAP.NO_ZERO].slice(NUMBER_MAP.NO_LAST); 56 | if (!M2Cdata[moduleName]) { 57 | M2Cdata[moduleName] = {}; 58 | } 59 | const _module = M2Cdata[moduleName]; 60 | 61 | const childrenList = moduleitem.children; 62 | utils.each(childrenList, function (item) { 63 | const css = item['属性']; 64 | 65 | if (!css.includes('、')) { 66 | const minName = utils.getStyleMinName(css); 67 | 68 | if (!_module[minName]) _module[minName] = css; 69 | else { 70 | _module[utils.getStyleMinName(css, true)] = css; 71 | } 72 | 73 | C2Mdata[css] = `${moduleName}-${minName}`; 74 | } else { 75 | css.split('、').map(_css => { 76 | const minName = utils.getStyleMinName(_css); 77 | 78 | if (!_module[minName]) { 79 | _module[minName] = _css; 80 | } else { 81 | _module[utils.getStyleMinName(_css, true)] = _css; 82 | } 83 | 84 | C2Mdata[_css] = `${moduleName}-${minName}`; 85 | return true; 86 | }); 87 | } 88 | }); 89 | }); 90 | 91 | fs.writeFile( 92 | join(__dirname, '../datas/m2c-data.json'), 93 | JSON.stringify(M2Cdata, null, NUMBER_MAP.NO_TWO), 94 | err => { 95 | if (err) { 96 | console.error(err); 97 | } else { 98 | console.log('m2c-data.json build success!'); 99 | } 100 | } 101 | ); 102 | fs.writeFile( 103 | join(__dirname, '../datas/c2m-data.json'), 104 | JSON.stringify(C2Mdata, null, NUMBER_MAP.NO_TWO), 105 | err => { 106 | if (err) { 107 | console.error(err); 108 | } else { 109 | console.log('c2m-data.json build success!'); 110 | } 111 | } 112 | ); 113 | } 114 | 115 | function handleList(data) { 116 | for (const i in data) { 117 | if (!utils.hasOwnProp(data, i)) continue; 118 | if (data[i].name === '样式模块词典') { 119 | handleStyleList(data[i].children); 120 | } 121 | } 122 | } 123 | 124 | getMooList().then(resultData => handleList(resultData)); 125 | -------------------------------------------------------------------------------- /moo-css-transformer/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @config 3 | * @author Wayne 4 | */ 5 | 6 | // semantiztion style name abbreviation 7 | const NAMEID_MAP = { 8 | background: 'bg', 9 | 'box-sizing': 'box', 10 | border: 'bd', 11 | overflow: 'ov', 12 | opacity: 'hide', 13 | flex: 'flex', 14 | transform: 'trans', 15 | 'text-align': 't', 16 | 'vertical-align': 'v', 17 | color: 'cr', 18 | }; 19 | 20 | // semantiztion style value abbreviation 21 | const VALUEID_MAP = { 22 | left: 'l', 23 | right: 'r', 24 | center: 'c', 25 | middle: 'm', 26 | top: 't', 27 | bottom: 'b', 28 | relative: 'r', 29 | absolute: 'a', 30 | fixed: 'f', 31 | }; 32 | 33 | // box css attribute 34 | const BOX_LIST = [ 35 | 'top', 36 | 'right', 37 | 'bottom', 38 | 'left', 39 | 'margin', 40 | 'margin-top', 41 | 'margin-right', 42 | 'margin-bottom', 43 | 'margin-left', 44 | 'padding', 45 | 'padding-top', 46 | 'padding-right', 47 | 'padding-bottom', 48 | 'padding-left', 49 | 'width', 50 | 'height', 51 | 'font-size', 52 | 'line-height', 53 | 'border-top', 54 | 'border-right', 55 | 'border-bottom', 56 | 'border-left', 57 | 'border-top-left-radius', 58 | 'border-top-right-radius', 59 | 'border-bottom-left-radius', 60 | 'border-bottom-right-radius', 61 | ]; 62 | 63 | // minify css attribute 64 | const MINI_LIST = ['position', 'text-align', 'float', 'vertical-align']; 65 | 66 | // minify css map 67 | const MINI_LIST_MAP = { 68 | position: { 69 | f: 'fixed', 70 | r: 'relative', 71 | a: 'absolute', 72 | s: 'static', 73 | sk: 'sticky', 74 | }, 75 | 'text-align': { 76 | c: 'center', 77 | l: 'left', 78 | r: 'right', 79 | j: 'justify', 80 | }, 81 | float: { 82 | c: 'center', 83 | l: 'left', 84 | r: 'right', 85 | }, 86 | 'vertical-align': { 87 | t: 'top', 88 | m: 'middle', 89 | b: 'bottom', 90 | }, 91 | }; 92 | 93 | module.exports = { 94 | NAMEID_MAP, 95 | VALUEID_MAP, 96 | BOX_LIST, 97 | MINI_LIST, 98 | MINI_LIST_MAP, 99 | }; 100 | -------------------------------------------------------------------------------- /moo-css-transformer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * moo-css-transformer 3 | * @author MichealWayne 4 | * @update 2020.02.20 5 | */ 6 | 7 | const c2m = require('./dist/c2m'); 8 | 9 | module.exports = { 10 | m2c: require('./dist/m2c').m2c, 11 | c2m: c2m.style2MooSelector, 12 | styleScaner: c2m.styleScaner, 13 | }; 14 | -------------------------------------------------------------------------------- /moo-css-transformer/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testRegex: 'test/(.+)\\.test\\.(jsx?|tsx?)$', 5 | moduleFileExtensions: ['js', 'jsx', 'json', 'node'], 6 | }; 7 | -------------------------------------------------------------------------------- /moo-css-transformer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moo-css-transformer", 3 | "version": "1.0.1", 4 | "description": "moo-css, css style transform function.", 5 | "main": "index.js", 6 | "types": "types/index.d.ts", 7 | "files": [ 8 | "dist/", 9 | "types/", 10 | "index.js" 11 | ], 12 | "scripts": { 13 | "test": "jest", 14 | "update:data": "node build/getMooDatas", 15 | "build": "webpack -p --env.config production --env.prod --config ./webpack.config.js" 16 | }, 17 | "keywords": [ 18 | "moo-css" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/MichealWayne/moo-css-transformer.git" 23 | }, 24 | "homepage": "https://github.com/MichealWayne/moo-css-transformer.git", 25 | "author": "MichealWayne", 26 | "license": "ISC", 27 | "devDependencies": { 28 | "@babel/cli": "^7.0.0-beta.40", 29 | "@babel/core": "^7.0.0-beta.40", 30 | "@babel/preset-env": "^7.13.15", 31 | "@babel/preset-stage-2": "^7.8.3", 32 | "babel-loader": "^8.0.0-beta.0", 33 | "webpack": "^4.28.1", 34 | "webpack-cli": "^3.2.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /moo-css-transformer/src/c2m.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-bitwise */ 2 | /** 3 | * @module c2m 4 | * @description css to moo 5 | * @author Wayne 6 | * @time 2020.02.19 7 | */ 8 | const utils = require('./utils'); 9 | const scaner = require('./scaner'); 10 | const C2Mdata = require('../datas/c2m-data.json'); 11 | const CONST = require('./const'); 12 | 13 | const MooValueHandler = { 14 | display(styleVal) { 15 | return `${styleVal === 'none' ? 'z-' : 'u-'}${ 16 | { 17 | 'inline-block': 'block_il', 18 | none: 'hide', 19 | }[styleVal] || styleVal 20 | }`; 21 | }, 22 | 23 | opacity(styleVal) { 24 | return `${~~(styleVal * CONST.ONE_HUNDRED)}`; 25 | }, 26 | 27 | 'font-family'(styleVal) { 28 | return styleVal && styleVal.split(',')[CONST.NO_ZERO]; 29 | }, 30 | 31 | 'box-size'() { 32 | return 'box-sizing'; 33 | }, 34 | 35 | 'line-height'(styleVal) { 36 | if (!Number.isNaN(+styleVal)) { 37 | return `${~~parseFloat(styleVal * CONST.ONE_HUNDRED)}%`; 38 | } else { 39 | return styleVal; 40 | } 41 | }, 42 | }; 43 | 44 | /** 45 | * @function style2MooSelector 46 | * @description style content -> moo-css selector 47 | * @param {string} stylename 48 | * @param {string} styleVal 49 | * @return {string | false} 50 | */ 51 | function style2MooSelector(stylename, _styleVal) { 52 | // handle display 53 | if (stylename === 'display') { 54 | return MooValueHandler.display(_styleVal); 55 | } 56 | let styleVal = _styleVal; 57 | // handle rgba color 58 | if (styleVal.startsWith('rgba') && styleVal.endsWith('1)')) { 59 | styleVal = styleVal.replace(/\s/g, '').replace('rgba', 'rgb').replace(',1)', ')'); 60 | } else if (MooValueHandler[stylename]) { 61 | styleVal = MooValueHandler[stylename](styleVal); 62 | } 63 | 64 | const name = C2Mdata[stylename]; 65 | const value = utils.getStyleValue(styleVal); 66 | 67 | return name && value ? name + value : ''; 68 | } 69 | 70 | module.exports = { 71 | style2MooSelector, 72 | styleScaner: scaner, 73 | }; 74 | -------------------------------------------------------------------------------- /moo-css-transformer/src/const.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @constants 3 | * @author Wayne 4 | * @time 2020.02.19 5 | */ 6 | 7 | const NO_ZERO = 0; 8 | const NO_ONE = 1; 9 | const NO_LAST = -1; 10 | const ONE_HUNDRED = 100; 11 | const DEFAULT_SCREEN_SIZE = 750; 12 | const HEX_LENGTH = 6; 13 | 14 | module.exports = { 15 | NO_ZERO, 16 | NO_ONE, 17 | NO_LAST, 18 | ONE_HUNDRED, 19 | DEFAULT_SCREEN_SIZE, 20 | HEX_LENGTH, 21 | }; 22 | -------------------------------------------------------------------------------- /moo-css-transformer/src/m2c.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module m2c 3 | * @description moo to css 4 | * @author Wayne 5 | * @time 2020.02.19 6 | */ 7 | const utils = require('./utils'); 8 | const M2Cdata = require('../datas/m2c-data.json'); 9 | const CONST = require('./const'); 10 | const { BOX_LIST, MINI_LIST, MINI_LIST_MAP } = require('../config'); 11 | 12 | function _getBasicCSS(moduleName, minname) { 13 | let cssAttr = ''; 14 | let cssVal = ''; 15 | const tagMap = M2Cdata[moduleName]; 16 | 17 | if (tagMap) { 18 | for (const key in tagMap) { 19 | if (!utils.hasOwnProp(tagMap, key)) continue; 20 | const _tag = `${moduleName}-${key}`; 21 | 22 | if ( 23 | minname.includes(_tag) && 24 | (minname[_tag.length] === '_' || 25 | +minname[_tag.length] || 26 | _tag.length >= minname.length - CONST.NO_ONE) 27 | ) { 28 | cssAttr = tagMap[key]; 29 | cssVal = minname.replace(_tag, ''); 30 | break; 31 | } 32 | } 33 | } 34 | return { 35 | cssAttr, 36 | cssVal, 37 | }; 38 | } 39 | 40 | /** 41 | * @function m2c 42 | * @param {String} minname 43 | * @param {String} lenUnit 44 | * @param {Number} viewport 45 | * @returns 46 | */ 47 | // eslint-disable-next-line complexity 48 | function m2c(minname, lenUnit = 'vw', viewport = CONST.DEFAULT_SCREEN_SIZE) { 49 | let cssAttr = ''; 50 | let cssVal = ''; 51 | if (minname.includes('-')) { 52 | const moduleName = minname.split('-')[CONST.NO_ZERO]; 53 | 54 | const basicCSS = _getBasicCSS(moduleName, minname); 55 | cssAttr = basicCSS.cssAttr; 56 | cssVal = basicCSS.cssVal; 57 | 58 | if (BOX_LIST.find(item => cssAttr.includes(item))) { 59 | // handle size 60 | const _val = cssVal.match(/\d+/g); 61 | 62 | if (cssVal.endsWith('per')) { 63 | cssVal = `${parseInt(cssVal, 10)}%`; 64 | } else if (lenUnit !== 'px') { 65 | let _valNum = String(utils.SizeUnit[`px2${lenUnit}`](_val[CONST.NO_ZERO], viewport)); 66 | const _index = _valNum.indexOf('.'); 67 | if (_index > -1) { 68 | _valNum = _valNum.slice(0, _index + 6); 69 | } 70 | cssVal = _val ? _valNum + lenUnit : ''; 71 | } else { 72 | cssVal += lenUnit; 73 | } 74 | } else if (MINI_LIST.includes(cssAttr)) { 75 | cssVal = MINI_LIST_MAP[cssAttr][cssVal] || cssVal; 76 | } else if (cssAttr.includes('color')) { 77 | // handle colors 78 | cssVal = `#${cssVal.slice(CONST.NO_ONE)}`; 79 | } else if (moduleName === 'f' && cssVal.startsWith('_r')) { 80 | // handle rotate 81 | cssVal = `rotate(${parseInt(cssVal.replace('_r', ''), 10)}deg)`; 82 | } else if (cssVal.startsWith('_')) { 83 | cssVal = cssVal.slice(CONST.NO_ONE); 84 | } 85 | //} 86 | } 87 | return { 88 | key: minname, 89 | attr: cssAttr, 90 | val: cssVal, 91 | }; 92 | } 93 | 94 | module.exports = { 95 | m2c, 96 | }; 97 | -------------------------------------------------------------------------------- /moo-css-transformer/src/scaner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DFS css style scaner 3 | */ 4 | 5 | const TAG_STATUS_MAP = { 6 | OUTTER: 0, 7 | INNER: 1, 8 | }; 9 | 10 | /** 11 | * @function scanner 12 | * @description css string scanner 13 | * @param {string} cssStr 14 | * @returns {Array} 15 | */ 16 | function scaner(cssStr) { 17 | cssStr = String(cssStr); 18 | if (!cssStr || !cssStr.includes('{')) { 19 | return false; 20 | } 21 | cssStr = cssStr.replace(/[\r\n\t]/g, '').replace(/\:\s/g, ':'); 22 | // 0: out of tag; 1: in css selector 23 | let tagStatus = TAG_STATUS_MAP.OUTTER; 24 | let _styleStr = ''; 25 | const styleSet = new Set(); 26 | for (let i = 0, len = cssStr.length; i < len; i++) { 27 | const _str = cssStr[i]; 28 | if (tagStatus) { 29 | if (_str !== '}') { 30 | if (_str !== ';') { 31 | _styleStr += _str; 32 | } else { 33 | styleSet.add(_styleStr.trim()); 34 | _styleStr = ''; 35 | } 36 | } else { 37 | // close 38 | if (_styleStr) { 39 | _styleStr = _styleStr.trim(); 40 | _styleStr && styleSet.add(_styleStr); 41 | _styleStr = ''; 42 | } 43 | tagStatus = TAG_STATUS_MAP.OUTTER; 44 | continue; 45 | } 46 | } else { 47 | if (_str !== '{') continue; 48 | else { 49 | tagStatus = TAG_STATUS_MAP.INNER; 50 | } 51 | } 52 | } 53 | 54 | return Array.from(styleSet); 55 | } 56 | 57 | module.exports = scaner; 58 | -------------------------------------------------------------------------------- /moo-css-transformer/src/utils.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | /** 3 | * @module utils 4 | * @author Wayne 5 | * @time 2020.02.19 6 | */ 7 | 8 | const CONST = require('./const'); 9 | const { NAMEID_MAP, VALUEID_MAP } = require('../config'); 10 | 11 | /** 12 | * @function type 13 | * @description get value type 14 | * @param {any} val 15 | * @return {string} 16 | */ 17 | function type(val) { 18 | return Object.prototype.toString.call(val).replace(/\[object\s|\]/g, ''); 19 | } 20 | 21 | /** 22 | * @function hasOwnProp 23 | * @param {Object} obj 24 | * @param {string} key 25 | * @returns 26 | */ 27 | function hasOwnProp(obj, key) { 28 | return Object.prototype.hasOwnProperty.call(obj, key); 29 | } 30 | 31 | /** 32 | * @function each 33 | * @description traverse array 34 | * @param {array} array 35 | * @param {Function} fn 36 | */ 37 | function each(array, fn) { 38 | for (let i = 0, len = array.length; i < len; i++) { 39 | fn(array[i], i); 40 | } 41 | } 42 | 43 | /** 44 | * @function getStrnumInt 45 | * @param {string} str 46 | * @param {number} multiple 47 | */ 48 | function getStrnumInt(str, multiple = 1) { 49 | // eslint-disable-next-line no-bitwise 50 | return ~~(parseFloat(str) * multiple); 51 | } 52 | 53 | /** 54 | * grb转16进制 55 | * @param {string[]} rgb 56 | * @return {number} 57 | */ 58 | function rgbToHex(rgb) { 59 | return rgb 60 | .map(value => { 61 | const _value = Number(value); 62 | return `${_value < 15 ? '0' : ''}${_value.toString(16)}`; 63 | }) 64 | .join(''); 65 | } 66 | 67 | function _getNameId(name) { 68 | return NAMEID_MAP[name] || name.charAt(CONST.NO_ZERO); 69 | } 70 | /** 71 | * get style name abbreviation 72 | * @param {string} name 73 | * @param {boolean} extendbool 74 | * @return {string} 75 | */ 76 | function getStyleMinName(name, extendbool) { 77 | if (NAMEID_MAP[name]) { 78 | return NAMEID_MAP[name]; 79 | } else if (name.includes('-')) { 80 | const nameArr = name.split('-'); 81 | return ( 82 | _getNameId(nameArr[CONST.NO_ZERO]) + 83 | (extendbool ? name.slice(CONST.NO_LAST) : '') + 84 | nameArr 85 | .slice(1) 86 | .map(letter => letter.charAt(CONST.NO_ZERO)) 87 | .join('') 88 | ); 89 | } else { 90 | return _getNameId(name) + (extendbool ? name.slice(CONST.NO_LAST) : ''); 91 | } 92 | } 93 | 94 | /** 95 | * @Object SizeUnit 96 | * @description 长度单位计算集合 97 | */ 98 | const SizeUnit = { 99 | vw2px(val, viewport) { 100 | return getStrnumInt(val, viewport / 100); 101 | }, 102 | rem2px(val, viewport) { 103 | return getStrnumInt(val, viewport / 10); 104 | }, 105 | px2rem(val, viewport) { 106 | return val / (viewport / 10); 107 | }, 108 | px2vw(val, viewport) { 109 | return val / (viewport / 100); 110 | }, 111 | 112 | handleSize(styleval, viewport) { 113 | const _unit = styleval.slice(-3).replace(/\d/, ''); 114 | if (_unit === 'px') { 115 | return styleval.replace('px', ''); 116 | } 117 | if (SizeUnit[`${_unit}2px`]) { 118 | return SizeUnit[`${_unit}2px`](styleval, viewport); 119 | } 120 | if (styleval.includes('.')) { 121 | return ''; 122 | } 123 | return styleval.replace('%', 'per'); 124 | }, 125 | }; 126 | 127 | /** 128 | * get style value abbreviation 129 | * @param {string|number} styleval 130 | * @param {number} viewport 131 | * @return {string} 132 | * @todo box-shadow,animation,transition,transform... 133 | */ 134 | function getStyleValue(_styleVal = '', viewport = CONST.DEFAULT_SCREEN_SIZE) { 135 | const styleval = _styleVal.trim(); 136 | if (!styleval || (styleval.includes(' ') && !styleval.startsWith('rgb('))) { 137 | return ''; 138 | } 139 | 140 | if (VALUEID_MAP[styleval]) { 141 | return VALUEID_MAP[styleval]; 142 | } 143 | 144 | if (styleval[CONST.NO_ZERO].match(/\d/) || styleval[CONST.NO_ZERO] === '.') { 145 | // number value 146 | return SizeUnit.handleSize(styleval, viewport); 147 | } else if (styleval.startsWith('#')) { 148 | // hex color 149 | return `_${styleval.replace('#', '')}`; 150 | } else if (styleval.startsWith('rgb(')) { 151 | // rgb color 152 | return `_${rgbToHex(styleval.replace(/[^\d|\,]/g, '').split(','))}`; 153 | } else if (styleval.startsWith('rotate(')) { 154 | // rotate 155 | return `_r${parseInt(styleval.replace('rotate(', ''), 10)}`; 156 | } else { 157 | return `_${getStyleMinName(styleval)}`; 158 | } 159 | } 160 | 161 | module.exports = { 162 | type, 163 | each, 164 | getStyleMinName, 165 | getStyleValue, 166 | getStrnumInt, 167 | SizeUnit, 168 | hasOwnProp, 169 | }; 170 | -------------------------------------------------------------------------------- /moo-css-transformer/test/c2m.test.js: -------------------------------------------------------------------------------- 1 | const c2m = require('../src/c2m'); 2 | const { style2MooSelector, styleScaner } = c2m; 3 | 4 | /** 5 | * dom 6 | */ 7 | describe('c2m font test', () => { 8 | it('text test', () => { 9 | // text 10 | expect(style2MooSelector('font-size', '20px')).toBe('g-fs20'); 11 | expect(style2MooSelector('font-size', '0.333rem')).toBe('g-fs24'); 12 | expect(style2MooSelector('font-size', '2vw')).toBe('g-fs15'); 13 | 14 | // color 15 | expect(style2MooSelector('color', '#fff')).toBe('s-cr_fff'); 16 | expect(style2MooSelector('color', 'rgb(255, 30, 0)')).toBe('s-cr_ff1e00'); 17 | 18 | // text-align 19 | expect(style2MooSelector('text-align', 'center')).toBe('f-tc'); 20 | expect(style2MooSelector('text-align', 'left')).toBe('f-tl'); 21 | expect(style2MooSelector('text-align', 'right')).toBe('f-tr'); 22 | 23 | expect(style2MooSelector('vertical-align', 'middle')).toBe('f-vm'); 24 | expect(style2MooSelector('vertical-align', 'top')).toBe('f-vt'); 25 | expect(style2MooSelector('vertical-align', 'bottom')).toBe('f-vb'); 26 | 27 | // line-height 28 | expect(style2MooSelector('line-height', '1.5')).toBe('g-lh150per'); 29 | expect(style2MooSelector('line-height', '40px')).toBe('g-lh40'); 30 | expect(style2MooSelector('line-height', '150%')).toBe('g-lh150per'); 31 | 32 | // text-shadow 33 | }); 34 | 35 | it('shape test', () => { 36 | expect(style2MooSelector('width', '300px')).toBe('u-w300'); 37 | expect(style2MooSelector('width', '3rem')).toBe('u-w225'); 38 | expect(style2MooSelector('width', '3vw')).toBe('u-w22'); 39 | expect(style2MooSelector('height', '200px')).toBe('u-h200'); 40 | expect(style2MooSelector('height', '1rem')).toBe('u-h75'); 41 | expect(style2MooSelector('height', '5.5vw')).toBe('u-h41'); 42 | expect(style2MooSelector('border-radius', '5px')).toBe('f-bdr5'); 43 | }); 44 | 45 | it('grid test', () => { 46 | expect(style2MooSelector('margin-top', '30px')).toBe('g-mt30'); 47 | expect(style2MooSelector('margin-left', '20px')).toBe('g-ml20'); 48 | expect(style2MooSelector('margin-bottom', '10px')).toBe('g-mb10'); 49 | expect(style2MooSelector('margin-right', '5px')).toBe('g-mr5'); 50 | expect(style2MooSelector('padding-top', '30px')).toBe('u-pt30'); 51 | expect(style2MooSelector('padding-left', '20px')).toBe('u-pl20'); 52 | expect(style2MooSelector('padding-bottom', '10px')).toBe('u-pb10'); 53 | expect(style2MooSelector('padding-right', '5px')).toBe('u-pr5'); 54 | 55 | expect(style2MooSelector('top', '30px')).toBe('g-t30'); 56 | expect(style2MooSelector('left', '20px')).toBe('g-l20'); 57 | expect(style2MooSelector('bottom', '10px')).toBe('g-b10'); 58 | expect(style2MooSelector('right', '5px')).toBe('g-r5'); 59 | 60 | expect(style2MooSelector('position', 'relative')).toBe('g-pr'); 61 | expect(style2MooSelector('position', 'absolute')).toBe('g-pa'); 62 | expect(style2MooSelector('position', 'fixed')).toBe('g-pf'); 63 | }); 64 | 65 | it('scanner test', () => { 66 | expect( 67 | styleScaner(` 68 | body{ 69 | padding: 0 4% 50px; 70 | color: #333; 71 | font-size: 13px; 72 | line-height: 1.5; 73 | }`)[0] 74 | ).toBe('padding:0 4% 50px'); 75 | 76 | expect( 77 | styleScaner(` 78 | table th, table td{border: solid 1px #d8d8d8;} 79 | table tbody tr td:first-child{text-align: center;}`)[0] 80 | ).toBe('border:solid 1px #d8d8d8'); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /moo-css-transformer/test/m2c.test.js: -------------------------------------------------------------------------------- 1 | const { m2c } = require('../dist/m2c'); 2 | 3 | /** 4 | * m2c test 5 | */ 6 | describe('m2c keys test', () => { 7 | it('size attribute analyse test', () => { 8 | expect(m2c('g-m10').attr).toBe('margin'); 9 | expect(m2c('g-mt10').attr).toBe('margin-top'); 10 | expect(m2c('g-ml10').attr).toBe('margin-left'); 11 | expect(m2c('g-mr10').attr).toBe('margin-right'); 12 | expect(m2c('g-mb10').attr).toBe('margin-bottom'); 13 | expect(m2c('g-t10').attr).toBe('top'); 14 | expect(m2c('g-l10').attr).toBe('left'); 15 | expect(m2c('g-r10').attr).toBe('right'); 16 | expect(m2c('g-b10').attr).toBe('bottom'); 17 | expect(m2c('g-lh10').attr).toBe('line-height'); 18 | expect(m2c('u-h100').attr).toBe('height'); 19 | expect(m2c('u-mh100').attr).toBe('max-height'); 20 | expect(m2c('u-mth100').attr).toBe('min-height'); 21 | expect(m2c('u-w100').attr).toBe('width'); 22 | expect(m2c('u-mw100').attr).toBe('max-width'); 23 | expect(m2c('u-mhw100').attr).toBe('min-width'); 24 | expect(m2c('u-p10').attr).toBe('padding'); 25 | expect(m2c('u-pl10').attr).toBe('padding-left'); 26 | expect(m2c('u-pr10').attr).toBe('padding-right'); 27 | expect(m2c('u-pb10').attr).toBe('padding-bottom'); 28 | expect(m2c('u-pt10').attr).toBe('padding-top'); 29 | 30 | expect(m2c('u-bdbw100').attr).toBe('border-bottom-width'); 31 | expect(m2c('u-bdiw100').attr).toBe('border-image-width'); 32 | expect(m2c('u-bdlw100').attr).toBe('border-left-width'); 33 | expect(m2c('u-bdrw100').attr).toBe('border-right-width'); 34 | expect(m2c('u-bdtw100').attr).toBe('border-top-width'); 35 | expect(m2c('u-bdtw100').attr).toBe('border-top-width'); 36 | expect(m2c('u-bdw100').attr).toBe('border-width'); 37 | expect(m2c('u-ow100').attr).toBe('outline-width'); 38 | }); 39 | 40 | it('color attribute analyse test', () => { 41 | expect(m2c('s-cr_f00').attr).toBe('color'); 42 | expect(m2c('s-oc_f00').attr).toBe('outline-color'); 43 | expect(m2c('s-bdtc_f00').attr).toBe('border-top-color'); 44 | expect(m2c('s-bdrc_f00').attr).toBe('border-right-color'); 45 | expect(m2c('s-bdlc_f00').attr).toBe('border-left-color'); 46 | expect(m2c('s-bdbc_f00').attr).toBe('border-bottom-color'); 47 | expect(m2c('s-bgc_f00').attr).toBe('background-color'); 48 | }); 49 | 50 | it('transform attribute analyse test', () => { 51 | expect(m2c('f-trans_r90').attr).toBe('transform'); 52 | }); 53 | 54 | it('simple attribute analyse test', () => { 55 | expect(m2c('g-box_border-box').attr).toBe('box-sizing'); 56 | expect(m2c('g-pr').attr).toBe('position'); 57 | expect(m2c('g-pf').attr).toBe('position'); 58 | expect(m2c('g-pa').attr).toBe('position'); 59 | expect(m2c('g-fs24').attr).toBe('font-size'); 60 | expect(m2c('f-bgc_border-box').attr).toBe('background-clip'); 61 | expect(m2c('f-bgo_center').attr).toBe('background-origin'); 62 | expect(m2c('f-bgr_no-repeat').attr).toBe('background-repeat'); 63 | expect(m2c('f-bdb10').attr).toBe('border-bottom'); 64 | expect(m2c('f-bdl10').attr).toBe('border-left'); 65 | expect(m2c('f-bdt10').attr).toBe('border-top'); 66 | expect(m2c('f-bdtr10').attr).toBe('border-right'); 67 | expect(m2c('f-bdtlr10').attr).toBe('border-top-left-radius'); 68 | expect(m2c('f-bdtrr10').attr).toBe('border-top-right-radius'); 69 | expect(m2c('f-bdblr10').attr).toBe('border-bottom-left-radius'); 70 | expect(m2c('f-bdbrr10').attr).toBe('border-bottom-right-radius'); 71 | expect(m2c('f-c_both').attr).toBe('clear'); 72 | expect(m2c('f-fr').attr).toBe('float'); 73 | expect(m2c('f-fl').attr).toBe('float'); 74 | expect(m2c('f-ov_hidden').attr).toBe('overflow'); 75 | expect(m2c('f-ovx_hidden').attr).toBe('overflow-x'); 76 | expect(m2c('f-ovy_hidden').attr).toBe('overflow-y'); 77 | expect(m2c('f-ff_DIN').attr).toBe('font-family'); 78 | expect(m2c('f-fs_italic').attr).toBe('font-style'); 79 | expect(m2c('f-fw_bold').attr).toBe('font-weight'); 80 | expect(m2c('f-tc').attr).toBe('text-align'); 81 | expect(m2c('f-td_underline').attr).toBe('text-decoration'); 82 | expect(m2c('f-ti2').attr).toBe('text-indent'); 83 | expect(m2c('f-tj_center').attr).toBe('text-justify'); 84 | expect(m2c('f-cr_pointer').attr).toBe('cursor'); 85 | expect(m2c('u-ai_center').attr).toBe('align-items'); 86 | expect(m2c('u-jc_center').attr).toBe('justify-content'); 87 | expect(m2c('u-d_block').attr).toBe('display'); 88 | expect(m2c('u-flexd_row').attr).toBe('flex-direction'); 89 | expect(m2c('z-v_hidden').attr).toBe('visibility'); 90 | expect(m2c('z-zi_999').attr).toBe('z-index'); 91 | expect(m2c('z-hide_99').attr).toBe('opacity'); 92 | }); 93 | it('simple value analyse test', () => { 94 | expect(m2c('g-box_border-box').val).toBe('border-box'); 95 | expect(m2c('g-pr').val).toBe('relative'); 96 | expect(m2c('g-pf').val).toBe('fixed'); 97 | expect(m2c('g-pa').val).toBe('absolute'); 98 | expect(m2c('g-fs20').val).toBe('2.66666vw'); 99 | expect(m2c('g-lh200per').val).toBe('200%'); 100 | expect(m2c('f-bgc_border-box').val).toBe('border-box'); 101 | expect(m2c('f-bgo_center').val).toBe('center'); 102 | expect(m2c('f-bgr_no-repeat').val).toBe('no-repeat'); 103 | expect(m2c('f-bdb10').val).toBe('1.33333vw'); 104 | expect(m2c('f-bdl10').val).toBe('1.33333vw'); 105 | expect(m2c('f-bdt10').val).toBe('1.33333vw'); 106 | expect(m2c('f-bdtr10').val).toBe('1.33333vw'); 107 | expect(m2c('f-bdtlr10').val).toBe('1.33333vw'); 108 | expect(m2c('f-bdtrr10').val).toBe('1.33333vw'); 109 | expect(m2c('f-bdblr10').val).toBe('1.33333vw'); 110 | expect(m2c('f-bdbrr10').val).toBe('1.33333vw'); 111 | expect(m2c('f-c_both').val).toBe('both'); 112 | expect(m2c('f-fr').val).toBe('right'); 113 | expect(m2c('f-fl').val).toBe('left'); 114 | expect(m2c('f-ov_hidden').val).toBe('hidden'); 115 | expect(m2c('f-ovx_hidden').val).toBe('hidden'); 116 | expect(m2c('f-ovy_hidden').val).toBe('hidden'); 117 | expect(m2c('f-ff_DIN').val).toBe('DIN'); 118 | expect(m2c('f-fs_italic').val).toBe('italic'); 119 | expect(m2c('f-fw_bold').val).toBe('bold'); 120 | expect(m2c('f-tc').val).toBe('center'); 121 | expect(m2c('f-td_underline').val).toBe('underline'); 122 | expect(m2c('f-ti2').val).toBe('2'); 123 | expect(m2c('f-tj_center').val).toBe('center'); 124 | expect(m2c('f-cr_pointer').val).toBe('pointer'); 125 | expect(m2c('u-ai_center').val).toBe('center'); 126 | expect(m2c('u-jc_center').val).toBe('center'); 127 | expect(m2c('u-d_block').val).toBe('block'); 128 | expect(m2c('u-flexd_row').val).toBe('row'); 129 | expect(m2c('z-v_hidden').val).toBe('hidden'); 130 | expect(m2c('z-zi_999').val).toBe('999'); 131 | expect(m2c('z-hide_99').val).toBe('99'); 132 | }); 133 | }); 134 | -------------------------------------------------------------------------------- /moo-css-transformer/types/index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | type cssValue = string | number; 4 | 5 | interface m2cResult { 6 | key: string; 7 | attr: string; 8 | val: cssValue; 9 | } 10 | 11 | 12 | declare module 'moo-css-transformer' { 13 | /** 14 | * MooCSS selector --> CSS values 15 | * @param minName 16 | * @param lenUnit 17 | * @param viewport 18 | */ 19 | export function m2c (minName: string, lenUnit?: string, viewport?: number): m2cResult; 20 | 21 | /** 22 | * CSS values --> MooCSS selector 23 | * @param styleName 24 | * @param styleVal 25 | */ 26 | export function c2m (styleName: string, styleVal: cssValue): string; 27 | 28 | /** 29 | * CSS sheet --> CSS list 30 | * @param cssStr 31 | */ 32 | export function styleScaner (cssStr: string): string[]; 33 | 34 | interface MooCssTransformerType { 35 | m2c: typeof m2c, 36 | c2m: typeof c2m, 37 | styleScaner: typeof styleScaner 38 | } 39 | const MooCssTransformer: { 40 | m2c: typeof m2c, 41 | c2m: typeof c2m, 42 | styleScaner: typeof styleScaner, 43 | } 44 | export default MooCssTransformer 45 | } -------------------------------------------------------------------------------- /moo-css-transformer/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * moo-css-transformer webpack config 3 | * @author Wayne 4 | * @date 2021.02.21 5 | */ 6 | 7 | const path = require('path'); 8 | const webpack = require('webpack'); 9 | const pkg = require('./package.json'); 10 | const myBanner = ` 11 | ${pkg.name} 12 | @github ${pkg.repository.url} 13 | `; 14 | 15 | module.exports = { 16 | mode: 'production', 17 | entry: { 18 | c2m: path.join(__dirname, './src/c2m.js'), 19 | m2c: path.join(__dirname, './src/m2c.js'), 20 | }, 21 | output: { 22 | path: path.join(__dirname, 'dist'), 23 | filename: '[name].js', 24 | publicPath: path.join(__dirname), 25 | libraryTarget: 'commonjs', 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.js$/, 31 | loader: 'babel-loader', 32 | query: { 33 | presets: [ 34 | [ 35 | '@babel/env', 36 | { 37 | loose: true, 38 | }, 39 | ], 40 | ], 41 | }, 42 | }, 43 | ], 44 | }, 45 | node: { 46 | fs: 'empty', 47 | }, 48 | plugins: [new webpack.BannerPlugin(myBanner)], 49 | }; 50 | -------------------------------------------------------------------------------- /moo-css-weapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moo-css-weapp", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "" 8 | }, 9 | "author": "Micheal Wang", 10 | "license": "ISC", 11 | "dependencies": {} 12 | } 13 | -------------------------------------------------------------------------------- /moo-css-weapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "module": "commonjs", 8 | "target": "es5", 9 | "allowJs": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "@/*": [ 13 | "src/*" 14 | ] 15 | }, 16 | "typeRoots": ["./src/types/"], 17 | "rootDir": "./src/" 18 | } 19 | } -------------------------------------------------------------------------------- /moo-css-web/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/* 2 | src/js/lib/*.js 3 | lib/*.js -------------------------------------------------------------------------------- /moo-css-web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | /yarn.lock 8 | # /package-lock.json 9 | /coverage 10 | 11 | 12 | # production 13 | /dist 14 | 15 | # misc 16 | .DS_Store 17 | 18 | # logs 19 | /*.log 20 | 21 | # vscode 22 | /.vscode 23 | 24 | # zip 25 | /*.zip 26 | -------------------------------------------------------------------------------- /moo-css-web/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "printWidth": 100, // 每行代码长度 3 | "tabWidth": 2, // tab 宽度(2个空格) 4 | "useTabs": false, // 不使用 tab 缩进 5 | "singleQuote": true, // 使用单引号 6 | "semi": true, // 使用分号 7 | "trailingComma": "es5", // 在 es5 中合法的地方加尾逗号 8 | "bracketSpacing": true, // 对象字面量的大括号间使用空格 9 | "arrowParens": "avoid" // 只有一个参数的箭头函数参数不带圆括号 10 | }; 11 | -------------------------------------------------------------------------------- /moo-css-web/dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @namespace mvdom2web 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const json2html_1 = require("./json2html"); 7 | const moo_css_transformer_1 = require("moo-css-transformer"); 8 | function handleData(config) { 9 | let { data, handleImg, nostyle, viewport, } = config; 10 | let cssTextObj = {}; 11 | const _style2MooSelector = (str) => { 12 | let _arr = str.split(':'); 13 | if (!_arr[1] || _arr[1] === 'undefined') 14 | return undefined; 15 | return moo_css_transformer_1.c2m.style2MooSelector(_arr[0], _arr[1]); 16 | }; 17 | const _handleStyleProps = (props) => { 18 | let styleList = moo_css_transformer_1.c2m.styleScaner(`{${props.style}}`); 19 | let classList = []; 20 | if (!nostyle) { 21 | let newStyle = styleList.filter((item) => { 22 | if (viewport && ~item.indexOf('px')) { // mobile 23 | let arr = item.split(':'); 24 | item = `${arr[0]}:${(parseInt(arr[1]) / viewport * 100).toFixed(4)}vw`; 25 | } 26 | let moo = _style2MooSelector(item); 27 | if (moo) { 28 | classList.push(moo); 29 | if (!cssTextObj[moo]) 30 | cssTextObj[moo] = item; 31 | return false; 32 | } 33 | else if (moo !== undefined) { 34 | return item; 35 | } 36 | else 37 | return false; 38 | }).join(';'); 39 | props.style = newStyle; 40 | } 41 | else { 42 | let moduleClassList = []; 43 | styleList.forEach((item) => { 44 | if (viewport && ~item.indexOf('px')) { // mobile 45 | let arr = item.split(':'); 46 | item = `${arr[0]}:${(parseInt(arr[1]) / viewport * 100).toFixed(4)}vw`; 47 | } 48 | let moo = _style2MooSelector(item); 49 | if (moo) { 50 | classList.push(moo); 51 | if (!cssTextObj[moo]) 52 | cssTextObj[moo] = item; 53 | return false; 54 | } 55 | else if (moo !== undefined) { 56 | moduleClassList.push(item); 57 | return item; 58 | } 59 | else 60 | return false; 61 | }); 62 | if (moduleClassList.length) { 63 | props.className = 'm-' + ('' + Math.random()).slice(-6); 64 | cssTextObj[props.className] = moduleClassList.join(';'); 65 | } 66 | delete props.style; 67 | } 68 | if (classList.length) { 69 | let className = classList.join(' '); 70 | props.className = (props.className ? props.className + ' ' : '') + className; 71 | return className; 72 | } 73 | }; 74 | let htmlTxt = json2html_1.default.build(data, { 75 | handleStyle: _handleStyleProps, 76 | handleImg 77 | }); 78 | let cssTxt = ''; 79 | for (let selector in cssTextObj) { 80 | cssTxt += ` 81 | .${selector} { 82 | ${cssTextObj[selector]} 83 | }`; 84 | } 85 | return { 86 | html: htmlTxt, 87 | css: cssTxt 88 | }; 89 | } 90 | exports.default = handleData; 91 | -------------------------------------------------------------------------------- /moo-css-web/dist/json2html.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @module json2html 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | class JSON2HTML { 7 | static get selfCloseTags() { 8 | return [ 9 | 'area', 'base', 'br', 'col', 'embed', 'hr', 10 | 'img', 'input', 'link', 'meta', 'param', 'source', 11 | 'track', 'wbr', 'command', 'keygen', 'menuitem', 12 | ]; 13 | } 14 | static build(json, handlers) { 15 | if (!json || !json.tagName) 16 | return ''; 17 | const props = JSON2HTMLBuilder.props(json, handlers); 18 | if (JSON2HTMLBuilder.isSelfCloseTag(json)) { 19 | return `<${json.tagName}${props}/>`; 20 | } 21 | const children = JSON2HTMLBuilder.children(json, handlers); 22 | return ` 23 | <${json.tagName}${props}>${children}`; 24 | } 25 | } 26 | exports.default = JSON2HTML; 27 | class JSON2HTMLBuilder { 28 | static props(json, handlers) { 29 | let props = json.props; 30 | if (!props) 31 | return ''; 32 | let html = ''; 33 | const { handleStyle, handleImg, } = handlers; 34 | if (props.style && handleStyle) { 35 | handleStyle(props); 36 | } 37 | if (props.src && handleImg && props.src.startsWith('data:image')) { 38 | handleImg(props); 39 | } 40 | const keys = Object.keys(props); 41 | for (const index in keys) { 42 | let key = keys[index]; 43 | if (key === 'children') 44 | continue; 45 | else if (key === 'className') 46 | html += ` class="${props[key]}"`; 47 | else if ({}.hasOwnProperty.call(keys, index)) { 48 | if (props[key]) 49 | html += ` ${key}="${props[key]}"`; 50 | } 51 | } 52 | return html; 53 | } 54 | static children(json, handlers) { 55 | let children = json.props && json.props.children; 56 | if (!children) 57 | return ''; 58 | let html = ''; 59 | for (const index in children) { 60 | if ({}.hasOwnProperty.call(children, index)) { 61 | if (typeof children[index] == 'object') { 62 | html += JSON2HTML.build(children[index], handlers); 63 | } 64 | else { 65 | html += children[index]; 66 | } 67 | } 68 | } 69 | return html; 70 | } 71 | static isSelfCloseTag(json) { 72 | return (JSON2HTML.selfCloseTags.indexOf(json.tag) > -1); 73 | } 74 | } 75 | exports.JSON2HTMLBuilder = JSON2HTMLBuilder; 76 | ; 77 | -------------------------------------------------------------------------------- /moo-css-web/dist/src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @namespace mvdom2web 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const json2html_1 = require("./json2html"); 7 | function test(json) { 8 | console.log(json2html_1.default.build(json)); 9 | } 10 | exports.default = test; 11 | -------------------------------------------------------------------------------- /moo-css-web/dist/src/json2html.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @module json2html 4 | */ 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | class JSON2HTML { 7 | static get selfCloseTags() { 8 | return [ 9 | 'area', 'base', 'br', 'col', 'embed', 'hr', 10 | 'img', 'input', 'link', 'meta', 'param', 'source', 11 | 'track', 'wbr', 'command', 'keygen', 'menuitem', 12 | ]; 13 | } 14 | static build(json, handleStyle) { 15 | if (!json || !json.tagName) 16 | return ''; 17 | const props = JSON2HTMLBuilder.props(json, handleStyle); 18 | if (JSON2HTMLBuilder.isSelfCloseTag(json)) { 19 | return `<${json.tagName}${props}/>`; 20 | } 21 | const children = JSON2HTMLBuilder.children(json); 22 | return `<${json.tagName}${props}> 23 | ${children} 24 | `; 25 | } 26 | } 27 | exports.default = JSON2HTML; 28 | class JSON2HTMLBuilder { 29 | static props(json, handleStyle) { 30 | if (!json.props) 31 | return ''; 32 | let html = ''; 33 | const keys = Object.keys(json.props); 34 | if (json.props.style && handleStyle) { 35 | handleStyle(json.props); 36 | } 37 | for (const index in keys) { 38 | let key = keys[index]; 39 | if (key === 'children') 40 | continue; 41 | if ({}.hasOwnProperty.call(keys, index)) { 42 | html += ` ${key}="${json.props[key]}"`; 43 | } 44 | } 45 | return html; 46 | } 47 | static children(json) { 48 | let children = json.props && json.props.children; 49 | if (!children) 50 | return ''; 51 | let html = ''; 52 | for (const index in children) { 53 | if ({}.hasOwnProperty.call(children, index)) { 54 | if (typeof children[index] == 'object') { 55 | html += JSON2HTML.build(children[index]); 56 | } 57 | else { 58 | html += children[index]; 59 | } 60 | } 61 | } 62 | return html; 63 | } 64 | static isSelfCloseTag(json) { 65 | return (JSON2HTML.selfCloseTags.indexOf(json.tag) > -1); 66 | } 67 | } 68 | exports.JSON2HTMLBuilder = JSON2HTMLBuilder; 69 | ; 70 | -------------------------------------------------------------------------------- /moo-css-web/dist/utils/handleImage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * handle image base64 4 | */ 5 | /* 6 | export default function handleImgBase64 (base64: string) { 7 | let base64Data = base64.replace(/^data:image\/\w+;base64,/, ''); 8 | let dataBuffer = new Buffer(base64Data, 'base64'); 9 | return dataBuffer; 10 | }*/ 11 | -------------------------------------------------------------------------------- /moo-css-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moo-css-web", 3 | "version": "1.0.0", 4 | "description": "mvdom data to html and css file.", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "node ./__test__/", 8 | "build": "tsc" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^13.7.6", 12 | "typescript": "^3.4.4" 13 | }, 14 | "keywords": [ 15 | "moo-css" 16 | ], 17 | "author": "MichealWayne", 18 | "license": "ISC" 19 | } 20 | -------------------------------------------------------------------------------- /moo-css-web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "module": "commonjs", 8 | "target": "es5", 9 | "allowJs": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "@/*": [ 13 | "src/*" 14 | ] 15 | }, 16 | "typeRoots": ["./src/types/"], 17 | "rootDir": "./src/" 18 | } 19 | } -------------------------------------------------------------------------------- /vscode/moo-css-plugin.dev.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichealWayne/moo-css-plugins/1cb1da935358103ff286036ee19c2eee508f7c80/vscode/moo-css-plugin.dev.vsix --------------------------------------------------------------------------------