import { h, Component } from 'preact';
/** Creates a new store, which is a tiny evented state container.
* @example
* let store = createStore();
* store.subscribe( state => console.log(state) );
* store.setState({ a: 'b' }); // logs { a: 'b' }
* store.setState({ c: 'd' }); // logs { c: 'd' }
*/
export default function createStore(state={}) {
let listeners = [];
return {
setState(update) {
state = { ...state, ...update };
listeners.forEach( f => f(state) );
},
subscribe(f) {
listeners.push(f);
},
unsubscribe(f) {
let i = listeners.indexOf(f);
listeners.splice(i, !!~i);
},
getState() {
return state;
}
};
}
/** Provides its props into the tree as context.
* @example
* let store = createStore();
*
*/
export class Provider extends Component {
getChildContext() {
let { children, ...context } = this.props;
return context;
}
render({ children }) {
return children[0];
}
}
/** Wire a component up to the store. Passes state as props, re-renders on change.
* @param {Function|Array|String} mapStateToProps A function (or any `select()` argument) mapping of store state to prop values.
* @example
* const Foo = connect('foo,bar')( ({ foo, bar }) =>
)
* @example
* @connect( state => ({ foo: state.foo, bar: state.bar }) )
* export class Foo { render({ foo, bar }) { } }
*/
export function connect(mapToProps) {
if (typeof mapToProps!=='function') mapToProps = select(mapToProps);
return Child => class Wrapper extends Component {
state = this.getProps();
update = () => {
let mapped = this.getProps();
if (!shallowEqual(mapped, this.state)) {
this.setState(mapped);
}
};
getProps() {
let state = this.context.store && this.context.store.getState() || {};
return mapToProps(state);
}
componentWillMount() {
this.context.store.subscribe(this.update);
}
componentWillUnmount() {
this.context.store.unsubscribe(this.update);
}
render(props, state, context) {
return ;
}
};
}
/** select('foo,bar') creates a function of the form: ({ foo, bar }) => ({ foo, bar }) */
export function select(properties) {
if (typeof properties==='string') properties = properties.split(',');
return state => {
let selected = {};
for (let i=0; i