diff --git a/README.md b/README.md index 6ac6bcc..fb4f071 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ fit-html is a combination of [lit-html](https://github.com/Polymer/lit-html), we You need the following: ```js -import { connect, createProvider } from 'fit-html'; +import { connect, withStore } from 'fit-html'; import { html } from 'lit-html/lib/lit-extended'; import { createStore } from 'redux'; ``` @@ -33,12 +33,6 @@ const todos = (state = [], action) => { const store = createStore(todos, ['Use Redux']); ``` -Set up redux provider element (this must be at the root of your element tree): -```js -const provider = createProvider(store); -customElements.define('redux-provider', provider); -``` - Define actions and view: ```js function addTodo() { @@ -58,11 +52,14 @@ const render = ({ addTodo, todos }) => html` `; -const TodosApp = connect( +// The withStore mixin is only required for the root element of your +// app. All other 💪-elements will get the redux store from that element. + +const TodosApp = withStore(connect( state => ({ todos: state }), { addTodo }, render -); +), store); customElements.define('todo-app', TodosApp); ``` @@ -74,9 +71,7 @@ customElements.define('todo-app', TodosApp); My cool 💪-html app - - - + ``` diff --git a/package.json b/package.json index a7fe828..47e1c5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fit-html", - "version": "0.5.2", + "version": "0.5.3", "description": "5KB functional Web Components without bloat", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/connect.ts b/src/connect.ts index f2ff670..715d607 100644 --- a/src/connect.ts +++ b/src/connect.ts @@ -3,7 +3,6 @@ import { render as shadyRender } from 'lit-html/lib/shady-render'; import { bindActionCreators, ActionCreatorsMapObject, Dispatch, Store, Unsubscribe } from 'redux'; import { ClassConstructor } from '.'; -import { ProviderElement } from './provider'; /** * The function that extracts required data out of the state and the passed props. @@ -154,14 +153,13 @@ export default function connect( let node: any = this; while (node = node.parentNode || node.host) { - const maybeStore = node._store || node.reduxStore; - if (isReduxStore(maybeStore)) { - this._store = maybeStore; - return maybeStore; + if (isFunction(node.getStore)) { + this._store = node.getStore(); + return this._store; } } - throw new Error("💪-html: Missing redux store.\nSeems like you're using fit-html without a redux store. Please use the provider component to provide one to the element tree."); + throw new Error("💪-html: Missing redux store.\nSeems like you're using fit-html without a redux store. Please use a provider component to provide one to the element tree."); } getProps(ownProps = {} as OP): SP & DP { @@ -205,10 +203,6 @@ function isFunction(f: any): f is Function { return typeof f === 'function'; } -function isReduxStore(obj: any): obj is Store { - return obj && obj.getState && obj.dispatch && obj.subscribe; -} - function shallowEqual(a, b) { if (a === b) { return true; diff --git a/src/provider.ts b/src/provider.ts index 0555236..05eacce 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -1,17 +1,17 @@ import { Store } from 'redux'; -import { ClassConstructor } from '.'; +import { ClassConstructor, FitElement } from '.'; /** - * A 💪 redux store provider element. + * Creates a subclass of the given HTML element that supplies the redux store to its DOM children. * - * This element supplies the redux store to the 💪-html elements below it. + * Thus, all other 💪-elements must be a child of that element. * It works much like {@see https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store}. * * When connected to the document, 💪-elements walk the dom upwards until they * either find another 💪-element that already has an initialized redux store * or the store provider element. They then take the store from that given - * element, subscribe to it for rendering and cache it for further lookups + * element, subscribe to the store for rendering and cache it for further lookups * or potential 💪-children. * * You usually only need one per application as you would usually only use one @@ -23,40 +23,39 @@ import { ClassConstructor } from '.'; * * @example * ```html - * - * + * + * * * * - * - * - * + * + * + * * - * - * + * + * * ``` - */ -export declare class ProviderElement extends HTMLElement { - /** - * The previously created redux store to be accessible for all children. - */ - reduxStore: Store; -} - -/** - * Creates a new redux store provider element using the given store. - * - * This element supplies the redux store to the 💪-html elements below it. - * Thus, all 💪-elements must be a child of this element. * + * @param {T} clazz The base class to extend from. * @param {Store} store The redux store. * @returns {ProviderElement} The redux store provider element class. * @template S */ -export default function createProvider(store: Store): ClassConstructor> { - return class extends HTMLElement { - get reduxStore(): Store { +export function withStore, S>(clazz: T, store: Store) { + return class extends clazz { + getStore(): Store { return store; } }; } + +/** + * Creates a new HTML element that supplies the redux store to its DOM children. + * + * Thus, all other 💪-elements must be a child of that element. + * + * @param {Store} store The redux store. + * @deprecated Use `withStore` on your app shell / root element instead. + */ +export const createProvider = (store: Store) => withStore(HTMLElement, store); +export default createProvider;