├── examples └── navigation-react-redux │ ├── .gitignore │ ├── README.md │ ├── .babelrc │ ├── containers │ ├── App.js │ ├── Root.js │ ├── Admin.js │ ├── ReposByUser.js │ └── UserSearch.js │ ├── index.html │ ├── reducers │ ├── adminAccess.js │ ├── userResults.js │ ├── index.js │ ├── searchInFlight.js │ └── reposByUser.js │ ├── components │ ├── UserSearchInput.js │ ├── Repos.js │ └── UserSearchResults.js │ ├── constants │ └── ActionTypes.js │ ├── epics │ ├── index.js │ ├── stateStreamTest.js │ ├── clearSearchResults.js │ ├── searchUsersDebounced.js │ ├── adminAccess.js │ ├── fetchReposByUser.js │ └── searchUsers.js │ ├── actions │ └── index.js │ ├── webpack.config.prod.babel.js │ ├── webpack.config.dev.babel.js │ ├── package.json │ ├── index.js │ ├── utils │ └── index.js │ └── store │ └── index.js ├── .vscode └── settings.json ├── .gitignore ├── .eslintignore ├── .travis.yml ├── src ├── actions.js ├── constants.js ├── select.js ├── selectArray.js ├── index.js ├── withState.js ├── createStateStreamEnhancer.js ├── combineEpics.js └── createEpicMiddleware.js ├── .babelrc ├── tests ├── select.test.js ├── selectArray.test.js └── combineEpics.test.js ├── LICENSE ├── .eslintrc.json ├── webpack.config.babel.js ├── index.d.ts ├── package.json └── README.md /examples/navigation-react-redux/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | lib 4 | es 5 | temp 6 | dist 7 | _book 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # /node_modules and /bower_components ignored by default 2 | 3 | dist/ 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | 5 | script: 6 | - npm run safety-check 7 | -------------------------------------------------------------------------------- /src/actions.js: -------------------------------------------------------------------------------- 1 | import { EPIC_END } from './constants' 2 | 3 | export const epicEnd = () => ({ type: EPIC_END }) 4 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | export const EPIC_END = '@@redux-most/EPIC_END' 2 | export const STATE_STREAM_SYMBOL = Symbol('@@redux-most/STATE_STREAM') 3 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/README.md: -------------------------------------------------------------------------------- 1 | #### Instructions 2 | ``` 3 | npm install 4 | npm run start 5 | ``` 6 | Then, open your browser and navigate to localhost:3000 7 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-3", 7 | "react" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/containers/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const App = ({ children }) => 4 |
{user} has no repos
17 | } 18 |Checking access...
14 | ) 15 | } 16 | 17 | if (this.props.adminAccess === 'GRANTED') { 18 | return ( 19 |Access granted
20 | ) 21 | } 22 | 23 | return ( 24 |25 | Access denied. Redirecting back home. 26 |
27 | ) 28 | } 29 | } 30 | 31 | const mapStateToProps = ({ adminAccess }) => ({ adminAccess }) 32 | 33 | const mapDispatchToProps = { checkAdminAccess } 34 | 35 | export default connect(mapStateToProps, mapDispatchToProps)(Admin) 36 | -------------------------------------------------------------------------------- /tests/selectArray.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { observe } from 'most' 3 | import { sync } from 'most-subject' 4 | import { selectArray } from '../src/' 5 | 6 | test('selectArray should filter by multiple action types', t => { 7 | const actions$ = sync() 8 | const lulz = [] 9 | const haha = [] 10 | 11 | observe(x => lulz.push(x), selectArray(['LULZ', 'LMFAO'], actions$)) 12 | observe(x => haha.push(x), selectArray(['HAHA'], actions$)) 13 | 14 | actions$.next({ type: 'LULZ', i: 0 }) 15 | 16 | t.deepEqual([{ type: 'LULZ', i: 0 }], lulz) 17 | t.deepEqual([], haha) 18 | 19 | actions$.next({ type: 'LMFAO', i: 1 }) 20 | 21 | t.deepEqual([{ type: 'LULZ', i: 0 }, { type: 'LMFAO', i: 1 }], lulz) 22 | t.deepEqual([], haha) 23 | 24 | actions$.next({ type: 'HAHA', i: 0 }) 25 | 26 | t.deepEqual([{ type: 'LULZ', i: 0 }, { type: 'LMFAO', i: 1 }], lulz) 27 | t.deepEqual([{ type: 'HAHA', i: 0 }], haha) 28 | }) 29 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/epics/clearSearchResults.js: -------------------------------------------------------------------------------- 1 | import { SEARCHED_USERS_DEBOUNCED } from '../constants/ActionTypes' 2 | import { clearSearchResults } from '../actions' 3 | import { select } from 'redux-most' 4 | // import { select } from '../../../src/index' 5 | import { 6 | curriedFilter as filter, 7 | curriedMap as map, 8 | } from '../utils' 9 | import { compose } from 'ramda' 10 | 11 | const whereEmpty = ({ payload: { query } }) => !query 12 | 13 | // Fluent style 14 | // const clear = action$ => 15 | // action$.thru(select(SEARCHED_USERS_DEBOUNCED)) 16 | // .filter(whereEmpty) 17 | // .map(clearSearchResults) 18 | 19 | // Functional style 20 | // const clear = action$ => { 21 | // const search$ = select(SEARCHED_USERS_DEBOUNCED, action$) 22 | // const whereEmpty$ = filter(whereEmpty, search$) 23 | // return map(clearSearchResults, whereEmpty$) 24 | // } 25 | 26 | // Functional & Pointfree style using functional composition 27 | const clear = compose( 28 | map(clearSearchResults), 29 | filter(whereEmpty), 30 | select(SEARCHED_USERS_DEBOUNCED) 31 | ) 32 | 33 | export default clear 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Josh Burgess 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/epics/searchUsersDebounced.js: -------------------------------------------------------------------------------- 1 | import { SEARCHED_USERS_DEBOUNCED } from '../constants/ActionTypes' 2 | import { searchedUsers } from '../actions' 3 | import { select } from 'redux-most' 4 | // import { select } from '../../../src/index' 5 | import { 6 | curriedDebounce as debounce, 7 | curriedMap as map, 8 | } from '../utils' 9 | import { compose } from 'ramda' 10 | 11 | const toSearchedUsers = ({ payload: { query } }) => 12 | searchedUsers(query) 13 | 14 | // Fluent style 15 | // const searchUsersDebounced = action$ => 16 | // action$.thru(select(SEARCHED_USERS_DEBOUNCED)) 17 | // .debounce(800) 18 | // .map(toSearchedUsers) 19 | 20 | // Functional style 21 | // const searchUsersDebounced = action$ => { 22 | // const search$ = select(SEARCHED_USERS_DEBOUNCED, action$) 23 | // const debouncedSearch$ = debounce(800, search$) 24 | // return map(toSearchedUsers, debouncedSearch$) 25 | // } 26 | 27 | // Functional & Pointfree style using functional composition 28 | const searchUsersDebounced = compose( 29 | map(toSearchedUsers), 30 | debounce(800), 31 | select(SEARCHED_USERS_DEBOUNCED) 32 | ) 33 | 34 | export default searchUsersDebounced 35 | -------------------------------------------------------------------------------- /examples/navigation-react-redux/containers/ReposByUser.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import Repos from '../components/Repos' 4 | import { requestReposByUser } from '../actions' 5 | 6 | class ReposByUser extends React.Component { 7 | componentDidMount () { 8 | this.props.requestReposByUser(this.props.params.user) 9 | } 10 | 11 | componentWillReceiveProps (nextProps) { 12 | const { user } = this.props.params 13 | 14 | if (user !== nextProps.params.user) { 15 | this.props.requestReposByUser(user) 16 | } 17 | } 18 | 19 | render () { 20 | const { 21 | reposByUser, 22 | user, 23 | } = this.props 24 | 25 | if (!reposByUser[user]) { 26 | return ( 27 |Loading
28 | ) 29 | } 30 | 31 | return ( 32 |