Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
deamme committed Feb 15, 2018
0 parents commit 36cc879
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
node_modules
dist
yarn.lock
examples
21 changes: 21 additions & 0 deletions LICENSE
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Deam Hansen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
75 changes: 75 additions & 0 deletions README.md
@@ -0,0 +1,75 @@
# Laco (WIP)
[![npm version](https://badge.fury.io/js/laco.svg)](https://badge.fury.io/js/laco)

Very simple and powerful state management solution for React and Inferno.

Set up your stores and subscribe to them. Easy as that!

## Summary
- :rocket: Simple to use
- :tada: Lightweight (under 1kb in size)
- :sparkles: [Redux DevTools Extension support](https://github.com/zalmoxisus/redux-devtools-extension) (time travel, persist state etc.)

## Example
```javascript
import { render } from 'inferno' // or 'react-dom'
import { Store, Subscribe } from 'laco'

// Creating a new store with an initial state { count: 0 }
const CounterStore = new Store({ count: 0 })

// Utility function to get the state of the store
const getState = () => CounterStore.getState()

// Implementing some actions to update the store
const increment = () => CounterStore.setState({ count: getState().count + 1 })
const decrement = () => CounterStore.setState({ count: getState().count - 1 })

const Counter = () => (
<Subscribe to={[CounterStore]}>
{(state) => (
<button onClick={decrement}>-</button>
<span>{state.count}</span>
<button onClick={increment}>+</button>
)}
</Subscribe>
)

render(<Counter />, document.getElementById('root'))
```

For more examples check the examples folder.

Following commands are available for each example project:

`npm run start:dev`

`npm run start:prod`

## API
### `Store`
#### Arguments
1. [Required] - Object
2. [Optional] - String
```javascript
// Initializing with an initial state and a name:
const NewStore = Store({ count: 0 }, "Counter")
```
The name is optional and is used to get an overview of action and store relationship in Redux DevTools Extension. Action names for the Store will now show up as `Counter - ${actionType}` in DevTools Extension where as before only `${actionType}`.

### `Store.setState()`
#### Arguments
1. [Required] - Function or Object
2. [Optional] - String
```javascript
// Setting a new state and passing an optional action name "increment"
Store.setState({ count: getState().count + 1 }, "increment")
```
Immutability is taking care of to a certain extent behind the scenes with the spread operator but you may want more control over the state. You can do this by passing a function like so:
```javascript
// Setting a new state and passing an optional action name "increment"
Store.setState((state) => { /* return modified state */}, "increment")
```

## Credits
Heavily inspired by [Unstated](https://github.com/jamiebuilds/unstated)
109 changes: 109 additions & 0 deletions index.ts
@@ -0,0 +1,109 @@
export let Component

try {
Component = require("inferno").Component
} catch (error) { /* Fail silent */ }
try {
Component = require("react").Component
} catch (error) { /* Fail silent */ }

if (!Component) {
throw 'Please require Inferno or React'
}

if (process.env.NODE_ENV !== 'production') {
console.error(`You're currently using a development version of Laco`)
}

let STORE = {}
let COUNTER = 0

if (process.env.NODE_ENV !== 'production') {
if ((window as any).__REDUX_DEVTOOLS_EXTENSION__) {
(window as any).__LACO_TOOLS__ = (window as any).__REDUX_DEVTOOLS_EXTENSION__.connect()
}
}

export class Store {
idx
name = ''
_listeners = []
devTools

constructor(initialState: Object, name?: string) {
if (name) this.name = name
this.idx = COUNTER++
STORE[this.idx] = initialState
}

getGlobalStore() {
return STORE
}

getState() {
return STORE[this.idx]
}

setState(state: Object | Function, info?: String) {
STORE[this.idx] = typeof state === 'function'
? state(STORE[this.idx])
: { ...STORE[this.idx], ...state }

if (process.env.NODE_ENV !== 'production') {
if ((window as any).__LACO_TOOLS__) {
(window as any).__LACO_TOOLS__.send(
this.name ? this.name + ' - ' + info : info,
STORE
)
}
}

this._listeners.forEach(fn => fn())
}

subscribe(fn) {
this._listeners.push(fn)
}

unsubscribe(fn) {
this._listeners = this._listeners.filter(f => f !== fn)
}
}

export class Subscribe extends Component<any, any> {
stores = []

componentWillReceiveProps() {
this._unsubscribe()
}

componentWillUnmount() {
this._unsubscribe()
}

_unsubscribe() {
this.stores.forEach(store => {
store.unsubscribe(this.onUpdate)
})
}

onUpdate = () => {
this.setState({})
}

render() {
let stores = []

const states = this.props.to.map(store => {
store.unsubscribe(this.onUpdate)
store.subscribe(this.onUpdate)

stores.push(store)

return store.getState()
})

this.stores = stores
return (this.props as any).children(...states)
}
}
16 changes: 16 additions & 0 deletions package.json
@@ -0,0 +1,16 @@
{
"name": "laco",
"version": "0.0.1",
"description": "Simple and powerful state management for React and Inferno",
"main": "index.js",
"repository": "https://github.com/deamme/laco.git",
"author": "Deam <deamkh@gmail.com>",
"license": "MIT",
"scripts": {
"build": "tsc",
"prepublishOnly": "rimraf dist && tsc"
},
"devDependencies": {
"typescript": "^2.7.1"
}
}
20 changes: 20 additions & 0 deletions tsconfig.json
@@ -0,0 +1,20 @@

{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"stripInternal": true,
"jsx": "preserve",
"outDir": "dist",
"lib": [ "es2015", "dom"]
},
"files": [
"index.ts"
],
}

0 comments on commit 36cc879

Please sign in to comment.