[
  {
    "path": ".github/FUNDING.yml",
    "content": "patreon: yezyilomo\n"
  },
  {
    "path": ".github/workflows/node.js.yml",
    "content": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [16.x, 18.x, 19.x, 20.x]\n        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v2\n      with:\n        node-version: ${{ matrix.node-version }}\n    - run: npm ci\n    - run: npm test  # Run tests \n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n/dist\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Yezy Ilomo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# [State Pool](https://yezyilomo.github.io/state-pool/)\n\n![Build Status](https://github.com/yezyilomo/state-pool/actions/workflows/node.js.yml/badge.svg?branch=master)\n[![Build Size](https://img.shields.io/bundlephobia/minzip/state-pool?label=bundle-size&style=flat)](https://bundlephobia.com/result?p=state-pool)\n[![Version](https://img.shields.io/npm/v/state-pool?style=flat)](https://www.npmjs.com/package/state-pool)\n[![Downloads](https://img.shields.io/npm/dt/state-pool.svg?style=flat)](https://www.npmjs.com/package/state-pool)\n\nTransform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨\n\n## Features & Advantages\n- Simple, familiar, flexible and very minimal core API but powerful\n- Built-in support for state persistence\n- Very easy to learn because its API is very similar to react state hook's API\n- Support selecting deeply nested state\n- Support creating state dynamically\n- Can be used outside react components\n- Doesn't wrap your app in context providers\n- Very organized API, You can do almost everything with a single import\n\nWant to see how this library is making all that possible?\n\nCheck out the full documentation at [yezyilomo.github.io/state-pool](https://yezyilomo.github.io/state-pool/)\n\nYou can also try live examples [Here](https://yezyilomo.github.io/state-pool-examples)\n<br/>\n\n## How it Works\n1. Create a state\n\n2. Subscribe a component(s) to the state created\n\n3. If a component wants to update the state, it sends update request\n\n4. When a state receives update request, it performs the update and send signal to all components subscribed to it for them to update themselves(re-render)\n\n<br/>\n\n## Installation\n```sh\nnpm install state-pool\n```\n\nOr \n\n```sh\nyarn add state-pool\n```\n\n<br/>\n\n## Getting Started\nUsing **state-pool** to manage state is very simple, all you need to do is\n1. Create and initialize a state by using `createState`\n2. Use your state in your component through `useState` hooks\n\nThese two steps summarises pretty much everything you need to use **state-pool**.\n\nBelow are few examples showing how to use **state-pool** to manage states.\n\n```jsx\n// Example 1.\nimport React from 'react';\nimport { createState } from 'state-pool';\n\n\nconst count = createState(0);  // Create \"count\" state and initialize it with 0\n\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = count.useState();\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\nThe other way to do it is using `useState` from `state-pool`\n```jsx\n// Example 2.\nimport React from 'react';\nimport { createState, useState } from 'state-pool';\n\n\nconst count = createState(0);  // Create \"count\" state and initialize it with 0\n\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = useState(count);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\n## What about local state?\nWith **state-pool**, state are just like variables, if declared on a global scope, it’s a global state and if declared on local scope it’s a local state, so the difference between global state and local state in **state-pool** lies where you declare them just like variables.\n\nHere is an example for managing local state\n```jsx\n// Example 1.\nimport React from 'react';\nimport { useState } from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    // Note: the `useState` hook used here is impored from state-pool and not react\n    const [count, setCount] = useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n<br/>\n\nIf you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,\n\nHere is an example\n```jsx\n// Example 2.\nimport React from 'react';\nimport StatePool from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    const [count, setCount] = StatePool.useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\n## Isn't `StatePool.useState` the same thing as `React.useState`?\n**Definitely. not!...**\n\nBoth can be used to manage local state, and that's where the similarity ends. `StatePool.useState` offers more features, for one it offers a simple way to update nested data unlike `React.useState`, it's also flexible as it's used to manage both global state and local state. So you could say `React.useState` is a subset of `StatePool.useState`.\n\nHere is an example of `StatePool.useState` in action, updating nested data\n```jsx\n// Example 2.\nimport React from 'react';\nimport StatePool from 'state-pool';\n\n\nconst user = StatePool.createState({name: \"Yezy\", age: 25});\n\nfunction UserInfo(props){\n    const [user, setUser, updateUser] = StatePool.useState(user);\n\n    const updateName = (e) => {\n        updateUser(user => {\n            user.name = e.target.value;\n        });\n    }\n\n    return (\n        <div>\n            Name: {user.name}\n            <br/>\n            <input type=\"text\" value={user.name} onChange={updateName}/>\n        </div>\n    );\n}\n\nReactDOM.render(UserInfo, document.querySelector(\"#root\"));\n```\n\nWith `React.useState` you would need to recreate `user` object when updating `user.name`, but with `StatePool.useState` you don't need that, you just update the value right away. \n\nThat's one advantage of using `StatePool.useState` but there are many more, you'll learn when going through [**documentation**📝](https://yezyilomo.github.io/state-pool/).\n\n\n\n## Store based example\nIf you have many states and you would like to organize them into a store, **state-pool** allows you to do that too and provides a ton of features on top of it.\n\nHere are steps for managing state with a store\n1. Create a store(which is basically a container for your state)\n1. Create and initialize a state by using `store.setState`\n2. Use your state in your component through `store.useState` hooks\n\nThese three steps summarises pretty much everything you need to manage state with a store.\n\nBelow are few examples of store in action\n\n```jsx\n// Example 1.\nimport { createStore } from 'state-pool';\n\n\nconst store = createStore();  // Create store for storing our state\nstore.setState(\"count\", 0);  // Create \"count\" state and add it to the store\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = store.useState(\"count\");\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={e => setCount(++count)}>Click</button>\n        </div>\n    );\n}\n```\n\n<br/>\n\n```jsx\n// Example 2.\nimport { createStore } from 'state-pool';\n\n\n// Instead of using createStore and store.setState,\n// you can combine store creation and initialization as follows\n\nconst store = createStore({\"user\", {name: \"Yezy\", age: 25}});  // create store and initialize it with user\n\nfunction UserInfo(props){\n    const [user, setUser, updateUser] = store.useState(\"user\");\n\n    const updateName = (e) => {\n        updateUser(user => {\n            user.name = e.target.value;\n        });\n    }\n\n    return (\n        <div>\n            Name: {user.name}\n            <br/>\n            <input type=\"text\" value={user.name} onChange={updateName}/>\n        </div>\n    );\n}\n```\n\n<br/>\n\n**State-pool** doesn't enforce storing your states in a store, If you don't like using the architecture of store you can still use **state-pool** without it. In **state-pool**, store is just a container for states, so you can still use your states without it, in fact **state-pool** doesn’t care where you store your states as long as you can access them you're good to go.\n\n<br/>\n\nPretty cool, right?\n\n\n## [Documentation 📝](https://yezyilomo.github.io/state-pool/)\nFull documentation for this project is available at [yezyilomo.github.io/state-pool](https://yezyilomo.github.io/state-pool/), you are advised to read it inorder to utilize this library to the fullest. You can also try live examples [here](https://yezyilomo.github.io/state-pool-examples).\n\n\n## Running Tests\nIf you've forked this library and you want to run tests use the following command\n\n```sh\nnpm test\n```\n"
  },
  {
    "path": "babel.config.js",
    "content": "// babel.config.js\nmodule.exports = {\n    presets: ['@babel/preset-env', '@babel/preset-react'],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"state-pool\",\n    \"private\": true,\n    \"version\": \"0.10.2\",\n    \"description\": \"Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://github.com/yezyilomo/state-pool/blob/master/README.md\",\n    \"repository\": \"https://github.com/yezyilomo/state-pool\",\n    \"bugs\": \"https://github.com/yezyilomo/state-pool/issues\",\n    \"keywords\": [\n        \"state\",\n        \"immutable\"\n    ],\n    \"authors\": [\n        \"Yezileli Ilomo <yezileliilomo@hotmail.com> (https://github.com/yezyilomo)\"\n    ],\n    \"main\": \"index.js\",\n    \"module\": \"esm/index.js\",\n    \"types\": \"index.d.ts\",\n    \"files\": [\n        \"**\"\n    ],\n    \"sideEffects\": false,\n    \"scripts\": {\n        \"prebuild\": \"shx rm -rf dist\",\n        \"build\": \"tsc\",\n        \"postbuild\": \"npm run copy\",\n        \"test\": \"shx rm -rf dist && tsc && jest ./dist/test && shx rm -rf dist\",\n        \"copy\": \"shx mkdir dist/esm && shx cp -r dist/src/* dist/esm && shx mv dist/src/* dist && shx rm -rf dist/{src,tests} && shx cp package.json README.md LICENSE dist && json -I -f dist/package.json -e \\\"this.private=false; this.devDependencies=undefined; this.scripts=undefined;\\\"\",\n        \"publish:dist\": \"npm run build && cd dist && npm publish\"\n    },\n    \"exports\": {\n        \"./package.json\": \"./package.json\",\n        \".\": {\n            \"types\": \"./index.d.ts\",\n            \"module\": \"./esm/index.js\",\n            \"import\": \"./esm/index.js\",\n            \"default\": \"./index.js\"\n        }\n    },\n    \"dependencies\": {\n        \"immer\": \">=10.0.0\"\n    },\n    \"peerDependencies\": {\n        \"react\": \">=16.8.3\"\n    },\n    \"devDependencies\": {\n        \"@babel/preset-env\": \"latest\",\n        \"@babel/preset-react\": \"latest\",\n        \"@testing-library/react-hooks\": \"latest\",\n        \"@types/jest\": \"latest\",\n        \"@babel/eslint-parser\": \"latest\",\n        \"babel-jest\": \"latest\",\n        \"jest\": \"latest\",\n        \"json\": \"latest\",\n        \"react\": \"latest\",\n        \"react-test-renderer\": \"latest\",\n        \"shx\": \"latest\",\n        \"typescript\": \"latest\"\n    }\n}\n"
  },
  {
    "path": "src/State.ts",
    "content": "import { produce, nothing } from \"immer\";\nimport {\n    StateInitializer, Selector, Patcher,\n    Reducer, Unsubscribe, StateModifier,\n    StateUpdater, SetState, UpdateState,\n} from './types';\nimport _useState from \"./useState\";\nimport _useReducer from \"./useReducer\";\n\n\n\ntype Refresh = () => void\n\n// Might subscribe to derived/selected state, so we use <ST> cuz it might not always be <T>\ntype Observer<ST> = (newState: ST) => void\n\n// Subscribe to a state\ntype Subscriber<ST> = {\n    observer: Observer<ST>,\n    selector: Selector<ST>,\n    refresh?: Refresh\n}\n\n\nexport default class State<T> {\n    private value: T;\n    private subscribers: Array<Subscriber<unknown>>;\n\n    constructor(initialValue: StateInitializer<T> | T) {\n        if (typeof initialValue === \"function\") {\n            this.value = (initialValue as StateInitializer<T>)();\n        }\n        else {\n            this.value = initialValue as T;\n        }\n        this.subscribers = [];\n    }\n\n    getValue<ST>(selector?: Selector<ST>): T | ST {\n        if (selector) {\n            return selector(this.value);\n        }\n        return this.value;\n    }\n\n    refresh(): void {\n        this.subscribers.forEach(subscriber => {\n            if (subscriber.refresh) {\n                subscriber.refresh();\n            }\n        });\n    }\n\n    setValue(\n        newValue: T | StateUpdater<T>\n    ): void;\n\n    setValue<ST>(\n        newValue: ST | StateUpdater<ST>,\n        config: { selector?: Selector<ST> }\n    ): void;\n\n    setValue<ST>(\n        newValue: ST | StateUpdater<ST>,\n        config: { selector?: Selector<ST>, patcher?: Patcher<ST> },\n    ): void;\n\n    setValue<ST>(\n        newValue: (T | ST) | StateUpdater<T | ST>,\n        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},\n    ): void {\n        if (newValue === undefined) {\n            this.__updateValue<T | ST>(\n                (draftVal) => nothing as undefined,  // nothing is equivalent to undefined\n                config\n            )\n        }\n        else if (typeof newValue === 'function') {\n            const reducer = newValue as StateUpdater<T | ST>\n\n            this.setValue(\n                reducer(this.getValue(config.selector)), config\n            )\n        }\n        else {\n            this.__updateValue<T | ST>(\n                (draftVal) => newValue,\n                config\n            )\n        }\n    }\n\n\n    updateValue(\n        stateModifier: StateModifier<T>\n    ): void;\n\n    updateValue<ST>(\n        stateModifier: StateModifier<ST>,\n        config: { selector?: Selector<ST> }\n    ): void;\n\n    updateValue<ST>(\n        stateModifier: StateModifier<ST>,\n        config: { selector?: Selector<ST>, patcher?: Patcher<ST> }\n    ): void;\n\n    updateValue<ST>(\n        stateModifier: StateModifier<T> | StateModifier<ST>,\n        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},\n    ): void {\n        const stateModifierWrapper = function (draftState) {\n            // This wrapper is for disabling setting returned value\n            // We don't allow returned value to be set(just return undefined)\n            stateModifier(draftState)\n        }\n\n        this.__updateValue<ST>(stateModifierWrapper, config)\n    }\n\n    private __updateValue<ST>(stateUpdater: StateUpdater<T | ST> | StateModifier<T | ST>, config): void {\n        // No need to do a lot of type checking here bcuz this is an internal method\n        const selector = config.selector as Selector<ST>;\n        const patcher = config.patcher as Patcher<ST>;\n\n        const oldState = this.value;\n\n        let newState: T;\n        if (selector && patcher) {\n            // Update the selected node first and get its value\n            const selectedNodeValue: ST = produce(selector(oldState), stateUpdater) as ST;\n\n            // Here we're patching back the updated selected node to the main state\n            newState = produce(\n                oldState,\n                (draftCurrentState: T) => {\n                    // Avoid setting returns\n                    patcher(draftCurrentState, selectedNodeValue);\n                }\n            )\n        }\n        else {\n            newState = produce(oldState, stateUpdater);\n        }\n\n        this.value = newState;\n\n        if (newState !== oldState) {\n            // There's a new update\n            this.subscribers.forEach(subscriber => {\n                if (subscriber.selector(newState) !== subscriber.selector(oldState)) {\n                    // Node value has changed\n                    subscriber.observer(\n                        subscriber.selector(newState)\n                    );\n                }\n            });\n        }\n    }\n\n    subscribe<ST>(itemToSubscribe: Subscriber<T | ST> | Observer<T | ST>): Unsubscribe {\n        let _itemToSubscribe;\n        if (typeof itemToSubscribe === 'function') {\n            const selector: Selector<T> = (state) => state;\n            _itemToSubscribe = {\n                observer: itemToSubscribe as Observer<T>,\n                selector: selector\n            } as Subscriber<T>;\n        }\n        else {\n            _itemToSubscribe = itemToSubscribe as Subscriber<ST>;\n        }\n\n        if (this.subscribers.indexOf(_itemToSubscribe) === -1) {\n            // Subscribe a component to this state\n            this.subscribers.push(_itemToSubscribe);\n        };\n\n        const unsubscribe = () => {\n            this.subscribers = this.subscribers.filter(\n                subscriber => (subscriber !== _itemToSubscribe)\n            );\n        }\n\n        return unsubscribe;\n    }\n\n    select<ST>(selector: Selector<ST>): DerivedState<T, ST> {\n        return createDerivedState(this, selector);\n    }\n\n\n    useState(config?: {}): [\n        state: T,\n        setState: SetState<T>,\n        updateState: UpdateState<T>,\n        stateObject: State<T>\n    ];\n\n    useState<ST>(\n        config: { selector: Selector<ST> },\n    ): [\n            state: ST,\n            setState: SetState<T>,\n            updateState: UpdateState<T>,\n            stateObject: State<T>\n        ];\n\n    useState<ST>(\n        config: { selector: Selector<ST>, patcher: Patcher<ST> },\n    ): [\n            state: ST,\n            setState: SetState<ST>,\n            updateState: UpdateState<ST>,\n            stateObject: State<T>\n        ]\n\n    useState<ST>(\n        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},\n    ): [\n            state: T | ST,\n            setState: SetState<T | ST>,\n            updateState: UpdateState<T | ST>,\n            stateObject: State<T>\n        ] {\n        return _useState(this, config);\n    }\n\n\n    useReducer<_T extends T, A>(\n        reducer: Reducer<_T, A>,\n        config?: {}\n    ): [\n            state: _T,\n            dispatch: (action: A) => void,\n            stateObject: State<_T>\n        ];\n\n    useReducer<ST, A>(\n        reducer: Reducer<ST, A>,\n        config: { selector: Selector<ST> }\n    ): [\n            state: ST,\n            dispatch: (action: A) => void,\n            stateObject: State<T>\n        ];\n\n    useReducer<ST, A>(\n        reducer: Reducer<ST, A>,\n        config: { selector: Selector<ST>, patcher: Patcher<ST> }\n    ): [\n            state: ST,\n            dispatch: (action: A) => void,\n            stateObject: State<T>\n        ]\n\n    useReducer(\n        reducer: Reducer<unknown, unknown>,\n        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {}\n    ): [\n            state: unknown,\n            dispatch: (action: unknown) => void,\n            stateObject: State<unknown>\n        ] {\n        return _useReducer(reducer, this, config);\n    }\n}\n\n\nexport class DerivedState<T, ST> {\n    State: State<unknown>;\n    selector: Selector<ST>;\n\n    constructor(State: State<unknown>, selector: Selector<ST>) {\n        this.State = State;\n        this.selector = selector;\n    }\n\n    getValue(): ST {\n        return this.State.getValue(this.selector) as ST;\n    }\n\n    subscribe(observer?: Observer<ST>, refresh?: Refresh): Unsubscribe {\n        const itemToSubscribe: Subscriber<ST> = {\n            observer: observer,\n            selector: this.selector,\n            refresh: refresh\n        }\n\n        return this.State.subscribe(itemToSubscribe);\n    }\n}\n\n\nexport function createDerivedState<T, ST>(State: State<T>, selector: Selector<ST>): DerivedState<T, ST> {\n    return new DerivedState<T, ST>(State, selector);\n}\n\n\nexport function createState<T>(initialValue: StateInitializer<T> | T): State<T> {\n    return new State<T>(initialValue);\n}"
  },
  {
    "path": "src/Store.ts",
    "content": "import State, { createState } from './State';\nimport {\n    StateInitializer, Selector, Patcher,\n    Reducer, SetState, Unsubscribe, UpdateState\n} from './types';\n\n\n\n// Observer function for a store\ntype StoreObserver = (key: string, value: unknown) => void\n\ntype PersistenceConfig = {\n    saveState: (key: string, state: unknown, isInitialSet: boolean) => void,\n    loadState: (key: string, noState: Empty) => unknown,\n    removeState?: (key: string) => void,\n    clear?: () => void,\n    PERSIST_ENTIRE_STORE?: boolean\n}\n\ntype StoreState<T> = {\n    state: State<T>,\n    unsubscribe: Unsubscribe,\n    persist: boolean\n}\n\ntype StoreInitializer = { [key: string]: unknown } | (() => { [key: string]: unknown });\n\n\nconst notImplementedErrorMsg = [\n    `You must implement 'loadState' and 'saveState' to be able `,\n    'to save state to your preffered storage. E.g \\n',\n    'store.persist({ \\n',\n    '    saveState: function(key, state, isInitialSet){/*Code to save state to your storage*/}, \\n',\n    '    loadState: function(key, noState){/*Code to load state from your storage*/} \\n',\n    '}) \\n'\n].join(\"\");\n\n\nclass Empty { }  // Class for empty state/value\nconst EMPTY = new Empty();\n\nclass PersistentStorage {\n    SHOULD_PERSIST_BY_DEFAULT: boolean = false;\n\n    loadState(key: string, noState: Empty): unknown {\n        throw TypeError(notImplementedErrorMsg);\n    }\n\n    saveState(key: string, state: unknown, isInitialSet?: boolean) {\n        throw TypeError(notImplementedErrorMsg);\n    }\n\n    removeState: (key: string) => void\n\n    clear: () => void\n}\n\n\nexport default class Store {\n    private states: Map<string, StoreState<unknown>>;\n    private subscribers: Array<StoreObserver>;\n    private persistentStorage: PersistentStorage;\n\n    constructor(storeInitializer?: StoreInitializer) {\n        this.states = new Map();\n        this.subscribers = [];\n        this.persistentStorage = new PersistentStorage();\n\n        if (storeInitializer) {\n            if (typeof storeInitializer === \"function\") {\n                storeInitializer = storeInitializer();\n            }\n\n            for (let key in storeInitializer) {\n                if (storeInitializer.hasOwnProperty(key)) {\n                    this.setState(key, storeInitializer[key]);\n                }\n            }\n        }\n    }\n\n    subscribe(observer: StoreObserver): () => void {\n        if (this.subscribers.indexOf(observer) === -1) {\n            // Subscribe a component to this store\n            this.subscribers.push(observer);\n        }\n\n        const unsubscribe = () => {\n            this.subscribers = this.subscribers.filter(\n                subscriber => subscriber !== observer\n            );\n        }\n\n        return unsubscribe\n    }\n\n    private onStoreUpdate(key: string, value: unknown): void {\n        this.subscribers.forEach(subscriber => {\n            subscriber(key, value);\n        });\n    }\n\n    persist(config: PersistenceConfig): void {\n        if (config.saveState) {\n            this.persistentStorage.saveState = config.saveState;\n        }\n        if (config.loadState) {\n            this.persistentStorage.loadState = config.loadState;\n        }\n        if (config.removeState) {\n            this.persistentStorage.removeState = config.removeState;\n        }\n        if (config.clear) {\n            this.persistentStorage.clear = config.clear;\n        }\n        if (config.PERSIST_ENTIRE_STORE) {\n            this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT = config.PERSIST_ENTIRE_STORE;\n        }\n    }\n\n    setState<T>(\n        key: string,\n        initialValue: StateInitializer<T> | T,\n        { persist }: { persist?: boolean } = {}\n    ): void {\n\n        const shouldPersist: boolean = persist === undefined ?\n            this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT : persist;\n\n        let shouldSaveToPersistentStorage = false;\n\n        if (shouldPersist) {\n            // Try to load state from persistent storage\n            const savedState = this.persistentStorage.loadState(key, EMPTY);\n\n            if (savedState !== EMPTY) {\n                // We have a saved state, so we use it as the initialValue\n                initialValue = savedState as T;\n            }\n            else {\n                // We don't have a saved state so we have to set/save it\n                // Here we set this flag to true but we'll save later after creating a state successfully\n                shouldSaveToPersistentStorage = true;\n            }\n        }\n\n\n        const onStateChange = (newValue: unknown) => {\n            // Note key & persist variables depends on scope\n\n            this.onStoreUpdate(key, newValue);\n\n            if (shouldPersist) {\n                this.persistentStorage.saveState(key, newValue, false);\n            }\n        }\n\n        // Create a state\n        const state: State<T> = createState<T>(initialValue);\n        const unsubscribe = state.subscribe({\n            observer: onStateChange,\n            selector: (st) => st\n        });\n        const storeState = {\n            \"state\": state,\n            \"unsubscribe\": unsubscribe,\n            \"persist\": shouldPersist\n        }\n        // Add state to the store\n        this.states.set(key, storeState);\n\n        if (shouldSaveToPersistentStorage) {\n            // Saving state to persistent storage after we've created it successfully\n            this.persistentStorage.saveState(key, state.getValue(), true);\n        }\n    }\n\n    getState<T>(\n        key: string,\n        config: { default?: StateInitializer<T> | T, persist?: boolean } = {}\n    ): State<T> {\n        let defaultValue;\n        if (config.hasOwnProperty('default')) {\n            // Use has set default explicitly\n            defaultValue = config.default\n        }\n        else {\n            // No default value\n            defaultValue = EMPTY;\n        }\n\n        // Get key based state\n        if (!this.has(key)) {  // state is not found\n            if (defaultValue !== EMPTY) {  // Default value is found\n                // Create a state and use defaultValue as the initial value\n                this.setState<T>(\n                    key,\n                    defaultValue as (StateInitializer<T> | T),  // Make sure we don't pass EMPTY value\n                    { persist: config.persist }\n                );\n            }\n            else {\n                // state is not found and the default value is not specified\n                const errorMsg = [\n                    `There is no state with the key '${key}', `,\n                    `You are either trying to access a `,\n                    `state that doesn't exist or it was deleted.`\n                ];\n                throw Error(errorMsg.join(\"\"));\n            }\n        }\n        return this.states.get(key).state as State<T>;\n    }\n\n    has(key: string) {\n        // Check if we have a state in a store\n        return this.states.has(key);\n    }\n\n    items(): Array<[key: string, state: unknown, persist: boolean]> {\n        const storeItems = [];\n        this.states.forEach((storeState, key) => {\n            storeItems.push([key, storeState.state.getValue(), storeState.persist]);\n        })\n        return storeItems;\n    }\n\n    getStateValue<ST, T = unknown>(key: string, selector?): T | ST {\n        const state = this.getState<T>(key);\n        return state.getValue<ST>(selector);\n    }\n\n    clear(fn?: () => void): void {\n        // Copy store\n        const storeCopy = this.states;\n\n        // Clear store\n        this.states = new Map();\n        if (this.persistentStorage.clear) {\n            try {\n                this.persistentStorage.clear()\n            } catch (error) {\n                // Ignore errors in clearing states\n            }\n        }\n\n        if (fn) {\n            // Run store re-initialization\n            fn();\n        }\n\n        storeCopy.forEach((oldState, key) => {\n            // Unsubscribe from an old state \n            oldState.unsubscribe()\n            // Notify subscribers to a store that a state has been removed\n            if (this.has(key)) {\n                const newState = this.getState(key);\n                this.onStoreUpdate(key, newState.getValue());\n            }\n            // Rerender all components using this state\n            oldState.state.refresh();\n        })\n    }\n\n    remove(Statekey: string | string[], fn?: () => void): void {\n        let keys: string[] = [];\n        if (typeof Statekey === 'string') {\n            keys = [Statekey];\n        }\n        else {\n            keys = Statekey;\n        }\n\n        const StatesToRemove: Map<string, StoreState<unknown>> = new Map();\n        keys.forEach(key => {\n            // Copy state to remove from a store\n            StatesToRemove.set(key, this.states.get(key));\n\n            // Remove state from a store\n            this.states.delete(key);\n            if (\n                StatesToRemove.get(key).persist &&  // Is state persisted\n                this.persistentStorage.removeState  // Is removeState Implemented\n            ) {\n                try {\n                    this.persistentStorage.removeState(key);\n                } catch (error) {\n                    // Ignore error in removing state\n                }\n            }\n        });\n\n        if (fn) {\n            // Run state re-initialization\n            fn();\n        }\n\n        StatesToRemove.forEach((oldState, key) => {\n            // Unsubscribe from an old state \n            oldState.unsubscribe()\n            // Notify subscribers to a store that a state has been removed\n            if (this.has(key)) {\n                const newState = this.getState(key);\n                this.onStoreUpdate(key, newState.getValue());\n            }\n\n            // Rerender all components depending on this state\n            oldState.state.refresh();\n        })\n    }\n\n\n    useState<T>(\n        key: string,\n        config?: { default?: StateInitializer<T> | T, persist?: boolean }\n    ): [\n            state: T,\n            setState: SetState<T>,\n            updateState: UpdateState<T>,\n            stateObject: State<T>\n        ];\n\n    useState<ST, T>(\n        key: string,\n        config: { selector: Selector<ST>, default?: StateInitializer<T> | T, persist?: boolean },\n    ): [\n            state: ST,\n            setState: SetState<T>,\n            updateState: UpdateState<T>,\n            stateObject: State<T>\n        ];\n\n    useState<ST, T>(\n        key: string,\n        config: { selector: Selector<ST>, patcher: Patcher<ST>, default?: StateInitializer<T> | T, persist?: boolean },\n    ): [\n            state: ST,\n            setState: SetState<ST>,\n            updateState: UpdateState<ST>,\n            stateObject: State<T>\n        ]\n\n    useState(\n        key: string,\n        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown>, default?: unknown, persist?: boolean } = {}\n    ): [\n            state: unknown,\n            setState: SetState<unknown>,\n            updateState: UpdateState<unknown>,\n            stateObject: State<unknown>\n        ] {\n        const storeStateConfig = config as { default?, persist?};\n        const stateConfig = config as { selector?, patcher?};\n\n        const state = this.getState(key, storeStateConfig);\n        return state.useState(stateConfig);\n    }\n\n\n    useReducer<T, A>(\n        reducer: Reducer<T, A>,\n        key: string,\n        config?: { default?: StateInitializer<T> | T, persist?: boolean }\n    ): [\n            state: T,\n            dispatch: (action: A) => void,\n            stateObject: State<T>\n        ];\n\n    useReducer<ST, A, T = unknown>(\n        reducer: Reducer<ST, A>,\n        key: string,\n        config: { selector?: Selector<ST>, default?: StateInitializer<T> | T | never, persist?: boolean }\n    ): [\n            state: ST,\n            dispatch: (action: A) => void,\n            stateObject: State<T>\n        ];\n\n    useReducer<ST, A, T = unknown>(\n        reducer: Reducer<ST, A>,\n        key: string,\n        config: { selector?: Selector<ST>, patcher?: Patcher<ST>, default?: StateInitializer<T> | T | never, persist?: boolean }\n    ): [\n            state: ST,\n            dispatch: (action: A) => void,\n            stateObject: State<T>\n        ]\n\n    useReducer(\n        reducer: Reducer<unknown, unknown>,\n        key: string,\n        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown>, default?: unknown, persist?: boolean } = {}\n    ): [\n            state: unknown,\n            dispatch: unknown,\n            stateObject: State<unknown>\n        ] {\n        const storeStateConfig = config as { default?, persist?};\n        const stateConfig = config as { selector?, patcher?};\n\n        const state = this.getState(key, storeStateConfig);\n        return state.useReducer(reducer, stateConfig);\n    }\n}\n\n\nexport function createStore(storeInitializer?: StoreInitializer): Store {\n    // Create a store for key based state\n    return new Store(storeInitializer);\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import State, { createState, DerivedState, createDerivedState } from './State';\nimport Store, { createStore } from './Store';\nimport useReducer from './useReducer';\nimport useState from './useState';\n\n\nexport {\n    State, createState,\n    Store, createStore,\n    useState, useReducer,\n    DerivedState, createDerivedState,\n};\n\n\nconst StatePool = {\n    State, createState,\n    Store, createStore,\n    useState, useReducer,\n    DerivedState, createDerivedState,\n}\n\nexport default StatePool;"
  },
  {
    "path": "src/types.ts",
    "content": "// Note; In all cases ST stands for type of selected state and T for base/original state\n\n// Function to call to unsubscribe from a state or a store\nexport type Unsubscribe = () => void\n\n// Reducer tha's passed in useReducer hook\nexport type Reducer<ST, A> = (state: ST, action: A) => ST\n\n// What's important is the type of what's returned, lib is the one passing state, so noworries\nexport type Selector<ST> = (state: any) => ST\n\n// What's important is the type of value(to set), the lib is the one passing state, so noworries\nexport type Patcher<ST> = (state: any, value: ST) => void\n\n// Function for initializing state\nexport type StateInitializer<T> = () => T\n\n// What's important is the export type of what's returned, lib is the one passing state\nexport type StateUpdater<ST> = (state: ST) => ST\n\n// Given the obj to modify, it does modifications and return nothing\nexport type StateModifier<ST> = (state: ST) => void\n\n// Setter returned by useState hook\nexport type SetState<ST> = (newState: ST | StateUpdater<ST>) => void\n\n// Updater returned by useState hook\nexport type UpdateState<ST> = (updater: StateModifier<ST>) => void"
  },
  {
    "path": "src/useReducer.ts",
    "content": "import React from 'react';\nimport State, { createState } from './State';\nimport { Patcher, Reducer, Selector, StateInitializer } from './types';\n\n\n\nfunction useStateObject(state) {\n    // This is for internal use only\n    const localStateRef = React.useMemo(() => {\n        if (state instanceof State) {\n            // We have a global state, so we'll simply pass it out\n            return null;\n        }\n        else {\n            // We have a local state, so we create state obj and keep its ref for futer renders\n            return createState(state);\n        }\n    }, [])\n\n    let stateObject: State<unknown>;\n    if (localStateRef instanceof State) {\n        stateObject = localStateRef;\n    }\n    else {\n        stateObject = state as State<unknown>;\n    }\n\n    return stateObject;\n}\n\n\nexport default function useReducer<T, A>(\n    reducer: Reducer<T, A>,\n    state: State<T> | StateInitializer<T> | T,\n    config?: {}\n): [\n        state: T,\n        dispatch: (action: A) => void,\n        stateObject: State<T>\n    ];\n\nexport default function useReducer<ST, A, T = unknown>(\n    reducer: Reducer<ST, A>,\n    state: State<T | never> | StateInitializer<T> | T,\n    config: { selector: Selector<ST> }\n): [\n        state: ST,\n        dispatch: (action: A) => void,\n        stateObject: State<T>\n    ];\n\nexport default function useReducer<ST, A, T = unknown>(\n    reducer: Reducer<ST, A>,\n    state: State<T | never> | StateInitializer<T> | T,\n    config: { selector: Selector<ST>, patcher: Patcher<ST> }\n): [\n        state: ST,\n        dispatch: (action: A) => void,\n        stateObject: State<T>\n    ];\n\nexport default function useReducer(\n    reducer: Reducer<unknown, unknown>,\n    state: State<unknown> | unknown,\n    config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {}\n): [\n        state: unknown,\n        dispatch: unknown,\n        stateObject: State<unknown>\n    ] {\n    const [, setState] = React.useState(null);\n    const isMounted = React.useRef(false);\n\n    const stateObject = useStateObject(state);\n\n    const currentState = stateObject.getValue(config.selector);\n\n    function reRender() {\n        // re-render if the component is mounted\n        if (isMounted.current) {\n            setState({});\n        }\n    }\n\n    function observer(newState) {\n        if (currentState === newState) {\n            // Do nothing because the selected state is up-to-date\n        }\n        else {\n            reRender();\n        }\n    }\n\n    const subscription = {\n        observer: observer,\n        selector: config.selector ?\n            config.selector :\n            (state) => state,  // Select the whole state if selector is not specified\n        refresh: reRender\n    }\n\n    React.useEffect(() => {\n        const unsubscribe = stateObject.subscribe(subscription);\n        isMounted.current = true;\n\n        return () => {\n            unsubscribe();\n            isMounted.current = false;\n        }\n    }, [currentState, State])\n\n    function dispatch(action: unknown) {\n        const newState = reducer(currentState, action);\n        stateObject.setValue(newState, config);\n    }\n\n    return [currentState, dispatch, stateObject]\n}\n"
  },
  {
    "path": "src/useState.ts",
    "content": "import React from 'react';\nimport useReducer from './useReducer';\nimport State, { createState } from './State';\nimport { Patcher, Selector, SetState, StateInitializer, UpdateState } from './types';\n\n\n\nexport default function useState<T>(\n    state: State<T> | StateInitializer<T> | T,\n    config?: {}\n): [\n        state: T,\n        setState: SetState<T>,\n        updateState: UpdateState<T>,\n        stateObject: State<T>\n    ];\n\nexport default function useState<ST, T = unknown>(\n    state: State<T | never> | StateInitializer<T> | T,\n    config: { selector: Selector<ST> },\n): [\n        state: ST,\n        setState: SetState<T>,\n        updateState: UpdateState<T>,\n        stateObject: State<T>\n    ];\n\nexport default function useState<ST, T = unknown>(\n    state: State<T | never> | StateInitializer<T> | T,\n    config: { selector: Selector<ST>, patcher: Patcher<ST> },\n): [\n        state: ST,\n        setState: SetState<ST>,\n        updateState: UpdateState<ST>,\n        stateObject: State<T>\n    ];\n\nexport default function useState(\n    state: State<unknown> | unknown,\n    config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {},\n): [\n        state: unknown,\n        setState: SetState<unknown>,\n        updateState: UpdateState<unknown>,\n        stateObject: State<unknown>\n    ] {\n\n    function reducer(currentState, newState) {\n        return newState;\n    }\n\n    const [stateValue, setStateValue, stateObject] = useReducer(reducer, state, config);\n\n    function updateStateValue(updater): void {\n        stateObject.updateValue(updater, config);\n    }\n\n    return [stateValue, setStateValue, updateStateValue, stateObject];\n}"
  },
  {
    "path": "tests/store.clear.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '../src/';\n\n\nconst store = createStore();\nstore.setState(\"count\", 0);\n\ntest('should clear the entire store and initialize `count` with 5', () => {\n    const hook1 = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        hook1.result.current[1](count => 1)\n    })\n\n    act(() => {\n        store.clear(()=>{ store.setState(\"count\", 5); })\n    })\n\n    expect(hook1.result.current[0]).toStrictEqual(5)\n})\n\n\nconst store2 = createStore();\nstore2.setState(\"count\", 0);\n\ntest('should clear the entire store and initialize `age` with 18', () => {\n    const hook2 = renderHook(() => store2.useState(\"age\", {default: 18}));\n\n    act(() => {\n        hook2.result.current[1](age => age + 2)\n    })\n\n    act(() => {\n        store2.clear(()=>{ })\n    })\n\n    expect(hook2.result.current[0]).toStrictEqual(18)\n})\n\n"
  },
  {
    "path": "tests/store.getState.test.ts",
    "content": "import StatePool, { State } from '../src/';\n\n\nconst store = StatePool.createStore({count: 0});\n\ntest('should get user values', () => {\n    const isStateInstance = store.getState(\"count\") instanceof State;\n    expect(isStateInstance).toStrictEqual(true)\n})"
  },
  {
    "path": "tests/store.getStateValue.test.ts",
    "content": "import React from 'react';\nimport StatePool from '../src/';\n\n\nconst store = StatePool.createStore({\n    user: { name: \"Yezy\", age: 20 }\n});\n\ntest('should get user values', () => {\n    const selector = (user): string => user.name;\n\n    expect(store.getStateValue(\"user\")).toStrictEqual({ name: \"Yezy\", age: 20 })\n    expect(store.getStateValue(\"user\", selector)).toStrictEqual(\"Yezy\")\n})"
  },
  {
    "path": "tests/store.has.test.ts",
    "content": "import StatePool from '../src/';\n\n\nconst store = StatePool.createStore({ count: 0 });\n\ntest('should get user values', () => {\n    const inStore = store.has(\"count\");\n    const notInStore = store.has(\"user\");\n\n    expect(inStore).toStrictEqual(true);\n    expect(notInStore).toStrictEqual(false);\n})"
  },
  {
    "path": "tests/store.items.test.ts",
    "content": "import StatePool from '../src/';\n\n\nconst store = StatePool.createStore({\n    width: 10,\n    height: 15\n});\n\ntest('should get user values', () => {\n    const [item1, item2] = store.items()\n\n    expect(item1).toStrictEqual([\"width\", 10, false]);\n    expect(item2).toStrictEqual([\"height\", 15, false]);\n})"
  },
  {
    "path": "tests/store.persist.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '../src/';\n\n\nconst store = createStore();\n\nlet storage: {count?: number, age?: number} = {\n    \"count\": 10  // Pre-set count state to storage\n}\n\nstore.persist({\n    saveState: (key, value) => {\n        storage[key] = value;\n    },\n    loadState: (key, noState) => {\n        if (storage.hasOwnProperty(key)) {\n            return storage[key]\n        }\n        return noState;\n    },\n    removeState: (key) => {\n        delete storage[key];\n    },\n    clear: () => {\n        storage = {};  // Clear a store\n    }\n})\n\nstore.setState(\"count\", 0, {persist: true});\n\ntest('should update count', () => {\n    const { result } = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        result.current[1](count => count + 1)  // Will use the value from storage instead of 0\n    })\n\n    expect(result.current[0]).toStrictEqual(11)\n})\n\n\ntest('should create `age` state with the given default value', () => {\n    const { result } = renderHook(() => store.useState(\"age\", {default: 18, persist: true}));\n\n    // age state will be saved to a store\n    expect(storage.age).toStrictEqual(18);\n\n    act(() => {\n        result.current[1](age => age + 2);  // Will use the default value 18\n    })\n\n    expect(result.current[0]).toStrictEqual(20);\n    expect(storage.age).toStrictEqual(20);\n})\n\n\ntest('should remove count state from store and storage', () => {\n    const { result } = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        store.remove(\"count\", () => {\n            store.setState(\"count\", 5, {persist: true});\n        });  // This will remove count state from a store and reset it\n    })\n\n    expect(result.current[0]).toStrictEqual(5);\n    expect(storage.count).toStrictEqual(5);\n    expect(storage.age).toStrictEqual(20);\n})\n\n\ntest('should clear both store and storage', () => {\n    const { result } = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        store.clear(() => {\n            store.setState(\"count\", 10, {persist: true});\n        });  // This will clear a store and reset count state\n    })\n\n    expect(result.current[0]).toStrictEqual(10);\n    expect(storage.count).toStrictEqual(10);\n    expect(storage.age).toStrictEqual(undefined);\n})\n\n\n\n\n// Test PERSIST_ENTIRE_STORE = True\n\nconst store2 = createStore();\n\nlet storage2: {count?: number, age?: number, weight?: number} = {\n    \"count\": 10  // Pre-set count state to storage2\n}\n\nstore2.persist({\n    PERSIST_ENTIRE_STORE: true,\n    saveState: (key, value) => {\n        storage2[key] = value;\n    },\n    loadState: (key, noState) => {\n        if (storage2.hasOwnProperty(key)) {\n            return storage2[key]\n        }\n        return noState;\n    },\n    removeState: (key) => {\n        delete storage2[key];\n    },\n    clear: () => {\n        storage2 = {};  // Clear a store2\n    }\n})\n\nstore2.setState(\"count\", 0);\nstore2.setState(\"weight\", 50, {persist: false})  // Won't save this to permanent storage\n\ntest('should update count', () => {\n    const { result } = renderHook(() => store2.useState(\"count\"))\n\n    act(() => {\n        result.current[1](count => count + 1)  // Will use the value from storage2 instead of 0\n    })\n\n    expect(result.current[0]).toStrictEqual(11)\n})\n\n\ntest('should not save weight to storage2', () => {\n    const { result } = renderHook(() => store2.useState(\"weight\"))\n\n    act(() => {\n        result.current[1](55)\n    })\n\n    expect(result.current[0]).toStrictEqual(55)\n    expect(storage2.weight).toStrictEqual(undefined);\n})\n\n\ntest('should create `age` state with the given default value', () => {\n    const { result } = renderHook(() => store2.useState(\"age\", {default: 18}));\n\n    // age state will be saved to a store2\n    expect(storage2.age).toStrictEqual(18);\n\n    act(() => {\n        result.current[1](age => age + 2);  // Will use the default value 18\n    })\n\n    expect(result.current[0]).toStrictEqual(20);\n    expect(storage2.age).toStrictEqual(20);\n})\n"
  },
  {
    "path": "tests/store.remove.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '../src/';\n\n\nconst store = createStore();\nstore.setState(\"count\", 0);\n\ntest('should remove `count` state and re-initialize it with 5', () => {\n    const hook1 = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        hook1.result.current[2](count => 1)\n    })\n\n    act(() => {\n        store.remove(\"count\", ()=>{ store.setState(\"count\", 5); })\n    })\n\n    expect(hook1.result.current[0]).toStrictEqual(5)\n})\n\n\nconst store2 = createStore();\nstore2.setState(\"count\", 0);\n\ntest('should remove `age` state and re-initialize it with 18', () => {\n    const hook2 = renderHook(() => store2.useState(\"age\", {default: 18}));\n\n    act(() => {\n        hook2.result.current[2](age => age + 2)\n    })\n\n    act(() => {\n        store2.remove(\"age\")\n    })\n\n    expect(hook2.result.current[0]).toStrictEqual(18)\n})\n\n"
  },
  {
    "path": "tests/store.useReducer.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '../src/';\n\n\nconst store = createStore();\nstore.setState(\"count\", 0);\n\ntest('should update count', () => {\n    const reducer = (state, newState) => newState;\n\n    const { result } = renderHook(() => store.useReducer(reducer, \"count\"))\n\n    act(() => {\n        result.current[1](1)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('should create `age` state with the given default value', () => {\n    const reducer = (state: number, newState: number): number => newState;\n\n    const { result } = renderHook(() => store.useReducer(reducer, \"age\", {default: 18}));\n\n    act(() => {\n        result.current[1](result.current[0] + 2)\n    })\n\n    expect(result.current[0]).toStrictEqual(20)\n})\n\n"
  },
  {
    "path": "tests/store.useState.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport StatePool from '../src/';\n\n\nconst store = StatePool.createStore({ count: 0 });  // initialize store during instantiation\n\ntest('should update count', () => {\n    const { result } = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        result.current[1](count => 1)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('should create `age` state with the given default value', () => {\n    const { result } = renderHook(() => store.useState(\"age\", { default: 18 }));\n\n    act(() => {\n        result.current[1](age => age + 2)\n    })\n\n    expect(result.current[0]).toStrictEqual(20)\n})\n\n\nstore.setState<{ name: string, age: number }>(\"user\", { name: \"Yezy\", age: 20 });\n\ntest('should update name', () => {\n    const selector = (user): string => user.name;\n    const patcher = (user, name: string) => { user.name = name }\n\n    const { result } = renderHook(() => store.useState(\"user\", { selector, patcher }))\n\n    act(() => {\n        result.current[1]((name) => \"Yezy Ilomo\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Yezy Ilomo\")\n})\n\n\ntest('should create `birthYear` state with the given state initializer on default', () => {\n    const { result } = renderHook(() => store.useState(\"birthYear\", { default: () => 1995 }));\n\n    act(() => {\n        result.current[1](birthYear => birthYear + 2)\n    })\n\n    expect(result.current[0]).toStrictEqual(1997)\n})"
  },
  {
    "path": "tests/subscription.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createState, useState, createStore } from '../src/';\n\n\nconst count = createState(0);\n\nlet testVal1 = 0;\n\ntest('should update testVal1 through a subscriber', () => {\n    const { result } = renderHook(() => useState(count))\n\n    act(() => {\n        count.subscribe((value) => {\n            testVal1 = ++testVal1;\n        })\n        result.current[1](count => 1)\n    })\n\n    expect(testVal1).toStrictEqual(1);\n})\n\n\nconst user = createState({ name: \"Yezy\", weight: 65 });\n\nlet testVal2 = 0;\n\ntest('should increment testVal2 twice through subscribers', () => {\n    const { result } = renderHook(() => useState(user))\n\n    act(() => {\n        user.select(user => user.weight).subscribe((value) => {\n            testVal2 = ++testVal2;\n        })\n\n        user.select(user => user.name).subscribe((value) => {\n            testVal2 = ++testVal2;\n        })\n\n        result.current[2](user => { user.weight = 66; user.name = \"Ilomo\"; });\n    })\n\n    expect(testVal2).toStrictEqual(2);\n})\n\n\nconst store = createStore();\nstore.setState(\"count\", 0);\n\nlet testVal3 = 0;\n\ntest('should update testVal3 through subscribers', () => {\n    const { result } = renderHook(() => store.useState(\"count\"))\n\n    act(() => {\n        store.subscribe((key, value) => {\n            testVal3 = ++testVal3;\n        })\n        result.current[1](count => 1)\n    })\n\n    expect(testVal3).toStrictEqual(1);\n})"
  },
  {
    "path": "tests/useReducer.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { useReducer, createState } from '../src/';\n\n\nconst count = createState(0);\n\ntest('should update count', () => {\n    const reducer = (state, action) => action;\n\n    const { result } = renderHook(() => useReducer(reducer, count));\n\n    act(() => {\n        result.current[1](1)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\nconst user = createState({ name: \"Yezy\", age: 20 });\n\ntest('should update name', () => {\n    const reducer = (state: string, action: string): string => action;\n\n    const selector = (user): string => user.name;\n    const patcher = (user, name: string) => { user.name = name }\n\n    const { result } = renderHook(() => useReducer(reducer, user, { selector, patcher }))\n\n    act(() => {\n        result.current[1](\"Yezy Ilomo\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Yezy Ilomo\")\n})\n\n\ntest('Test local state: should update count', () => {\n    const reducer = (state, action) => action;\n\n    const { result } = renderHook(() => useReducer(reducer, 0));\n\n    act(() => {\n        result.current[1](1)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('Test local state: should update name', () => {\n    const reducer = (state: string, action: string): string => action;\n\n    const selector = (user): string => user.name;\n    const patcher = (user, name: string) => { user.name = name }\n\n    const { result } = renderHook(() => useReducer(reducer, { name: \"Yezy\", age: 20 }, { selector, patcher }))\n\n    act(() => {\n        result.current[1](\"Ilomo\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Ilomo\")\n})\n\n\ntest('Test local state with state initializer: should update count', () => {\n    const reducer = (state, action) => action;\n\n    const { result } = renderHook(() => useReducer(reducer, () => 0));\n\n    act(() => {\n        result.current[1](1)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('Should return state object as the last item in array', () => {\n    const reducer = (state, action) => action;\n\n    const { result } = renderHook(() => useReducer(reducer, 0));\n\n    act(() => {\n        result.current[1](1)\n    })\n\n    expect(result.current[2].getValue()).toStrictEqual(1)\n})"
  },
  {
    "path": "tests/useState.test.ts",
    "content": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { useState, createState } from '../src/';\n\n\nconst count = createState(0);\n\ntest('should update count', () => {\n    const { result } = renderHook(() => useState(count))\n\n    act(() => {\n        result.current[1](count => ++count)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('should set count', () => {\n    const { result } = renderHook(() => useState(count))\n\n    act(() => {\n        result.current[1](5)\n    })\n\n    expect(result.current[0]).toStrictEqual(5)\n})\n\n\n\nconst user = createState<{ name: string, age: number }>({ name: \"Yezy\", age: 20 });\n\ntest('should update name', () => {\n    const selector = (user) => user.name;\n    const patcher = (user, name) => { user.name = name }\n\n    const { result } = renderHook(() => useState(user, { selector, patcher }))\n\n    act(() => {\n        result.current[1]((name) => \"Yezy Ilomo\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Yezy Ilomo\")\n})\n\n\ntest('should set name', () => {\n    // If you specify the type of what you're selecting & patcher it'll automatically know what to return\n    const selector = (user) => user.name;\n    const patcher = (user, name) => { user.name = name }\n\n    const { result } = renderHook(() => useState(user, { selector, patcher }))\n\n    act(() => {\n        result.current[1](\"Ilomo Yezy\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Ilomo Yezy\")\n})\n\n\ntest('should update name without patcher', () => {\n    const selector = (user) => user.name;\n\n    const { result } = renderHook(() => user.useState({ selector }))\n\n    act(() => {\n        result.current[2]((usr) => { usr.name = \"Ilomo\" })\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Ilomo\")\n})\n\n\ntest('Test local state: should update count', () => {\n    const { result } = renderHook(() => useState(0))\n\n    act(() => {\n        result.current[1](count => ++count)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('Test local state: should set name', () => {\n    // If you specify the type of what you're selecting & patcher it'll automatically know what to return\n    const selector = (user) => user.name;\n    const patcher = (user, name) => { user.name = name }\n\n    const { result } = renderHook(() => useState({ name: \"Yezy\", age: 27 }, { selector, patcher }))\n\n    act(() => {\n        result.current[1](\"Ilomo Yezy\")\n    })\n\n    expect(result.current[0]).toStrictEqual(\"Ilomo Yezy\")\n})\n\n\ntest('Test local state with state initializer: should update count', () => {\n    const { result } = renderHook(() => useState(() => 0))\n\n    act(() => {\n        result.current[1](count => ++count)\n    })\n\n    expect(result.current[0]).toStrictEqual(1)\n})\n\n\ntest('Should return state object as the last item in array', () => {\n    const { result } = renderHook(() => useState(0))\n\n    act(() => {\n        result.current[1](count => ++count)\n    })\n\n    expect(result.current[3].getValue()).toStrictEqual(1)\n})\n\n\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"target\": \"ES5\",\n        \"module\": \"commonjs\",\n        \"allowJs\": true,\n        \"outDir\": \"dist\",\n        \"strict\": false,\n        \"jsx\": \"preserve\",\n        \"declaration\": true,\n        \"esModuleInterop\": true,\n        \"moduleResolution\": \"node\",\n        \"baseUrl\": \".\",\n        \"paths\": {\n          \"state-pool\": [\n            \"./src/index.ts\"\n          ]\n        }\n    },\n    \n    \"include\": [\n        \"src/**/*\",\n        \"tests/**/*\"\n    ],\n    \"exclude\": [\n        \"node_modules\",\n        \"dist\"\n    ]\n}"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\n### Installation\n\n```\n$ yarn\n```\n\n### Local Development\n\n```\n$ yarn start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ yarn build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\nUsing SSH:\n\n```\n$ USE_SSH=true yarn deploy\n```\n\nNot using SSH:\n\n```\n$ GIT_USER=<Your GitHub username> yarn deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "website/blog/2019-05-28-first-blog-post.md",
    "content": "---\nslug: first-blog-post\ntitle: First Blog Post\nauthors:\n  name: Gao Wei\n  title: Docusaurus Core Team\n  url: https://github.com/wgao19\n  image_url: https://github.com/wgao19.png\ntags: [hola, docusaurus]\n---\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n"
  },
  {
    "path": "website/blog/2019-05-29-long-blog-post.md",
    "content": "---\nslug: long-blog-post\ntitle: Long Blog Post\nauthors: endi\ntags: [hello, docusaurus]\n---\n\nThis is the summary of a very long blog post,\n\nUse a `<!--` `truncate` `-->` comment to limit blog post size in the list view.\n\n<!--truncate-->\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet\n"
  },
  {
    "path": "website/blog/2021-08-01-mdx-blog-post.mdx",
    "content": "---\nslug: mdx-blog-post\ntitle: MDX Blog Post\nauthors: [slorber]\ntags: [docusaurus]\n---\n\nBlog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).\n\n:::tip\n\nUse the power of React to create interactive blog posts.\n\n```js\n<button onClick={() => alert('button clicked!')}>Click me!</button>\n```\n\n<button onClick={() => alert('button clicked!')}>Click me!</button>\n\n:::\n"
  },
  {
    "path": "website/blog/2021-08-26-welcome/index.md",
    "content": "---\nslug: welcome\ntitle: Welcome\nauthors: [slorber, yangshun]\ntags: [facebook, hello, docusaurus]\n---\n\n[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).\n\nSimply add Markdown files (or folders) to the `blog` directory.\n\nRegular blog authors can be added to `authors.yml`.\n\nThe blog post date can be extracted from filenames, such as:\n\n- `2019-05-30-welcome.md`\n- `2019-05-30-welcome/index.md`\n\nA blog post folder can be convenient to co-locate blog post images:\n\n![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg)\n\nThe blog supports tags as well!\n\n**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.\n"
  },
  {
    "path": "website/blog/authors.yml",
    "content": "endi:\n  name: Endilie Yacop Sucipto\n  title: Maintainer of Docusaurus\n  url: https://github.com/endiliey\n  image_url: https://github.com/endiliey.png\n\nyangshun:\n  name: Yangshun Tay\n  title: Front End Engineer @ Facebook\n  url: https://github.com/yangshun\n  image_url: https://github.com/yangshun.png\n\nslorber:\n  name: Sébastien Lorber\n  title: Docusaurus maintainer\n  url: https://sebastienlorber.com\n  image_url: https://github.com/slorber.png\n"
  },
  {
    "path": "website/docs/api_reference/_category_.json",
    "content": "{\n    \"label\": \"API Reference\",\n    \"position\": 4\n}\n  "
  },
  {
    "path": "website/docs/api_reference/high_level_api/_category_.json",
    "content": "{\n    \"label\": \"High Level API\",\n    \"position\": 2\n}\n  "
  },
  {
    "path": "website/docs/api_reference/high_level_api/createStore.md",
    "content": "---\nsidebar_position: 1\n---\n\n# createStore\nStore is a container for state, it comes with several methods which are used to manage states in it including `store.setState`, `store.getState`, `store.remove`, `store.clear`, `store.useState`, `store.useReducer` and `store.subscribe`. Store is created by using `createStore` API as \n\n```js\nimport { createStore } from 'state-pool';\n\nconst store = createStore();\n\n// Or with initialization as \n\nconst store = createStore({\"state1\": value1, \"state2\": value2, ...});\n```\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.clear.md",
    "content": "---\nsidebar_position: 8\n---\n\n# store.clear\nThis is used to clear an entire store if you don't need all states in it anymore or you want to reload/reset all states. It accepts a function to run after clearing the store. \n\n:::important\n\n The function runs before components subscribed to all states in a store rerenders.\n\n:::\n\n```js\n// Signature\nstore.clear(fn: Function)\n```\n\nBelow is an example showing how to use it\n\n```jsx\nimport React from 'react';\nimport { createStore } from 'state-pool';\n\n\nconst store = createStore();\n\nconst user = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n    \nconst profile = {\n    url: \"https://yezyilomo.me\",\n    rating: 5\n}\nstore.setState(\"user\", user);\nstore.setState(\"profile\", profile);\n\n\nfunction UserInfo(props){\n    const [user, setUser, updateUser] = store.useState(\"user\");\n\n    const updateName = (e) => {\n        updateUser(user => {\n            user.name = e.target.value;\n        });\n    }\n\n    const reinitializeStore = () => {\n        const user = {name: \"Yezy\", age: 25, email: \"yezy@me.com\"}\n        const profile = {url: \"https://yezyilomo.me\", rating: 5}\n        store.setState(\"user\", user);\n        store.setState(\"profile\", profile);\n    }\n\n    const resetStore = (e) => {\n        store.clear(initializeStore);\n    }\n\n    return (\n        <div>\n            Name: {user.name}\n            <br/>\n            <input type=\"text\" value={user.name} onChange={updateName}/>\n             <button onClick={resetStore}>Reset Store</button>\n        </div>\n    );\n}\n\nReactDOM.render(UserInfo, document.querySelector(\"#root\"));\n```\nFrom the code above, when you click `Reset Store` button `store.clear` will remove all states from the store and create them again by executing `initializeStore`. This might come in handy when you need to clear all data when user logs out of your application.\n\n\n**NOTE:** both `store.remove` and `store.clear` when executed causes all components subscribed to states which are removed to rerender.\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.getState.md",
    "content": "---\nsidebar_position: 5\n---\n\n# store.getState\n`store.getState` is used to get a state object from a store, it accepts one required parameter which is a key(string) and another optional parameters which is the configuration object(available configurations are `default` and `persist` works just like in `store.setState`). When called, `store.getState` returns a state object.\n\n```js\n// Signature\nstore.getState(key: String, config?: {default: Any, persist: Boolean})\n```\n\nHere is how to use it\n\n```js\nconst State = store.getState(key);\n```\n\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.getStateValue.md",
    "content": "---\nsidebar_position: 12\n---\n\n# store.getStateValue\nThis method is used to get state value directly from a store given its key, it's equivalent of calling `store.getState(key).getValue(selector?)`. You can pass `selector` too if you want to select part of the state.\n\n```js\nconst userName = store.getStateValue(\"user\", (user) => user.name);\n```"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.has.md",
    "content": "---\nsidebar_position: 10\n---\n\n# store.has\n`store.has` is a method for checking if a state is available in a store. If you try to get a state from a store with `store.getState(key)` and it’s not available, state-pool will throw an error, so we need a good way to handle this, i.e check if a state is available first, then access it, This is where `store.has` swoops in.\n\nHere is an example of `store.has` in action\n\n\n```js\n// We want to access user state in a store but first we have to check if it's available\nif(store.has(\"user\")) {\n    const user = store.getState(\"user\");\n}\nelse {\n    // There is not user state in a store\n}\n\n```"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.items.md",
    "content": "---\nsidebar_position: 11\n---\n\n# store.items\n`store.items` is used to iterate over an entire store, it returns an array containing `key`, `value` and `persist` for each state in a store.\n\n\nHere is how to use it.\n\n```js\nstore.items().map(([key, value, persist]) => {\n    // Do whatever you want with these values\n})\n```"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.persist.md",
    "content": "---\nsidebar_position: 9\n---\n\n# store.persist\nSometimes you might want to save your states in a permanent storage probably because you might not want to lose them when your application is closed(i.e you want to retain them when your application starts).\n\n**State pool** makes it very easy to save your states in your preferred permanent storage, all you need to do is:\n\n1. Tell **state-pool** how to save your state by using `store.persist`\n2. Use `persist` configuration to tell state-pool to save your state in your preferred storage when creating your state.\n\nWhen telling **state-pool**  how to save state to a permanent storage we need to implement four functions which are \n\n1. `saveState`: This is for saving your state to your preferred permanent storage, it should accept a `key` as the first parameter, `value` as the second parameter and `isInitialSet` as the third parameter, the third parameter is boolean which tells if the state is being saved for the first time(initial set) or it's just an update. This function is called automatically when `store.setState` is executed and when the state changes\n2. `loadState`: This is used for loading state from your preferred permanent storage, it should accept a `key` as the first parameter and `noState` as the second parameter which is a constant(empty) to return if the state is not available from your permanent storage. This function is called when `store.setState` needs an initial value from your storage to populate a state\n3. `removeState`: This is used for removing state from a permanent storage, it should accept a `key` as the only parameter. This function is called when `store.remove` is executed\n4. `clear`: This is used for clearing an entire permanent storage, it doesn’t accept any parameter. This function is called when `store.clear` is executed.\n\nNow the way to implement these is by calling `store.persist` and pass them as shown below \n\n```js\nstore.persist({\n    saveState: function(key, value, isInitialSet){/*your code to save state */},\n    loadState: function(key, noState){/*your code to load state */},\n    removeState: function(key){/*your code to remove state */},\n    clear: function(){/*your code to clear storage */}\n})\n```\n\nAfter implementing these four functions you're good to go, you won’t need to worry about calling them, **state-pool** will be doing that for you automatically so that you can focus on using your states.\n\nAs discussed earlier both `store.setState`, `store.useState` and `store.useReducer` accepts an optional configuration parameter, `persist` being one of configurations, this is the one which is used to tell **state-pool** whether to save your state to a permanent storage or not. i.e\n\n```js\nstore.setState(\n    key: String,\n    initialState: Any,\n    config?: {persist: Boolean}\n)\n```\n\n```js\nstore.useState(\n    key: String,\n    config?: {default: Any, persist: Boolean, ...otherConfigs}\n)\n```\n\n```js\nstore.useReducer(\n    reducer: Function,\n    key: String,\n    config?: {default: Any, persist: Boolean, ...otherConfigs}\n)\n```\n\nBy default the value of `persist` in all cases is false(which means it doesn't save states to a permanent storage), so if you want to activate it, you have to set it to be true.\n\nWhat's even better about **state-pool** is that you get the freedom to choose what to save in your permanent storage and what's not to, so you don't need to save the whole store in your permanent storage, but if you want to save the whole store you can use `PERSIST_ENTIRE_STORE` configuration.\n\nBelow is an example showing how you could implement state persistance in local storage.\n\n```js\nimport { createStore } from 'state-pool';\n\nconst store = createStore();\n\nfunction debounce(func, timeout) {\n    let timer;\n    return (...args) => {\n        clearTimeout(timer);\n        timer = setTimeout(() => { func.apply(this, args); }, timeout);\n    };\n}\n\nstore.persist({\n    PERSIST_ENTIRE_STORE: true,  // Use this only if you want to persist the entire store\n    saveState: function (key, value, isInitialSet) {\n        \n        const doStateSaving = () => {\n            try {\n                const serializedState = JSON.stringify(value);\n                window.localStorage.setItem(key, serializedState);\n            } catch {\n                // Ignore write errors\n            }\n        }\n\n        if (isInitialSet) {\n            // Here we don't debounce saving state since it's the initial set\n            // so it's called only once and we need our storage to be updated\n            // right away\n            doStateSaving();\n        }\n        else {\n            // Here we debounce saving state because it's the update and this function\n            // is called every time the store state changes. However, it should not\n            // be called too often because it triggers the expensive `JSON.stringify` operation.\n            const DEBOUNCE_TIME = 1000 // In milliseconds\n             // Debounce doStateSaving before calling it\n            const processStateSaving = debounce(doStateSaving, DEBOUNCE_TIME);\n            processStateSaving()  // save State\n        }\n    },\n    loadState: function (key, noState) {\n        try {\n            const serializedState = window.localStorage.getItem(key);\n            if (serializedState === null) {\n                // No state saved\n                return noState;\n            }\n            return JSON.parse(serializedState);\n        } catch (err) {\n            // Failed to load state\n            return undefined\n        }\n    },\n    removeState: function (key) {\n        window.localStorage.removeItem(key);\n    },\n    clear: function () {\n        window.localStorage.clear();\n    }\n})\n```\n\n:::important\n\nWhen you set `PERSIST_ENTIRE_STORE = true`, **state-pool** will be persisting all your states to the permanent storage by default unless you explicitly specify `persist = false` when initializing your state.\n\n:::"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.remove.md",
    "content": "---\nsidebar_position: 7\n---\n\n# store.remove\nThis is used to remove a state from a store if you don't need it anymore or you want to reload/reset it. It accepts a key for a state or a list of keys to remove and a function to run after removal.\n\n:::important\n\nThe function runs before components subscribed to removed state(s) re-renders.\n\n:::\n\n```js\n// Signature\nstore.remove(key: String, fn: Function)\n```\n\nBelow is an example showing how to use it\n\n```jsx\nimport React from 'react';\nimport { createStore } from 'state-pool';\n\n\nconst store = createStore();\nstore.setState(\"count\", 0);\n\nfunction ClicksCounter(props){\n    const [count, setCount, updateCount] = store.useState(\"count\");\n\n    const incrementCount = (e) => {\n        setCount(count+1);\n    }\n\n    const reinitializeCountState = () => {\n        store.setState(\"count\", 0);\n    }\n\n    const resetCounter = (e) => {\n        store.remove(\"count\", reinitializeCountState)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n            <button onClick={resetCounter}>Reset</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\nFrom an example above, when you click `Reset` button `store.remove` will remove `count` state and create it again by executing `initializeStore`.\n\n\n**NOTE:** If we had more than one state to delete we could do\n\n```js\nstore.remove([key1, key2, key3, ...], initializeStore);\n```\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.setState.md",
    "content": "---\nsidebar_position: 2\n---\n\n# store.setState\nThis is used to create a state and map it to a key so that you won't need to use it directly, instead you use a key to get it. `store.setState` takes two required parameters, a key(string) to map to a state object and the initial value or state initializer, In addition to those two parameters it takes a third optional parameter which is the configuration object. `persist` is the only available config which is the flag to determine whether to save/persist state in a permanent storage or not.\n\n```js\n// Signature\nstore.setState(key: String, initialState: Any, config?: {persist: Boolean});\n\n// Or with lazy state initializer\n\nstore.setState(key: String, stateInitializer: () => Any, config?: {persist: Boolean})\n```\n\nHere is how to use it\n\n```js\nconst userState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\nstore.setState(\"user\", userState);\n```\n\n:::important\n\n`store.setState` should be used outside of a react component.\n\n:::\n\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.subscribe.md",
    "content": "---\nsidebar_position: 6\n---\n\n# store.subscribe\nIf you want to listen to changes in a store you can subscribe to it by using `store.subscribe`. it accepts an observer function. For example \n\n```js\n// Subscribe to store changes\nconst unsubscribe = store.subscribe(function(key: String, value: Any){\n    // key is the key for a state that has changed \n    // value is the new value of a state\n})\n\n// You can unsubscribe by calling the result\nunsubscribe();\n```\n\nIf you want to subscribe to a single state you can use \n\n```js\n// Subscribe to store changes\nconst unsubscribe = store.getState(key).subscribe(function(value){\n    // value is the new value of a state\n})\n\n// You can unsubscribe by calling the result\nunsubscribe();\n```\n\nYou can even subscribe to a deeply nested state by using a selector as \n\n```js\nstore.getState(key).subscribe({\n    observer:  function(value){\n        // value is the new value of a state \n    },\n    selector: function(value){\n        return  selected_state\n    })\n})\n```\nWith this observer function will only be called when the selected state changes.\n\n\nAnother way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as\n\n```js\nstore.getState(key).select(state => selected_state).subscribe(value =>{\n        // Do your thing here\n    }\n)\n```"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.useReducer.md",
    "content": "---\nsidebar_position: 4\n---\n\n# store.useReducer\nThis is an alternative to `store.useState`, it works just like `React.useReducer` hook(If you’re familiar with `React.useReducer`, you already know how this works). It accepts a reducer and a key for the state as parameters, it returns the current state paired with a dispatch method plus the state object, but in most cases you won't be using `stateObject` so you'll be okay with just `[state, dispatch]`.. In addition to the two parameters it also accept another optinal perameter which is the configuration object, available configurations are `default`, `persist`, `selector` & `patcher` they work exactly the same just like in `store.useState`.\n\n```js\n// Signature\nstore.useReducer(\n    reducer: Function,\n    key: String,\n    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}\n)\n```\n\nBelow is a simple example showing how to use `store.useReducer` hook\n\n```js\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nstore.setState(\"user\", initialState);\n\nfunction myReducer(state, action){\n    // This could be any reducer\n    // Do whatever you want to do here\n    return newState\n}\n\nfunction Component(props){\n    const [name, dispatch] = store.useReducer(myReducer, \"user\");\n\n    // Other stuff ...\n}\n```\n\n\nBelow is an example with `selector` and `patcher` parameters\n\n```js\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nstore.setState(\"user\", initialState);\n\n\nfunction myReducer(state, action){\n    // This could be any reducer\n    // Do whatever you want to do here\n    return newState\n}\n\nfunction UserInfo(props){\n    const selector = (user) => user.name;\n    const patcher = (user, name) => {user.name = name};\n    \n    const [name, dispatch] = store.useReducer(myReducer, \"user\", {selector, patcher});\n\n    // Other stuff\n}\n```\n"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.useState.md",
    "content": "---\nsidebar_position: 3\n---\n\n# store.useState\n`store.useState` is a hook that's used to get a state from a store, it's a way for a component to subscribe to a state from a store. `store.useState` works just like `React.useState` hook but it accepts a key for the state and returns an array of `[state, setState, updateState, stateObject]` rather than `[state, setState]`, In most cases you won't be using `stateObject` so you'll be okay with `[state, setState, updateState]`. In addition to the key parameter it also accept another optional parameter which is the config object, available configurations are `default`, `persist`, `selector` & `patcher`, these will be discussed in detail later.\n\n```js\n// Signature\nstore.useState(\n    key: String,\n    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}\n)\n\n// Or with lazy state initializer as \n\nstore.useState(\n    key: String,\n    config?: {default: () => Any, persist: Boolean, selector: Function, patcher: Function}\n)\n```\n\nBelow is an example showing how to use `store.useState` hook\n\n```js\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nstore.setState(\"user\", initialState);\n\nfunction Component(props){\n    const [user, setUser, updateUser] = store.useState(\"user\");\n    // Other stuff\n}\n```\n\nHere `updateUser` is a higher order function which accepts another function for updating user as an argument(this another functions takes user(old state) as the argument). So to update any value on user you could do\n\n```js\nupdateUser(function(user){\n    user.name = \"Yezy Ilomo\";\n    user.age = 26;\n})\n```\n\nOr you could just use `setUser` instead of `updateUser` i.e\n\n```js\nsetUser({name: \"Yezy Ilomo\", age: 26, email: \"yezy@me.com\"});\n```\n\nOr\n\n```js\nsetUser(function(user){\n    return {\n        name: \"Yezy Ilomo\",\n        age: 26,\n        email: user.email\n    }\n})\n```\n\nAs stated earlier `store.useState` takes a second optional parameter which is a configuration object, available configurations are:\n- `default` - This is used to specify the default value if you want `store.useState` to create a state if it doesn't find the one for the key specified in the first argument. For example\n\n  ```js\n  const [user, setUser, updateUser] = store.useState(\"user\", {default: null});\n\n  // You can also use lazy initialization on `default` option as\n    const [user, setUser, updateUser] = store.useState(\n        \"user\", \n        {default: () => { \n            // your expensive computation here\n            return null  // Return your initial state\n        }}); \n  ```\n\n  This piece of code means, get the state for the key \"user\" if it's not available in a store, create one and assign it the value `null`.\n\n- Also in addition to `default` configuration there is `persist` configuration which is the flag to determine whether to save/persist state in your preferred storage or not. Here `persist` configuration is only used if `store.useState` is going to create state dynamically(by using `default` config).\n<br/>\n\nOther allowed configurations are `selector` & `patcher`. These are used for specifying a way to select deeply nested state and update it.\n\n- `selector` should be a function which takes one parameter which is the state and returns a selected value. The purpose of this is to subscribe to a deeply nested state or derived state.\n\n- `patcher` should be a function which takes two parameters, the first is the state and the second is the selected value. The purpose of this is to merge back the selected value to the state once it's updated.\n\n  Example.\n  ```jsx\n  const initialState = {\n      name: \"Yezy\",\n      age: 25,\n      email: \"yezy@me.com\"\n  }\n  \n  store.setState(\"user\", initialState);\n  \n  \n  function UserName(props){\n      const selector = (user) => user.name;  // Subscribe to user.name only\n      const patcher = (user, name) => {user.name = name};  // Update user.name\n  \n      const [name, setName] = store.useState(\"user\", {selector: selector, patcher: patcher});\n  \n      const handleNameChange = (e) => {\n          setName(e.target.value);\n      }\n  \n      return (\n          <div>\n              Name: {name}\n              <br/>\n              <input type=\"text\" value={name} onChange={handleNameChange}/>\n          </div>\n      );\n  }\n  ```\n"
  },
  {
    "path": "website/docs/api_reference/intro.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Intro\nState pool API is divided into two parts. \n1. High Level API(Store based API)\n2. Low Level API(Non-Store based API)\n\nIn a high level API, states are stored in a container that we call \"store\". With high level API, State pool allows you to create as many stores as you want and use them anywhere in your application, it doesn't enforce having a single central store.\n\nHere is a simple example using high level API\n\n```jsx\nimport React from 'react';\nimport { createStore } from 'state-pool';\n\n// Create a store\nconst store = createStore();\n\n// Create count state and initialize it with 0\nconst count = store.setState(\"count\", 0);\n\nfunction ClicksCounter(props){\n    // Use count state\n    const [count, setCount] = store.useState(\"count\");\n\n    const incrementCount = (e) => {\n        setCount(count+1);\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\nOn the other hand, low level API doesn't use the concept of a store, You simply store your state wherever you want. In low level API **state-pool** doesn't care where you store your state as long as you can access them, for-instance I could choose to store my state in a global variable and it would still work just fine.\n\nSo basically the low level API gives you a way to create and use state, it doesn't matter where you store them as long as you can access them.\n\nHere is the same example as the previous one re-written using low level API\n\n```jsx\nimport React from 'react';\nimport { createState } from 'state-pool';\n\n\n// Create count state and initialize it with 0\nconst count = createState(0);\n\nfunction ClicksCounter(props){\n    // Use count state\n    const [count, setCount] = count.useState();\n\n    const incrementCount = (e) => {\n        setCount(count+1);\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\nOr if you want to import `useState` from **state-pool**\n\n```jsx\nimport React from 'react';\nimport { createState, useState } from 'state-pool';\n\n\n// Create count state and initialize it with 0\nconst count = createState(0);\n\nfunction ClicksCounter(props){\n    // Use count state\n    const [count, setCount] = useState(count);\n\n    const incrementCount = (e) => {\n        setCount(count+1);\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\nNow let's explore these two APIs\n"
  },
  {
    "path": "website/docs/api_reference/low_level_api/_category_.json",
    "content": "{\n    \"label\": \"Low Level API\",\n    \"position\": 3\n}\n  "
  },
  {
    "path": "website/docs/api_reference/low_level_api/createState.md",
    "content": "---\nsidebar_position: 1\n---\n\n# createState\nThis is the basic unit of **state-pool**, it's a function which is used to create a state object, it accepts one parameter which is the initial value or initializer function.\n\n```js\n// Signature\ncreateState(initialValue: Any)\n\n// Or\n\ncreateState(initializer: () => Any)\n```\n\nHere is how to use it\n\n```js\nimport { createState } from 'state-pool';\n\nconst userName = createState(\"Yezy\");\n\n// Or if you have expensive computations during initialization you could use lazy initialization\n\nfunction lazyInitializer(){\n  // Perform expensive computation here\n  \n  return \"Yezy\";  // Return your initial state\n}\n\nconst userName = createState(lazyInitializer);\n```\n\nHere are some of the mostly used methods available in a state object.\n\n- `useState`: This is used to subscribe a component to a state, it's a hook which should be used inside a react component.\n  ```js\n  // Signature\n  state.useState(config?: {selector: Function, patcher: Function});\n  ```\n- `useReducer`: This too is used to subscribe a component to a state, it's also a hook which should be used inside a react component.\n  ```js\n  // Signature\n  state.useReducer(reducer: Function, config?: {selector: Function, patcher: Function});\n  ```\n- `getValue`: This is used to get the value of a state\n  ```js\n  // Signature\n  state.getValue(selector?: Function);\n  ```\n- `setValue`: This is used to set the value of a state\n  ```js\n  // Signature\n  state.setValue(value | stateUpdater: Any | Function, config?: {selector, patcher});\n  ```\n- `updateValue`: This is used to update the value of a state\n  ```js\n  // Signature\n  state.updateValue(updater: Function, config?: {selector, patcher});\n  ```\n- `subscribe`: This is used to listen to all changes from a state\n  ```js\n  // Signature\n  state.subscribe(observer: Function | Subscription: {observer, selector});\n  ```\n- `select`: This is used to derive another state or select a deeply nested state\n  ```js\n  // Signature\n  state.select(selector: Function);\n  ```\n  This returns `DerivedState` that you can subscribe to by calling `subscribe` on it as\n  ```js\n  // Signature\n  state.select(selector: Function).subscribe(observer: Function);\n  ```\n\nBelow is an example showing all of them in action\n```js\nimport { createState } from 'state-pool';\n\nconst count = createState(0);\n\ncount.useState()  // This subscribe its component to count state\n\ncount.getValue()  // This will give 0\n\ncount.setValue(1)  // This set the value of count to 1\n\n// This will print whenever count change\nconst unsubscribe = count.subscribe(val => console.log(val)) \n\nunsubscribe()  // This will unsubscribe the observer above\n\n// An example for nested state\nconst user = createState({name: \"Yezy\", weight: 65});\n\nuser.updateValue(user => {user.weight += 1})  // This will increment the weight\n\n// Select user name and subscribe to it,\n// this will be printing whenever user name changes\nuser.select(user => user.name).subscribe(name => console.log(name));\n```\n\n\n:::important\n\n`createState` should be used outside of a react component. \n\n:::\n\n:::tip\n\n`createState` is used to implement `store.setState` API. \n\n:::"
  },
  {
    "path": "website/docs/api_reference/low_level_api/useReducer.md",
    "content": "---\nsidebar_position: 3\n---\n\n# useReducer\nThis is an alternative to `useState`, it works just like `React.useReducer` hook(If you’re familiar with `React.useReducer`, you already know how this works). It accepts a reducer and a state object or initial state or state initializer as parameters, it returns the current state paired with a dispatch method plus the state object, but in most cases you won't be using `stateObject` so you'll be okay with `[state, dispatch]`. In addition to the two parameters it also accept another optinal perameter which is the configuration object, available configurations are `selector` and `patcher` they work exactly the same just like in `useState`.\n\n\n```js\n// Signature\nuseReducer(\n    reducer: Function,\n    state: State,\n    config?: {selector: Function, patcher: Function}\n)\n\n// Or in local state as\n\nuseReducer(\n    reducer: Function,\n    initialState: Any,\n    config?: {selector: Function, patcher: Function}\n)\n\n// Or with lazy state initializer\nuseReducer(\n    reducer: Function,\n    stateInitializer: () => Any,\n    config?: {selector: Function, patcher: Function}\n)\n```\n\nBelow is a simple example showing how to use `useReducer`\n\n```js\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nconst user = createState(initialState);\n\nfunction myReducer(state, action){\n    // This could be any reducer\n    // Do whatever you want to do here\n    return newState\n}\n\nfunction Component(props){\n    const [name, dispatch] = useReducer(myReducer, user);\n    \n    // Other stuff ...\n}\n```\n\nBelow is the same example with `selector` and `patcher` parameters\n\n```js\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nconst user = createState(initialState);\n\n\nfunction myReducer(state, action){\n    // This could be any reducer\n    // Do whatever you want to do here\n    return newState\n}\n\nfunction UserInfo(props){\n    const selector = (user) => user.name;\n    const patcher = (user, name) => {user.name = name};\n    \n    const [name, dispatch] = useReducer(myReducer, user, {selector, patcher});\n\n    // Other stuffs\n}\n```\n\n\n# Using useReducer to manage local state\nJust like in `useState`, `useReducer` can be used to manage local state too.\n\nHere is an example for managing local state with `useReducer`\n```jsx\nimport React from 'react';\nimport { useReducer } from 'state-pool';\n\n\nconst myReducer = (state, action) => {\n   // Your computaton here\n   return action;\n}\n\nfunction ClicksCounter(props){\n    // Here `useReducer` hook will create \"count\" state and initialize it with 0\n    // Note: the `useReducer` hook used here is impored from state-pool and not react\n    const [count, dispatch] = useReducer(myReducer, 0);\n\n    const incrementCount = (e) => {\n        dispatch(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n<br/>\n\nIf you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,\n\n\n:::tip\n\n`useState` hook is derived from `useReducer` hook, also this hook is used to implement `store.useReducer`.\n\n:::"
  },
  {
    "path": "website/docs/api_reference/low_level_api/useState.md",
    "content": "---\nsidebar_position: 2\n---\n\n# useState\n`useState` is a hook that used within a react component to subscribe to a state. `useState` works just like `React.useState` hook but it accepts a state object or initial state or state initializer and returns an array of `[state, setState, updateState, stateObject]` rather than `[state, setState]`, In most cases you won't be using `stateObject` so you'll be okay with `[state, setState, updateState]`. In addition to a state object parameter it also accept another optional parameter which is the config object, available configurations are `selector` & `patcher`, these parameters works exactly the same as in `store.useState`. We could say `useState` is a low level implementation of `store.useState`.\n\n```js\n// Signature\nuseState(state: State, config?: {selector: Function, patcher: Function})\n\n// Or in local state as\n\nuseState(initialState: Any, config?: {selector: Function, patcher: Function})\n\n// Or with lazy state initializer\n\nuseState(stateInitializer: () => Any, config?: {selector: Function, patcher: Function})\n```\n\nBelow is a simple example showing how to use `useState` hook\n\n```jsx\nimport React from 'react';\nimport { createState, useState } from 'state-pool';\n\n\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nconst user = createState(initialState);\n\nfunction Component(props){\n    const [user, setUser, updateUser] = useState(user);\n    // Other stuff ...\n}\n```\n\nBelow is the same example with `selector` and `patcher` configurations\n\n```jsx\nconst initialState = {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n}\n\nconst user = createState(initialState);\n\n\nfunction UserName(props){\n    const selector = (user) => user.name;  // Subscribe to user.name only\n    const patcher = (user, name) => {user.name = name};  // Update user.name\n\n    const [name, setName] = useState(user, {selector: selector, patcher: patcher});\n\n    const handleNameChange = (e) => {\n        setName(e.target.value);\n    }\n\n    return (\n        <div>\n            Name: {name}\n            <br/>\n            <input type=\"text\" value={name} onChange={handleNameChange}/>\n        </div>\n    );\n}\n```\n\n# Using useState to manage local state\nWith **state-pool**, state are just like variables, if declared on a global scope, it’s a global state and if declared on local scope it’s a local state, so the difference between global state and local state in **state-pool** lies where you declare them just like variables.\n\nHere is an example for managing local state with `useState`\n```jsx\nimport React from 'react';\nimport { useState } from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    // Note: the `useState` hook used here is impored from state-pool and not react\n    const [count, setCount] = useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n<br/>\n\nIf you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,\n\nHere is an example\n```jsx\n// Example 2.\nimport React from 'react';\nimport StatePool from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    const [count, setCount] = StatePool.useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\nHere is an example with nested data\n```jsx\nimport { useState } from 'state-pool';\n\n\nfunction UserName(props){\n    const [user, setUser, updateUser] = useState({name: \"Yezy\", age: 25, email: \"yezy@me.com\"});\n\n    const handleNameChange = (e) => {\n        updateUser((user) => {\n            user.name = e.target.value\n        })\n    }\n\n    const handleAgeChange = (e) => {\n        updateUser((user) => {\n            user.age = e.target.value\n        })\n    }\n\n    return (\n        <div>\n            <div>Name: {user.name} </div>\n            <div>Age: {user.age} </div>\n            <input type=\"text\" value={user.name} onChange={handleNameChange}/>\n            <input type=\"text\" value={user.age} onChange={handleAgeChange}/>\n        </div>\n    );\n}\n```\n\n:::tip\n\n`useState` is used to implement `store.useState` hook.\n\n:::"
  },
  {
    "path": "website/docs/api_reference/typing-state.md",
    "content": "---\nsidebar_position: 4\n---\n\n\n# Typing State\nAll state related functions support implicity and explicity typing.\n\nExamples\n\n```ts\nstore.setState<number>('count', 0);\n\nstore.useState<number>('count');\n\nstore.useReducer<number, action>(reducer, 'count');\n\n// For none key based\nconst count = createState<number>(0);\n\nuseState<number>(count);\n\nuseReducer<number, action>(reducer, count);\n\n\n// Typing with selector\nstore.setState<{name: string, age: number}>('user', {name: 'Yezy', age: 25});\n\nstore.useState<string>('user', {selector: user => user.name});\nstore.useState<number>('age', {selector: user => user.age});\n\nstore.useReducer<string, action>(reducer, 'user', {selector: user => user.name});\nstore.useReducer<number, action>(reducer, 'user', {selector: user => user.age});\n\n// For none key based\nconst user = createState<{name: string, age: number}>({name: 'Yezy', age: 25});\n\nuseState<string>(user, {selector: user => user.name});\nuseState<number>(user, {selector: user => user.age});\n\nuseReducer<string, action>(reducer, user, {selector: user => user.name});\nuseReducer<number, action>(reducer, user, {selector: user => user.age});\n```\n\n<br/><br/>\n\n# Blue print for typing hooks\n**Note:** `T` is for base/original state type, `ST` for selected state type and `A` for reducer action.\n\n```ts\n// useState.js   (For useState)\n\nconst [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = useState<T>(state: State<T> | T)\n\nconst [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = useState<ST, T>(state: State<T> | T, { selector: Selector<ST> })\n\nconst [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = useState<ST, T>(state: State<T> | T, { selector: Selector<ST>, patcher: Patcher<ST> })\n\n\n// State.js   (For state.useState)\n\nconst [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = state<T>.useState()\n\nconst [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = state<T>.useState<ST>({ selector: Selector<ST> })\n\nconst [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = state<T>.useState<ST>({ selector: Selector<ST>, patcher: Patcher<ST> })\n\n// Store.js   (For store.useState)\n\nconst [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = store.useState<T>(key, { default: T });\n\nconst [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = store.useState<ST, T>(key, { selector: Selector<ST>, default: T })\n\nconst [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = store.useState<ST, T>(key, { selector: Selector<ST>, patcher: Patcher<ST>, default: T })\n\n\n// useReducer.js   (For useReducer)\n\ntype Reducer = (state: T, action: A) => T\nconst [state: T, dispatch: (action: A) => void, stateObj: State<T>] = useReducer<T, A>(type Reducer = Reducer<T, A>, state: State<T> | T)\n\ntype Reducer = (state: T, action: A) => T\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = useReducer<ST, A, T>(type Reducer = Reducer<ST, A>, state: State<T> | T, { selector: Selector<ST> })\n\ntype Reducer = (state: ST, action: A) => ST\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = useReducer<ST, A, T>(type Reducer = Reducer<ST, A>, state: State<T> | T, { selector: Selector<ST>, patcher: Patcher<ST> })\n\n\n// State.js  (For state.useReducer)\n\ntype Reducer = (state: T, action: A) => T\nconst [state: T, dispatch: (action: A) => void, stateObj: State<T>] = state<T>.useReducer<T, A>(type Reducer = Reducer<T, A>)\n\ntype Reducer = (state: T, action: A) => T\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = state<T>.useReducer<ST, A>(type Reducer = Reducer<T, A>, { selector: Selector<ST> })\n\ntype Reducer = (state: ST, action: A) => ST\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = state<T>.useReducer<ST, A>(type Reducer = Reducer<T, A>, { selector: Selector<ST>, patcher: Patcher<ST> })\n\n\n// Store.js   (For store.useReducer)\n\ntype Reducer = (state: T, action: A) => T\nconst [state: T, dispatch: (action: A) => void, stateObj: State<T>] = store.useReducer<T, A>(type Reducer = Reducer<T, A>, key, { default: T });\n\ntype Reducer = (state: T, action: A) => T\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = store.useReducer<ST, A, T>(type Reducer = Reducer<ST, A>, key, { selector: Selector<ST>, default: T })\n\ntype Reducer = (state: ST, action: A) => ST\nconst [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = store.useReducer<ST, A, T>(type Reducer = Reducer<ST, A>, key, { selector: Selector<ST>, patcher: Patcher<ST>, default: T })\n```\n"
  },
  {
    "path": "website/docs/basic_concepts/_category_.json",
    "content": "{\n    \"label\": \"Basic Concepts\",\n    \"position\": 2\n}\n  "
  },
  {
    "path": "website/docs/basic_concepts/derived_state.md",
    "content": "---\nsidebar_position: 3\n---\n\n# Derived & Nested State\nWith state pool you can subscribe to deeply nested or derived state. Both `store.useState` and `store.useReducer` accepts an optional configuration parameter with which you can pass `selector` & `patcher` options that are used to derive and update state.\n\nHere is a simple example showing how to use `selector` & `Patcher` options\n\n```jsx\n// With store API\nconst user = createState({\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n});\n\n\nfunction UserName(props){\n    const selector = (user) => user.name;  // Subscribe to user.name only\n    const patcher = (user, name) => {user.name = name};  // Update user.name\n\n    const [name, setName] = user.useState({selector: selector, patcher: patcher});\n\n    const handleNameChange = (e) => {\n        setName(e.target.value);\n    }\n\n    return (\n        <div>\n            Name: {name} <br/>\n            <input type=\"text\" value={name} onChange={handleNameChange}/>\n        </div>\n    );\n}\n```\n\nOr with store API\n\n```jsx\n// With store API\nstore.setState(\"user\", {\n    name: \"Yezy\",\n    age: 25,\n    email: \"yezy@me.com\"\n});\n\n\nfunction UserName(props){\n    const selector = (user) => user.name;  // Subscribe to user.name only\n    const patcher = (user, name) => {user.name = name};  // Update user.name\n\n    const [name, setName] = store.useState(\"user\", {selector: selector, patcher: patcher});\n\n    const handleNameChange = (e) => {\n        setName(e.target.value);\n    }\n\n    return (\n        <div>\n            Name: {name} <br/>\n            <input type=\"text\" value={name} onChange={handleNameChange}/>\n        </div>\n    );\n}\n```\nHere `selector` & `patcher` are used for specifying a way to select deeply nested state(derive new state) and update it.\n\n- `selector` should be a function which takes one parameter which is the state and returns a selected value. The purpose of this is to subscribe to a deeply nested or derived state.\n\n- `patcher` should be a function which takes two parameters, the first is the state and the second is the selected value. The purpose of this is to merge back the selected value to the state once it's updated."
  },
  {
    "path": "website/docs/basic_concepts/managing_subscriptions.md",
    "content": "---\nsidebar_position: 4\n---\n\n# Managing Subscriptions\nIf you want to listen to changes from a state you can subscribe to it by using `state.subscribe`. it accepts an observer function. For example\n\n\n```js\nconst state = createState(value);\n\n\n// Subscribe to state changes\nconst unsubscribe = state.subscribe(function(value){\n    // value is the new value of a state\n})\n\n// You can unsubscribe by calling the result\nunsubscribe();\n```\n\nYou can even subscribe to a deeply nested state by using a selector as \n\n```js\nstate.subscribe({\n    observer:  function(value){\n        // value is the new value of a state \n    },\n    selector: function(value){\n        return  selected_state\n    }\n})\n```\nWith this, observer function will only be called when the selected state changes.\n\n\nAnother way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as\n\n```js\nstate.select(state => selected_state).subscribe(value =>{\n        // Do your thing here\n    }\n)\n```\n\n# Subscriptions in a store\nIf you want to listen to changes in an entire store you can subscribe to it by using `store.subscribe`. it accepts an observer function. For example\n\n```js\n// Subscribe to store changes\nconst unsubscribe = store.subscribe(function(key: String, value: Any){\n    // key is the key for a state that has changed \n    // value is the new value of a state\n})\n\n// You can unsubscribe by calling the result\nunsubscribe();\n```\n\nIf you want to subscribe to a single state you can use \n\n```js\n// Subscribe to store changes\nconst unsubscribe = store.getState(key).subscribe(function(value){\n    // value is the new value of a state\n})\n\n// You can unsubscribe by calling the result\nunsubscribe();\n```\n\nYou can even subscribe to a deeply nested state by using a selector as \n\n```js\nstore.getState(key).subscribe({\n    observer:  function(value){\n        // value is the new value of a state \n    },\n    selector: function(value){\n        return  selected_state\n    })\n})\n```\nWith this, observer function will only be called when the selected state changes.\n\n\nAnother way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as\n\n```js\nstore.getState(key).select(state => selected_state).subscribe(value =>{\n        // Do your thing here\n    }\n)\n```"
  },
  {
    "path": "website/docs/basic_concepts/state_persistence.md",
    "content": "---\nsidebar_position: 5\n---\n\n# State Persistence\nState pool has a built in support for state persistence through store API, it makes saving your states in your preferred permanent storage very easy, all you need to do is tell state pool how to save, load, clear and remove your state from your preferred storage by using `store.persist` API.\n\nThe way to implement these is by calling `store.persist` and pass them as shown below \n\n```js\nstore.persist({\n    saveState: function(key, value, isInitialSet){/*your code to save state */},\n    loadState: function(key, noState){/*your code to load state */},\n    removeState: function(key){/*your code to remove state */},\n    clear: function(){/*your code to clear storage */}\n})\n```\n\nAfter implementing these four functions you're good to go, you won’t need to worry about calling them, **state-pool** will be doing that for you automatically so that you can focus on using your states.\n\nBoth `store.setState`, `store.useState` and `store.useReducer` accepts an optional configuration parameter, `persist`, this is the one which is used to tell **state-pool** whether to save your state to a permanent storage or not. i.e\n\n```js\nstore.setState(\n    key: String,\n    initialState: Any,\n    config?: {persist: Boolean}\n)\n```\n\n```js\nstore.useState(\n    key: String,\n    config?: {default: Any, persist: Boolean, ...otherConfigs}\n)\n```\n\n```js\nstore.useReducer(\n    reducer: Function,\n    key: String,\n    config?: {default: Any, persist: Boolean, ...otherConfigs}\n)\n```\n\nBy default the value of `persist` in all cases is `false`(which means it doesn't save states to a permanent storage), so if you want to activate it, you have to set it to be true.\n\nWhat's even better about **state-pool** is that you get the freedom to choose what to save in your permanent storage, so you don't need to save the whole store in your permanent storage, but if you want to save the whole store you can use `PERSIST_ENTIRE_STORE` configuration.\n\nBelow is an example showing how you could implement state persistance in local storage.\n\n```js\nimport { createStore } from 'state-pool';\n\nconst store = createStore();\n\nfunction debounce(func, timeout) {\n    let timer;\n    return (...args) => {\n        clearTimeout(timer);\n        timer = setTimeout(() => { func.apply(this, args); }, timeout);\n    };\n}\n\nstore.persist({\n    PERSIST_ENTIRE_STORE: true,  // Use this only if you want to persist the entire store\n    saveState: function (key, value, isInitialSet) {\n        \n        const doStateSaving = () => {\n            try {\n                const serializedState = JSON.stringify(value);\n                window.localStorage.setItem(key, serializedState);\n            } catch {\n                // Ignore write errors\n            }\n        }\n\n        if (isInitialSet) {\n            // Here we don't debounce saving state since it's the initial set\n            // so it's called only once and we need our storage to be updated\n            // right away\n            doStateSaving();\n        }\n        else {\n            // Here we debounce saving state because it's the update and this function\n            // is called every time the store state changes. However, it should not\n            // be called too often because it triggers the expensive `JSON.stringify` operation.\n            const DEBOUNCE_TIME = 1000 // In milliseconds\n             // Debounce doStateSaving before calling it\n            const processStateSaving = debounce(doStateSaving, DEBOUNCE_TIME);\n            processStateSaving()  // save State\n        }\n    },\n    loadState: function (key, noState) {\n        try {\n            const serializedState = window.localStorage.getItem(key);\n            if (serializedState === null) {\n                // No state saved\n                return noState;\n            }\n            return JSON.parse(serializedState);\n        } catch (err) {\n            // Failed to load state\n            return undefined\n        }\n    },\n    removeState: function (key) {\n        window.localStorage.removeItem(key);\n    },\n    clear: function () {\n        window.localStorage.clear();\n    }\n})\n```\n\n:::important\n\nWhen you set `PERSIST_ENTIRE_STORE = true`, **state-pool** will be persisting all your states to the permanent storage by default unless you explicitly specify `persist = false` when initializing your state.\n\n:::"
  },
  {
    "path": "website/docs/basic_concepts/store.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Store\nA store is a container for states. Store implements and encapsulates everything you need to easily manage your states including `store.setState`, `store.getState`, `store.useState`, `store.subscribe` and other functionalities. A store is created by using `createStore` API as \n\n```js\nimport { createStore } from 'state-pool';\n\nconst store = createStore();\n```\n\n## Adding states to a store\n\nSince a store is just a container for our state, we would eventually need to add states to it. Store provides `store.setState` API which is used to create a state and add it to a store by mapping it to a key. `store.setState` takes two required parameters, a key(string) to map to a state object and the initial value, In addition to those two parameters it takes a third optional parameter which is the configuration object.\n\n```js\n// Signature\nstore.setState(key: String, initialState: Any, config?: {persist: Boolean})\n```\n\nHere is an example showing how to use `store.setState`\n\n```js\nstore.setState(\"count\", 0);\n```\n\n<br/>\n\nAnother way to add state in a store is using `createStore`, in this way we're creating a store and initializing it at the same time. i.e\n\n```js\nimport { createStore } from 'state-pool';\n\nconst store = createStore({\"count\": 0});\n```\n\n```js\n// createStore Signature\ncreateStore({key1: stateValue1, key1, stateValue2, ...})\n```\n\n\n:::important\n\n`store.setState` should be used outside of a react component to make sure that it's executed only once. If you use it inside a react component make sure it's executed only once in order to avoid overriding state in a store.\n\n:::"
  },
  {
    "path": "website/docs/basic_concepts/using_store_state.md",
    "content": "---\nsidebar_position: 2\n---\n\n# Using Store State\nAfter creating a store and setting states to it we need to use our states in components. Here a store provides `store.useState` hook which is used to consume a state from a store in a component, it's basically a way for a component to subscribe to a state from a store.\n\n`store.useState` works just like `React.useState` hook but it accepts a key for the state to use and returns an array of `[state, setState, updateState]` rather than `[state, setState]`.\n\nIn addition to the key parameter it also accept another optional parameter which is the config object, available configurations are `default`, `persist`, `selector` & `patcher`, these are discussed in detail on [`store.useState` API](/docs/api_reference/high_level_api/store.useState).\n\n```js\n// Signature\nstore.useState(\n    key: String,\n    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}\n)\n```\n\nBelow is an example showing how to use `store.useState` hook\n\n```js\nstore.setState(\"user\", {name: \"Yezy\", email: \"yezy@me.com\"});\n\nfunction Component(props){\n    const [user, setUser, updateUser] = store.useState(\"user\");\n    // Other stuff\n}\n```\n\nHere `updateUser` is a higher order function which accepts another function for updating user as an argument(this another functions takes user(old state) as the argument). So to update any value on user you could do\n\n```js\nupdateUser(function(user){\n    user.name = \"Yezy Ilomo\";\n    user.email = \"hello@yezy.com\";\n})\n```\n\nOr you could just use `setUser` instead of `updateUser` i.e\n\n```js\nsetUser({name: \"Yezy Ilomo\", email: \"hello@yezy.com\"});\n```\n\nOr \n\n```js\nsetUser(function(user){\n    return {\n        name: \"Yezy Ilomo\",\n        email: \"hello@yezy.com\"\n    }\n})\n```\n\n\n<br/>\n\nAnother way to use store state is through `store.useReducer` which is an alternative to `store.useState`, it works just like `React.useReducer` hook(If you’re familiar with `React.useReducer`, you already know how this works).\n\n`store.useReducer` accepts a reducer and a key for the state as parameters, it returns the current state paired with a dispatch method.\n\nIn addition to the two parameters it also accept another optinal perameter which is the configuration object, available configurations are `default`, `persist`, `selector` & `patcher`, they work exactly the same just like in `store.useState`.\n\n\nBelow is a simple example showing how to use it\n\n```js\nstore.setState(\"user\", {name: \"Yezy\", email: \"yezy@me.com\"});\n\nfunction myReducer(state, action){\n    // This could be any reducer\n    // Do whatever you want to do here\n    return newState\n}\n\nfunction Component(props){\n    const [name, dispatch] = store.useReducer(myReducer, \"user\");\n\n    // Other stuff ...\n}\n```\n\nYou can learn more about `store.useReducer` on [`store.useReducer` API section](/docs/api_reference/high_level_api/store.useReducer)\n\n<br/>\n\n\n:::tip\nBoth `store.useState` and `store.useReducer` accepts an optional `default` configuration, this is used to specify the default value if you want `store.useState` or `store.useReducer` to create a state if it doesn't find the one for the key specified in the first argument. For example\n\n  ```js\n  const [user, setUser] = store.useState(\"user\", {default: null});\n  ```\n\n  This piece of code means, get the state for the key \"user\" if it's not available in a store, create one and assign it the value `null`. So state pool can create state dynamically.\n:::"
  },
  {
    "path": "website/docs/basic_tutorial/_category_.json",
    "content": "{\n    \"label\": \"Basic Tutorial\",\n    \"position\": 3\n}\n  "
  },
  {
    "path": "website/docs/basic_tutorial/intro.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Intro\n\n## Coming soon...."
  },
  {
    "path": "website/docs/introduction/_category_.json",
    "content": "{\n    \"label\": \"Introduction\",\n    \"position\": 1\n}\n  "
  },
  {
    "path": "website/docs/introduction/getting_started.md",
    "content": "---\nsidebar_position: 3\n---\n\n# Getting Started\nUsing **state-pool** to manage state is very simple, all you need to do is\n1. Create and initialize a state by using `createState`\n2. Use your state in your component through `useState` hooks\n\nThese two steps summarises pretty much everything you need to use **state-pool**.\n\nBelow are few examples showing how to use **state-pool** to manage states.\n\n```jsx\n// Example 1.\nimport React from 'react';\nimport { createState } from 'state-pool';\n\n\nconst count = createState(0);  // Create \"count\" state and initialize it with 0\n\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = count.useState();\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\nThe other way to do it is using `useState` from `state-pool`\n```jsx\n// Example 2.\nimport React from 'react';\nimport { createState, useState } from 'state-pool';\n\n\nconst count = createState(0);  // Create \"count\" state and initialize it with 0\n\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = useState(count);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\n# What about local state?\nWith **state-pool**, state are just like variables, if declared on a global scope, it’s a global state and if declared on local scope it’s a local state, so the difference between global state and local state in **state-pool** lies where you declare them just like variables.\n\nHere is an example for managing local state\n```jsx\n// Example 1.\nimport React from 'react';\nimport { useState } from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    // Note: the `useState` hook used here is impored from state-pool and not react\n    const [count, setCount] = useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n<br/>\n\nIf you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,\n\nHere is an example\n```jsx\n// Example 2.\nimport React from 'react';\nimport StatePool from 'state-pool';\n\n\nfunction ClicksCounter(props){\n    // Here `useState` hook will create \"count\" state and initialize it with 0\n    const [count, setCount] = StatePool.useState(0);\n\n    const incrementCount = (e) => {\n        setCount(count+1)\n    }\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={incrementCount}>Click</button>\n        </div>\n    );\n}\n\nReactDOM.render(ClicksCounter, document.querySelector(\"#root\"));\n```\n\n<br/>\n\n# Isn't `StatePool.useState` the same thing as `React.useState`?\n**Definitely. not!...**\n\nBoth can be used to manage local state, and that's where the similarity ends. `StatePool.useState` offers more features, for one it offers a simple way to update nested data unlike `React.useState`, it's also flexible as it's used to manage both global state and local state. So you could say `React.useState` is a subset of `StatePool.useState`.\n\nHere is an example of `StatePool.useState` in action, updating nested data\n```jsx\n// Example 2.\nimport React from 'react';\nimport StatePool from 'state-pool';\n\n\nconst user = StatePool.createState({name: \"Yezy\", age: 25});\n\nfunction UserInfo(props){\n    const [user, setUser, updateUser] = StatePool.useState(user);\n\n    const updateName = (e) => {\n        updateUser(user => {\n            user.name = e.target.value;\n        });\n    }\n\n    return (\n        <div>\n            Name: {user.name}\n            <br/>\n            <input type=\"text\" value={user.name} onChange={updateName}/>\n        </div>\n    );\n}\n\nReactDOM.render(UserInfo, document.querySelector(\"#root\"));\n```\n\nWith `React.useState` you would need to recreate `user` object when updating `user.name`, but with `StatePool.useState` you don't need that, you just update the value right away. \n\nThat's one advantage of using `StatePool.useState` but there are many more, you'll learn when going through [**documentation**📝](https://yezyilomo.github.io/state-pool/).\n\n\n\n# Store based example\nIf you have many states and you would like to organize them into a store, **state-pool** allows you to do that too and provides a ton of features on top of it.\n\nHere are steps for managing state with a store\n1. Create a store(which is basically a container for your state)\n1. Create and initialize a state by using `store.setState`\n2. Use your state in your component through `store.useState` hooks\n\nThese three steps summarises pretty much everything you need to manage state with a store.\n\nBelow are few examples of store in action\n\n```jsx\n// Example 1.\nimport { createStore } from 'state-pool';\n\n\nconst store = createStore();  // Create store for storing our state\nstore.setState(\"count\", 0);  // Create \"count\" state and add it to the store\n\nfunction ClicksCounter(props){\n    // Use \"count\" state\n    const [count, setCount] = store.useState(\"count\");\n\n    return (\n        <div>\n            Count: {count}\n            <br/>\n            <button onClick={e => setCount(++count)}>Click</button>\n        </div>\n    );\n}\n```\n\n<br/>\n\n```jsx\n// Example 2.\nimport { createStore } from 'state-pool';\n\n\n// Instead of using createStore and store.setState,\n// you can combine store creation and initialization as follows\n\nconst store = createStore({\"user\", {name: \"Yezy\", age: 25}});  // create store and initialize it with user\n\nfunction UserInfo(props){\n    const [user, setUser, updateUser] = store.useState(\"user\");\n\n    const updateName = (e) => {\n        updateUser(user => {\n            user.name = e.target.value;\n        });\n    }\n\n    return (\n        <div>\n            Name: {user.name}\n            <br/>\n            <input type=\"text\" value={user.name} onChange={updateName}/>\n        </div>\n    );\n}\n```\n\n<br/>\n\n**State-pool** doesn't enforce storing your states in a store, If you don't like using the architecture of store you can still use **state-pool** without it. In **state-pool**, store is just a container for states, so you can still use your states without it, in fact **state-pool** doesn’t care where you store your states as long as you can access them you're good to go.\n\n<br/>\n\nPretty cool, right?"
  },
  {
    "path": "website/docs/introduction/installation.md",
    "content": "---\nsidebar_position: 2\n---\n\n# Installation\n```bash\nnpm install state-pool\n```\n\nOr \n\n```bash\nyarn add state-pool\n```"
  },
  {
    "path": "website/docs/introduction/motivation.md",
    "content": "---\nsidebar_position: 1\n---\n\n# Motivation\n\n![Build Status](https://github.com/yezyilomo/state-pool/actions/workflows/node.js.yml/badge.svg?branch=master)\n[![Build Size](https://img.shields.io/bundlephobia/minzip/state-pool?label=bundle-size&style=flat)](https://bundlephobia.com/result?p=state-pool)\n[![Version](https://img.shields.io/npm/v/state-pool?style=flat)](https://www.npmjs.com/package/state-pool)\n[![Downloads](https://img.shields.io/npm/dt/state-pool.svg?style=flat)](https://www.npmjs.com/package/state-pool)\n\nTransform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨\n\n## Features & Advantages\n- Simple, familiar, flexible and very minimal core API but powerful\n- Built-in support for state persistence\n- Very easy to learn because its API is very similar to react state hook's API\n- Support selecting deeply nested state\n- Support creating state dynamically\n- Can be used outside react components\n- Doesn't wrap your app in context providers\n- Very organized API, You can do almost everything with a single import\n\n\n## State Flow\n1. Create a state\n\n2. Subscribe a component(s) to the state created\n\n3. If a component wants to update the state, it sends update request\n\n4. When a state receives update request, it performs the update and send signal to all components subscribed to it for them to update themselves(re-render)\n\nYou can try live examples [Here](https://yezyilomo.github.io/state-pool-examples)"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require('prism-react-renderer/themes/dracula');\nconst darkCodeTheme = require('prism-react-renderer/themes/dracula');\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'State Pool',\n  tagline: 'Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨',\n  url: 'https://yezyilomo.github.io',\n  baseUrl: '/state-pool/',\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n  favicon: 'img/favicon.png',\n  organizationName: 'yezyilomo', // Usually your GitHub org/user name.\n  projectName: 'state-pool', // Usually your repo name.\n\n  presets: [\n    [\n      'classic',\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: require.resolve('./sidebars.js'),\n          // Please change this to your repo.\n          editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',\n        },\n        blog: {\n          showReadingTime: true,\n          // Please change this to your repo.\n          editUrl:\n            'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',\n        },\n        theme: {\n          customCss: require.resolve('./src/css/custom.css'),\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      navbar: {\n        title: 'State Pool',\n        logo: {\n          alt: 'State Pool Logo',\n          src: 'img/logo.svg',\n        },\n        items: [\n          {\n            type: 'doc',\n            docId: 'introduction/motivation',\n            position: 'left',\n            label: 'Docs',\n          },\n          /*{to: '/blog', label: 'Blog', position: 'left'},*/\n          {\n            position: 'left',\n            label: 'Concepts',\n            to: '/docs/basic_concepts/store',\n          },\n          {\n            href: 'https://github.com/yezyilomo/state-pool',\n            label: 'GitHub',\n            position: 'right',\n          },\n        ],\n      },\n      footer: {\n        style: 'dark',\n        links: [\n          {\n            title: 'Docs',\n            items: [\n              {\n                label: 'Tutorial',\n                to: '/docs/basic_tutorial/intro',\n              },\n            ],\n          },\n          {\n            title: 'Community',\n            items: [\n              {\n                label: 'Twitter',\n                href: 'https://twitter.com/yezyilomo',\n              },\n            ],\n          },\n          {\n            title: 'More',\n            items: [\n              /*\n              {\n                label: 'Blog',\n                to: '/blog',\n              },\n              */\n              {\n                label: 'GitHub',\n                href: 'https://github.com/yezyilomo/state-pool/',\n              },\n            ],\n          },\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} State Pool, Inc. Built with Docusaurus.`,\n      },\n      prism: {\n        theme: lightCodeTheme,\n        darkTheme: darkCodeTheme,\n      },\n    }),\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"2.2.0\",\n    \"@docusaurus/preset-classic\": \"2.2.0\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"clsx\": \"^1.1.1\",\n    \"prism-react-renderer\": \"^1.2.1\",\n    \"react\": \"^17.0.1\",\n    \"react-dom\": \"^17.0.1\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\n\n// @ts-check\n\n/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],\n\n  // But you can create a sidebar manually\n  /*\n  tutorialSidebar: [\n    {\n      type: 'category',\n      label: 'Tutorial',\n      items: ['hello'],\n    },\n  ],\n   */\n};\n\nmodule.exports = sidebars;\n"
  },
  {
    "path": "website/src/components/HomepageFeatures/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport styles from './styles.module.css';\n\nconst FeatureList = [\n  {\n    title: 'Simple and Familiar',\n    Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,\n    description: (\n      <>\n        State pool comes with a very simple and intuitive API which\n        follows built in state management patterns in React.\n      </>\n    ),\n  },\n  {\n    title: 'Very Minimal Core API',\n    Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,\n    description: (\n      <>\n        State pool comes with a very minimal API which enables developers to manage\n        global state easly without struggling.\n      </>\n    ),\n  },\n  {\n    title: 'Powerful',\n    Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,\n    description: (\n      <>\n        Despite having minimal API, State pool is very powerful.\n      </>\n    ),\n  },\n];\n\nfunction Feature({Svg, title, description}) {\n  return (\n    <div className={clsx('col col--4')}>\n      <div className=\"text--center\">\n        <Svg className={styles.featureSvg} role=\"img\" />\n      </div>\n      <div className=\"text--center padding-horiz--md\">\n        <h3>{title}</h3>\n        <p>{description}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default function HomepageFeatures() {\n  return (\n    <section className={styles.features}>\n      <div className=\"container\">\n        <div className=\"row\">\n          {FeatureList.map((props, idx) => (\n            <Feature key={idx} {...props} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "website/src/components/HomepageFeatures/styles.module.css",
    "content": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureSvg {\n  height: 200px;\n  width: 200px;\n}\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #2e8555;\n  --ifm-color-primary-dark: #29784c;\n  --ifm-color-primary-darker: #277148;\n  --ifm-color-primary-darkest: #205d3b;\n  --ifm-color-primary-light: #33925d;\n  --ifm-color-primary-lighter: #359962;\n  --ifm-color-primary-lightest: #3cad6e;\n  --ifm-code-font-size: 95%;\n}\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n  --ifm-color-primary: #25c2a0;\n  --ifm-color-primary-dark: #21af90;\n  --ifm-color-primary-darker: #1fa588;\n  --ifm-color-primary-darkest: #1a8870;\n  --ifm-color-primary-light: #29d5b0;\n  --ifm-color-primary-lighter: #32d8b4;\n  --ifm-color-primary-lightest: #4fddbf;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.1);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n\n[data-theme='dark'] .docusaurus-highlight-code-line {\n  background-color: rgba(0, 0, 0, 0.3);\n}\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport Layout from '@theme/Layout';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport styles from './index.module.css';\nimport HomepageFeatures from '@site/src/components/HomepageFeatures';\n\nfunction HomepageHeader() {\n  const {siteConfig} = useDocusaurusContext();\n  return (\n    <header className={clsx('hero hero--primary', styles.heroBanner)}>\n      <div className=\"container\">\n        <h1 className=\"hero__title\">{siteConfig.title}</h1>\n        <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n        <div className={styles.buttons}>\n          <Link\n            className=\"button button--secondary button--lg\"\n            to=\"/docs/introduction/getting_started\">\n            Get started - 5min ⏱️\n          </Link>\n        </div>\n      </div>\n    </header>\n  );\n}\n\nexport default function Home() {\n  const {siteConfig} = useDocusaurusContext();\n  return (\n    <Layout\n      title={`Hello from ${siteConfig.title}`}\n      description=\"Description will go into a meta tag in <head />\">\n      <HomepageHeader />\n      <main>\n        <HomepageFeatures />\n      </main>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "website/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n"
  },
  {
    "path": "website/src/pages/markdown-page.md",
    "content": "---\ntitle: Markdown page example\n---\n\n# Markdown page example\n\nYou don't need React to write simple standalone pages.\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  }
]