├── .editorconfig
├── .gitignore
├── LICENSE.txt
├── Makefile
├── README.md
├── build.sbt
├── ci
└── npm-login.sh
├── circle.yml
├── codecov.yml
├── dist
└── .emtpy
├── docs
└── src
│ └── main
│ ├── resources
│ └── microsite
│ │ ├── css
│ │ └── override.css
│ │ └── img
│ │ ├── first_icon.png
│ │ ├── first_icon2x.png
│ │ ├── futurama_June_22__2016_at_0120AM.gif
│ │ ├── futurama_September_11__2016_at_0545AM (2).gif
│ │ ├── jumbotron_pattern.png
│ │ ├── jumbotron_pattern2x.png
│ │ ├── navbar_brand.png
│ │ ├── navbar_brand2x.png
│ │ ├── second_icon.png
│ │ ├── second_icon2x.png
│ │ ├── sidebar_brand.png
│ │ ├── sidebar_brand2x.png
│ │ ├── third_icon.png
│ │ └── third_icon2x.png
│ └── tut
│ ├── API.md
│ ├── CNAME
│ ├── Examples.md
│ ├── FAQ.md
│ ├── FRP-Best-Practice.md
│ ├── Fantasy.md
│ ├── Get-Started.md
│ ├── Home.md
│ ├── Monadic.md
│ ├── Notation.md
│ ├── Performance.md
│ ├── React-Most-函数式最佳实践.md
│ ├── _Footer.md
│ ├── _Sidebar.md
│ ├── circle.yml
│ ├── examples
│ ├── example.tsx
│ ├── index.html
│ ├── index.md
│ └── index.org
│ ├── flatMap.md
│ ├── index.md
│ ├── typeclass.md
│ ├── typeclass.org
│ ├── zh.md
│ ├── 教程.md
│ └── 范特西.md
├── examples
├── README.md
├── alacarte
│ ├── app.js
│ ├── app.jsx
│ └── index.html
├── bmi-calc
│ ├── app.js
│ ├── app.tsx
│ └── index.html
├── counter
│ ├── README.md
│ ├── app.js
│ ├── app.jsx
│ └── index.html
├── frp-counter
│ ├── app.js
│ ├── app.jsx
│ └── index.html
├── index.md
├── package.json
├── todomvc
│ ├── README.md
│ ├── __mocks__
│ │ └── rest.js
│ ├── app.js
│ ├── app.tsx
│ ├── components
│ │ ├── Footer.tsx
│ │ ├── Header.tsx
│ │ ├── MainSection.tsx
│ │ ├── TodoItem.tsx
│ │ ├── TodoTextInput.tsx
│ │ ├── __tests__
│ │ │ └── MainSection-spec.jsx
│ │ └── interfaces.ts
│ ├── index.html
│ ├── intent.ts
│ ├── todos.json
│ └── tsconfig.json
├── tsconfig.json
├── type-n-search
│ ├── README.md
│ ├── app.js
│ ├── app.jsx
│ ├── index.html
│ └── src
│ │ ├── transducer.jsx
│ │ └── undo.jsx
└── yarn.lock
├── package.json
├── project
├── build.properties
└── plugins.sbt
├── src
├── __tests__
│ ├── fantasy-test.ts
│ ├── fantasyx-test.ts
│ └── xtest.tsx
├── fantasy
│ ├── fantasyx.ts
│ ├── index.ts
│ ├── interfaces.ts
│ ├── state.ts
│ ├── streamT.ts
│ ├── typeclasses
│ │ ├── applicative.ts
│ │ ├── apply.ts
│ │ ├── cartesian.ts
│ │ ├── flatmap.ts
│ │ ├── functor.ts
│ │ ├── id.ts
│ │ ├── index.ts
│ │ ├── monad.ts
│ │ ├── semigroup.ts
│ │ └── traversable.ts
│ └── xstream.ts
├── index.ts
├── interfaces.ts
├── x.ts
├── xclass.ts
├── xs
│ ├── array.ts
│ ├── index.ts
│ ├── most.ts
│ └── rx.ts
└── xtests
│ ├── index.ts
│ ├── most.ts
│ ├── rx.ts
│ └── util.ts
├── test
└── test.js
├── tsconfig.common.json
├── tsconfig.examples.json
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [Makefile]
5 | indent_style = tab
6 | indent_size = 2
7 |
8 | [*.{ts,tsx}]
9 | indent_style = space
10 | indent_size = 2
11 | end_of_line = lf
12 | charset = utf-8
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/node
2 |
3 | ### Node ###
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | ##########idea
9 | .idea/
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22 | .grunt
23 |
24 | # node-waf configuration
25 | .lock-wscript
26 |
27 | # Compiled binary addons (http://nodejs.org/api/addons.html)
28 | build/Release
29 |
30 | # Dependency directory
31 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
32 | node_modules
33 |
34 | lib
35 |
36 | # Created by https://www.gitignore.io/api/sbt
37 |
38 | ### SBT ###
39 | # Simple Build Tool
40 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
41 |
42 | dist/*
43 | target/
44 | lib_managed/
45 | src_managed/
46 | project/boot/
47 | project/plugins/project/
48 | .history
49 | .cache
50 | .lib/
51 |
52 | # End of https://www.gitignore.io/api/sbt
53 | /examples
54 | /docs/**/example.js
55 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | /**
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Jichao Ouyang
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | docsdir = ./docs/**/*
2 | bin = ./node_modules/.bin
3 |
4 | test: unit integrate
5 |
6 | build: lib/**/*.js
7 |
8 | lib/**/*.js: src/**/*.ts
9 | $(bin)/tsc
10 |
11 | lib/%.js: src/%.ts
12 | $(bin)/tsc
13 |
14 | all: test dist
15 |
16 | .PHONY: test build unit integrate dist docs docs/publish
17 |
18 | unit: build
19 | yarn test
20 |
21 | integrate: build test/*.js docs/src/main/tut/examples/example.js
22 | $(bin)/mocha test/test.js
23 |
24 | docs/src/main/tut/examples/example.js: docs/src/main/tut/examples/example.tsx
25 | $(bin)/browserify -p [tsify -p tsconfig.examples.json] docs/src/main/tut/examples/example.tsx -o docs/src/main/tut/examples/example.js
26 |
27 | watch/example: docs/src/main/tut/examples/example.tsx
28 | $(bin)/watchify -p [tsify -p tsconfig.examples.json] -t envify docs/src/main/tut/examples/example.tsx -dv -o docs/src/main/tut/examples/example.js
29 |
30 | dist: dist/xreact.min.js dist/xreact-most.min.js dist/xreact-rx.min.js
31 |
32 | dist/xreact.js: lib/index.js dist/xreact-most.js dist/xreact-rx.js
33 | env NODE_ENV=production $(bin)/browserify -t browserify-shim -t envify -x ./lib/xs $< -s xreact -o $@
34 |
35 | dist/xreact-%.js: lib/xs/%.js
36 | env NODE_ENV=production $(bin)/browserify -t browserify-shim -t envify -r ./lib/xs $< -o $@
37 |
38 | dist/%.min.js: dist/%.js
39 | env NODE_ENV=production $(bin)/uglifyjs -c dead_code $(basename $(basename $@)).js -o $@
40 |
41 | docs: $(docsdir)
42 | sbt "project docs" makeMicrosite
43 |
44 | docs/publish: $(docsdir)
45 | sbt "project docs" publishMicrosite
46 |
47 | clean:
48 | rm -rf lib docs/src/main/tut/examples/example.js dist/*
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xReact
2 |
3 | xReact is a Functional Reactive State Wrapper for React Components. Data flow in xReact is observable and unidirectional.
4 |
5 | > formerly know as react-most, renamed so because mostjs is not madatory anymore.
6 |
7 | [](https://circleci.com/gh/reactive-react/xreact)
8 | [](https://gitter.im/jcouyang/react-most?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
9 | [](https://github.com/reactive-react/xreact)
10 | [](https://codecov.io/gh/reactive-react/xreact)
11 | [](https://www.npmjs.com/package/xreact)
12 | [](https://greenkeeper.io)
13 |
14 | 
15 |
16 | ## [Get Started](https://xreact.oyanglul.us)
17 |
18 | xReact works for both TypeScript and CMD JS, to install xReact simply use yarn or npm:
19 |
20 | ```
21 | npm install xreact --save
22 | # or
23 | yarn add xreact
24 | ```
25 |
26 |
27 | - Come from redux? :point_right: See the Pen XREACT by Jichao Ouyang (@jcouyang) on CodePen. See the Pen XREACT Counter in TypeScript by Jichao Ouyang (@jcouyang) on CodePen. See the Pen XREACT FANTASY COUNTER by Jichao Ouyang (@jcouyang) on CodePen. {props.product} {props.product} {props.semigroup}
70 |
71 | {props.sum} HEALTH: {props.health} BMI: {props.bmi}
121 | {props.count || 0}
122 | props.actions.fromEvent(e)} />
123 |
136 | props.actions.fromEvent(e)} />
137 | {props.count || 0}
138 | props.actions.fromEvent(e)} />
139 |
161 | {props.count}
162 | {actions.map(action=>
163 | props.actions.fromEvent(e)} />)}
164 | {props.product}
{props.product}
57 |{props.semigroup}
77 |102 | 103 |
)) 104 | } 105 |{props.sum}
106 |HEALTH: {props.health}
138 |BMI: {props.bmi}
139 |155 | {props.count} 156 | props.actions.fromEvent(e)} /> 157 |
158 | let Eg6 = Xeg6.map(a=>({count: a})).apply(ViewEg6) 159 | ``` 160 | 161 | 162 | 163 | 164 | 165 | 166 | # Example 7: Merge 167 | 168 | ```tsx 169 | let Xeg7 = fold( 170 | (acc:number,i: number) => acc+i, 0, 171 | fromEvent('click', 'increment').map(x=>1).merge( 172 | fromEvent('click', 'decrement').map(x=>-1))) 173 | 174 | let ViewEg7 = props =>175 | props.actions.fromEvent(e)} /> 176 | {props.count} 177 | props.actions.fromEvent(e)} /> 178 |
179 | let Eg7 = Xeg7.map(a=>({count: a})).apply(ViewEg7) 180 | ``` 181 | 182 | 183 | 184 | 185 | 186 | 187 | # Example 8: Fold multiple buttons 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | # Example 13: Adding items to a list 197 | -------------------------------------------------------------------------------- /docs/src/main/tut/examples/index.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Examples of xReact Fantasy 2 | #+Date: <2017-09-09 Sat> 3 | # #+AUTHOR: 欧阳继超 4 | #+HTML_HEAD: 5 | #+OPTIONS: exports:source tangle:yes eval:no-export num:1 6 | 7 | * Example 0: How to use xReact Fantasy 8 | 9 | #+BEGIN_SRC js :tangle example.tsx 10 | 11 | import * as React from 'react'; 12 | import { render } from 'react-dom'; 13 | import '../../../../../src/xs/rx' 14 | import { Applicative, lift2,Semigroup, Functor, map, Traversable, FlatMap } from '../../../../../src/fantasy' 15 | import {X} from '../../../../../src' 16 | function xmount(component, dom) { render(React.createFactory(X)({}, component), dom) } 17 | #+END_SRC 18 | 19 | * Example 1: Two number multiply 20 | A multiply function can be simply lifted to be a function that works with xReact FantasyX 21 | #+BEGIN_SRC js :tangle example.tsx 22 | let mult = (x:number,y: number) => x * y 23 | let Xeg1 = lift2<"FantasyX",number, number, number>(mult)(Applicative.FantasyX.pure(6), Applicative.FantasyX.pure(5)) 24 | #+END_SRC 25 | 26 | A very basic Stateless Component to display it. 27 | #+BEGIN_SRC js :tangle example.tsx 28 | let ViewEg1 = props =>{props.product}
29 | #+END_SRC 30 | 31 | #+BEGIN_SRC js :tangle example.tsx 32 | let Eg1 = Functor.FantasyX.map(a=>({product: a}), Xeg1).apply(ViewEg1) 33 | #+END_SRC 34 | 35 | #+BEGIN_SRC js :tangle example.tsx 36 | xmount({props.product}
61 |{props.semigroup}
85 |112 | 113 |
)) 114 | } 115 |{props.sum}
116 |HEALTH: {props.health}
157 |BMI: {props.bmi}
158 |180 | {props.count || 0} 181 | props.actions.fromEvent(e)} /> 182 |
183 | 184 | let Eg6 = Xeg6.apply(ViewEg6) 185 | #+END_SRC 186 | 187 | #+BEGIN_SRC js :tangle example.tsx :exports none 188 | xmount(202 | props.actions.fromEvent(e)} /> 203 | {props.count || 0} 204 | props.actions.fromEvent(e)} /> 205 |
206 | 207 | let Eg7 = Xeg7.merge(Xeg6).apply(ViewEg7) 208 | #+END_SRC 209 | 210 | #+BEGIN_SRC js :tangle example.tsx :exports none 211 | xmount(236 | {props.count} 237 | {actions.map(action=> 238 | props.actions.fromEvent(e)} />)} 239 |
240 | 241 | let Eg8 = Xeg8.apply(ViewEg8) 242 | 243 | xmount(Your BMI is {props.bmi}
33 |which means you're {props.health}
34 |where weight is {props.weight} kg
: null) 65 | const Height = heightx.apply(props => props.height ?and {props.height}m height
: null) 66 | render( 67 |