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