Full Code of yezyilomo/state-pool for AI

master 3228011d5254 cached
76 files
132.5 KB
35.2k tokens
60 symbols
1 requests
Download .txt
Repository: yezyilomo/state-pool
Branch: master
Commit: 3228011d5254
Files: 76
Total size: 132.5 KB

Directory structure:
gitextract_iwqcu_93/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── node.js.yml
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── src/
│   ├── State.ts
│   ├── Store.ts
│   ├── index.ts
│   ├── types.ts
│   ├── useReducer.ts
│   └── useState.ts
├── tests/
│   ├── store.clear.test.ts
│   ├── store.getState.test.ts
│   ├── store.getStateValue.test.ts
│   ├── store.has.test.ts
│   ├── store.items.test.ts
│   ├── store.persist.test.ts
│   ├── store.remove.test.ts
│   ├── store.useReducer.test.ts
│   ├── store.useState.test.ts
│   ├── subscription.test.ts
│   ├── useReducer.test.ts
│   └── useState.test.ts
├── tsconfig.json
└── website/
    ├── .gitignore
    ├── README.md
    ├── babel.config.js
    ├── blog/
    │   ├── 2019-05-28-first-blog-post.md
    │   ├── 2019-05-29-long-blog-post.md
    │   ├── 2021-08-01-mdx-blog-post.mdx
    │   ├── 2021-08-26-welcome/
    │   │   └── index.md
    │   └── authors.yml
    ├── docs/
    │   ├── api_reference/
    │   │   ├── _category_.json
    │   │   ├── high_level_api/
    │   │   │   ├── _category_.json
    │   │   │   ├── createStore.md
    │   │   │   ├── store.clear.md
    │   │   │   ├── store.getState.md
    │   │   │   ├── store.getStateValue.md
    │   │   │   ├── store.has.md
    │   │   │   ├── store.items.md
    │   │   │   ├── store.persist.md
    │   │   │   ├── store.remove.md
    │   │   │   ├── store.setState.md
    │   │   │   ├── store.subscribe.md
    │   │   │   ├── store.useReducer.md
    │   │   │   └── store.useState.md
    │   │   ├── intro.md
    │   │   ├── low_level_api/
    │   │   │   ├── _category_.json
    │   │   │   ├── createState.md
    │   │   │   ├── useReducer.md
    │   │   │   └── useState.md
    │   │   └── typing-state.md
    │   ├── basic_concepts/
    │   │   ├── _category_.json
    │   │   ├── derived_state.md
    │   │   ├── managing_subscriptions.md
    │   │   ├── state_persistence.md
    │   │   ├── store.md
    │   │   └── using_store_state.md
    │   ├── basic_tutorial/
    │   │   ├── _category_.json
    │   │   └── intro.md
    │   └── introduction/
    │       ├── _category_.json
    │       ├── getting_started.md
    │       ├── installation.md
    │       └── motivation.md
    ├── docusaurus.config.js
    ├── package.json
    ├── sidebars.js
    ├── src/
    │   ├── components/
    │   │   └── HomepageFeatures/
    │   │       ├── index.js
    │   │       └── styles.module.css
    │   ├── css/
    │   │   └── custom.css
    │   └── pages/
    │       ├── index.js
    │       ├── index.module.css
    │       └── markdown-page.md
    └── static/
        └── .nojekyll

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
patreon: yezyilomo


================================================
FILE: .github/workflows/node.js.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x, 19.x, 20.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v2
      with:
        node-version: ${{ matrix.node-version }}
    - run: npm ci
    - run: npm test  # Run tests 


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build
/dist

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Yezy Ilomo

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

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# [State Pool](https://yezyilomo.github.io/state-pool/)

![Build Status](https://github.com/yezyilomo/state-pool/actions/workflows/node.js.yml/badge.svg?branch=master)
[![Build Size](https://img.shields.io/bundlephobia/minzip/state-pool?label=bundle-size&style=flat)](https://bundlephobia.com/result?p=state-pool)
[![Version](https://img.shields.io/npm/v/state-pool?style=flat)](https://www.npmjs.com/package/state-pool)
[![Downloads](https://img.shields.io/npm/dt/state-pool.svg?style=flat)](https://www.npmjs.com/package/state-pool)

Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨

## Features & Advantages
- Simple, familiar, flexible and very minimal core API but powerful
- Built-in support for state persistence
- Very easy to learn because its API is very similar to react state hook's API
- Support selecting deeply nested state
- Support creating state dynamically
- Can be used outside react components
- Doesn't wrap your app in context providers
- Very organized API, You can do almost everything with a single import

Want to see how this library is making all that possible?

Check out the full documentation at [yezyilomo.github.io/state-pool](https://yezyilomo.github.io/state-pool/)

You can also try live examples [Here](https://yezyilomo.github.io/state-pool-examples)
<br/>

## How it Works
1. Create a state

2. Subscribe a component(s) to the state created

3. If a component wants to update the state, it sends update request

4. 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)

<br/>

## Installation
```sh
npm install state-pool
```

Or 

```sh
yarn add state-pool
```

<br/>

## Getting Started
Using **state-pool** to manage state is very simple, all you need to do is
1. Create and initialize a state by using `createState`
2. Use your state in your component through `useState` hooks

These two steps summarises pretty much everything you need to use **state-pool**.

Below are few examples showing how to use **state-pool** to manage states.

```jsx
// Example 1.
import React from 'react';
import { createState } from 'state-pool';


const count = createState(0);  // Create "count" state and initialize it with 0


function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = count.useState();

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

The other way to do it is using `useState` from `state-pool`
```jsx
// Example 2.
import React from 'react';
import { createState, useState } from 'state-pool';


const count = createState(0);  // Create "count" state and initialize it with 0


function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = useState(count);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

## What about local state?
With **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.

Here is an example for managing local state
```jsx
// Example 1.
import React from 'react';
import { useState } from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    // Note: the `useState` hook used here is impored from state-pool and not react
    const [count, setCount] = useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```
<br/>

If you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,

Here is an example
```jsx
// Example 2.
import React from 'react';
import StatePool from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    const [count, setCount] = StatePool.useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

## Isn't `StatePool.useState` the same thing as `React.useState`?
**Definitely. not!...**

Both 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`.

Here is an example of `StatePool.useState` in action, updating nested data
```jsx
// Example 2.
import React from 'react';
import StatePool from 'state-pool';


const user = StatePool.createState({name: "Yezy", age: 25});

function UserInfo(props){
    const [user, setUser, updateUser] = StatePool.useState(user);

    const updateName = (e) => {
        updateUser(user => {
            user.name = e.target.value;
        });
    }

    return (
        <div>
            Name: {user.name}
            <br/>
            <input type="text" value={user.name} onChange={updateName}/>
        </div>
    );
}

ReactDOM.render(UserInfo, document.querySelector("#root"));
```

With `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. 

That'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/).



## Store based example
If 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.

Here are steps for managing state with a store
1. Create a store(which is basically a container for your state)
1. Create and initialize a state by using `store.setState`
2. Use your state in your component through `store.useState` hooks

These three steps summarises pretty much everything you need to manage state with a store.

Below are few examples of store in action

```jsx
// Example 1.
import { createStore } from 'state-pool';


const store = createStore();  // Create store for storing our state
store.setState("count", 0);  // Create "count" state and add it to the store

function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = store.useState("count");

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={e => setCount(++count)}>Click</button>
        </div>
    );
}
```

<br/>

```jsx
// Example 2.
import { createStore } from 'state-pool';


// Instead of using createStore and store.setState,
// you can combine store creation and initialization as follows

const store = createStore({"user", {name: "Yezy", age: 25}});  // create store and initialize it with user

function UserInfo(props){
    const [user, setUser, updateUser] = store.useState("user");

    const updateName = (e) => {
        updateUser(user => {
            user.name = e.target.value;
        });
    }

    return (
        <div>
            Name: {user.name}
            <br/>
            <input type="text" value={user.name} onChange={updateName}/>
        </div>
    );
}
```

<br/>

**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.

<br/>

Pretty cool, right?


## [Documentation 📝](https://yezyilomo.github.io/state-pool/)
Full 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).


## Running Tests
If you've forked this library and you want to run tests use the following command

```sh
npm test
```


================================================
FILE: babel.config.js
================================================
// babel.config.js
module.exports = {
    presets: ['@babel/preset-env', '@babel/preset-react'],
};


================================================
FILE: package.json
================================================
{
    "name": "state-pool",
    "private": true,
    "version": "0.10.2",
    "description": "Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨",
    "license": "MIT",
    "homepage": "https://github.com/yezyilomo/state-pool/blob/master/README.md",
    "repository": "https://github.com/yezyilomo/state-pool",
    "bugs": "https://github.com/yezyilomo/state-pool/issues",
    "keywords": [
        "state",
        "immutable"
    ],
    "authors": [
        "Yezileli Ilomo <yezileliilomo@hotmail.com> (https://github.com/yezyilomo)"
    ],
    "main": "index.js",
    "module": "esm/index.js",
    "types": "index.d.ts",
    "files": [
        "**"
    ],
    "sideEffects": false,
    "scripts": {
        "prebuild": "shx rm -rf dist",
        "build": "tsc",
        "postbuild": "npm run copy",
        "test": "shx rm -rf dist && tsc && jest ./dist/test && shx rm -rf dist",
        "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;\"",
        "publish:dist": "npm run build && cd dist && npm publish"
    },
    "exports": {
        "./package.json": "./package.json",
        ".": {
            "types": "./index.d.ts",
            "module": "./esm/index.js",
            "import": "./esm/index.js",
            "default": "./index.js"
        }
    },
    "dependencies": {
        "immer": ">=10.0.0"
    },
    "peerDependencies": {
        "react": ">=16.8.3"
    },
    "devDependencies": {
        "@babel/preset-env": "latest",
        "@babel/preset-react": "latest",
        "@testing-library/react-hooks": "latest",
        "@types/jest": "latest",
        "@babel/eslint-parser": "latest",
        "babel-jest": "latest",
        "jest": "latest",
        "json": "latest",
        "react": "latest",
        "react-test-renderer": "latest",
        "shx": "latest",
        "typescript": "latest"
    }
}


================================================
FILE: src/State.ts
================================================
import { produce, nothing } from "immer";
import {
    StateInitializer, Selector, Patcher,
    Reducer, Unsubscribe, StateModifier,
    StateUpdater, SetState, UpdateState,
} from './types';
import _useState from "./useState";
import _useReducer from "./useReducer";



type Refresh = () => void

// Might subscribe to derived/selected state, so we use <ST> cuz it might not always be <T>
type Observer<ST> = (newState: ST) => void

// Subscribe to a state
type Subscriber<ST> = {
    observer: Observer<ST>,
    selector: Selector<ST>,
    refresh?: Refresh
}


export default class State<T> {
    private value: T;
    private subscribers: Array<Subscriber<unknown>>;

    constructor(initialValue: StateInitializer<T> | T) {
        if (typeof initialValue === "function") {
            this.value = (initialValue as StateInitializer<T>)();
        }
        else {
            this.value = initialValue as T;
        }
        this.subscribers = [];
    }

    getValue<ST>(selector?: Selector<ST>): T | ST {
        if (selector) {
            return selector(this.value);
        }
        return this.value;
    }

    refresh(): void {
        this.subscribers.forEach(subscriber => {
            if (subscriber.refresh) {
                subscriber.refresh();
            }
        });
    }

    setValue(
        newValue: T | StateUpdater<T>
    ): void;

    setValue<ST>(
        newValue: ST | StateUpdater<ST>,
        config: { selector?: Selector<ST> }
    ): void;

    setValue<ST>(
        newValue: ST | StateUpdater<ST>,
        config: { selector?: Selector<ST>, patcher?: Patcher<ST> },
    ): void;

    setValue<ST>(
        newValue: (T | ST) | StateUpdater<T | ST>,
        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},
    ): void {
        if (newValue === undefined) {
            this.__updateValue<T | ST>(
                (draftVal) => nothing as undefined,  // nothing is equivalent to undefined
                config
            )
        }
        else if (typeof newValue === 'function') {
            const reducer = newValue as StateUpdater<T | ST>

            this.setValue(
                reducer(this.getValue(config.selector)), config
            )
        }
        else {
            this.__updateValue<T | ST>(
                (draftVal) => newValue,
                config
            )
        }
    }


    updateValue(
        stateModifier: StateModifier<T>
    ): void;

    updateValue<ST>(
        stateModifier: StateModifier<ST>,
        config: { selector?: Selector<ST> }
    ): void;

    updateValue<ST>(
        stateModifier: StateModifier<ST>,
        config: { selector?: Selector<ST>, patcher?: Patcher<ST> }
    ): void;

    updateValue<ST>(
        stateModifier: StateModifier<T> | StateModifier<ST>,
        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},
    ): void {
        const stateModifierWrapper = function (draftState) {
            // This wrapper is for disabling setting returned value
            // We don't allow returned value to be set(just return undefined)
            stateModifier(draftState)
        }

        this.__updateValue<ST>(stateModifierWrapper, config)
    }

    private __updateValue<ST>(stateUpdater: StateUpdater<T | ST> | StateModifier<T | ST>, config): void {
        // No need to do a lot of type checking here bcuz this is an internal method
        const selector = config.selector as Selector<ST>;
        const patcher = config.patcher as Patcher<ST>;

        const oldState = this.value;

        let newState: T;
        if (selector && patcher) {
            // Update the selected node first and get its value
            const selectedNodeValue: ST = produce(selector(oldState), stateUpdater) as ST;

            // Here we're patching back the updated selected node to the main state
            newState = produce(
                oldState,
                (draftCurrentState: T) => {
                    // Avoid setting returns
                    patcher(draftCurrentState, selectedNodeValue);
                }
            )
        }
        else {
            newState = produce(oldState, stateUpdater);
        }

        this.value = newState;

        if (newState !== oldState) {
            // There's a new update
            this.subscribers.forEach(subscriber => {
                if (subscriber.selector(newState) !== subscriber.selector(oldState)) {
                    // Node value has changed
                    subscriber.observer(
                        subscriber.selector(newState)
                    );
                }
            });
        }
    }

    subscribe<ST>(itemToSubscribe: Subscriber<T | ST> | Observer<T | ST>): Unsubscribe {
        let _itemToSubscribe;
        if (typeof itemToSubscribe === 'function') {
            const selector: Selector<T> = (state) => state;
            _itemToSubscribe = {
                observer: itemToSubscribe as Observer<T>,
                selector: selector
            } as Subscriber<T>;
        }
        else {
            _itemToSubscribe = itemToSubscribe as Subscriber<ST>;
        }

        if (this.subscribers.indexOf(_itemToSubscribe) === -1) {
            // Subscribe a component to this state
            this.subscribers.push(_itemToSubscribe);
        };

        const unsubscribe = () => {
            this.subscribers = this.subscribers.filter(
                subscriber => (subscriber !== _itemToSubscribe)
            );
        }

        return unsubscribe;
    }

    select<ST>(selector: Selector<ST>): DerivedState<T, ST> {
        return createDerivedState(this, selector);
    }


    useState(config?: {}): [
        state: T,
        setState: SetState<T>,
        updateState: UpdateState<T>,
        stateObject: State<T>
    ];

    useState<ST>(
        config: { selector: Selector<ST> },
    ): [
            state: ST,
            setState: SetState<T>,
            updateState: UpdateState<T>,
            stateObject: State<T>
        ];

    useState<ST>(
        config: { selector: Selector<ST>, patcher: Patcher<ST> },
    ): [
            state: ST,
            setState: SetState<ST>,
            updateState: UpdateState<ST>,
            stateObject: State<T>
        ]

    useState<ST>(
        config: { selector?: Selector<T | ST>, patcher?: Patcher<T | ST> } = {},
    ): [
            state: T | ST,
            setState: SetState<T | ST>,
            updateState: UpdateState<T | ST>,
            stateObject: State<T>
        ] {
        return _useState(this, config);
    }


    useReducer<_T extends T, A>(
        reducer: Reducer<_T, A>,
        config?: {}
    ): [
            state: _T,
            dispatch: (action: A) => void,
            stateObject: State<_T>
        ];

    useReducer<ST, A>(
        reducer: Reducer<ST, A>,
        config: { selector: Selector<ST> }
    ): [
            state: ST,
            dispatch: (action: A) => void,
            stateObject: State<T>
        ];

    useReducer<ST, A>(
        reducer: Reducer<ST, A>,
        config: { selector: Selector<ST>, patcher: Patcher<ST> }
    ): [
            state: ST,
            dispatch: (action: A) => void,
            stateObject: State<T>
        ]

    useReducer(
        reducer: Reducer<unknown, unknown>,
        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {}
    ): [
            state: unknown,
            dispatch: (action: unknown) => void,
            stateObject: State<unknown>
        ] {
        return _useReducer(reducer, this, config);
    }
}


export class DerivedState<T, ST> {
    State: State<unknown>;
    selector: Selector<ST>;

    constructor(State: State<unknown>, selector: Selector<ST>) {
        this.State = State;
        this.selector = selector;
    }

    getValue(): ST {
        return this.State.getValue(this.selector) as ST;
    }

    subscribe(observer?: Observer<ST>, refresh?: Refresh): Unsubscribe {
        const itemToSubscribe: Subscriber<ST> = {
            observer: observer,
            selector: this.selector,
            refresh: refresh
        }

        return this.State.subscribe(itemToSubscribe);
    }
}


export function createDerivedState<T, ST>(State: State<T>, selector: Selector<ST>): DerivedState<T, ST> {
    return new DerivedState<T, ST>(State, selector);
}


export function createState<T>(initialValue: StateInitializer<T> | T): State<T> {
    return new State<T>(initialValue);
}

================================================
FILE: src/Store.ts
================================================
import State, { createState } from './State';
import {
    StateInitializer, Selector, Patcher,
    Reducer, SetState, Unsubscribe, UpdateState
} from './types';



// Observer function for a store
type StoreObserver = (key: string, value: unknown) => void

type PersistenceConfig = {
    saveState: (key: string, state: unknown, isInitialSet: boolean) => void,
    loadState: (key: string, noState: Empty) => unknown,
    removeState?: (key: string) => void,
    clear?: () => void,
    PERSIST_ENTIRE_STORE?: boolean
}

type StoreState<T> = {
    state: State<T>,
    unsubscribe: Unsubscribe,
    persist: boolean
}

type StoreInitializer = { [key: string]: unknown } | (() => { [key: string]: unknown });


const notImplementedErrorMsg = [
    `You must implement 'loadState' and 'saveState' to be able `,
    'to save state to your preffered storage. E.g \n',
    'store.persist({ \n',
    '    saveState: function(key, state, isInitialSet){/*Code to save state to your storage*/}, \n',
    '    loadState: function(key, noState){/*Code to load state from your storage*/} \n',
    '}) \n'
].join("");


class Empty { }  // Class for empty state/value
const EMPTY = new Empty();

class PersistentStorage {
    SHOULD_PERSIST_BY_DEFAULT: boolean = false;

    loadState(key: string, noState: Empty): unknown {
        throw TypeError(notImplementedErrorMsg);
    }

    saveState(key: string, state: unknown, isInitialSet?: boolean) {
        throw TypeError(notImplementedErrorMsg);
    }

    removeState: (key: string) => void

    clear: () => void
}


export default class Store {
    private states: Map<string, StoreState<unknown>>;
    private subscribers: Array<StoreObserver>;
    private persistentStorage: PersistentStorage;

    constructor(storeInitializer?: StoreInitializer) {
        this.states = new Map();
        this.subscribers = [];
        this.persistentStorage = new PersistentStorage();

        if (storeInitializer) {
            if (typeof storeInitializer === "function") {
                storeInitializer = storeInitializer();
            }

            for (let key in storeInitializer) {
                if (storeInitializer.hasOwnProperty(key)) {
                    this.setState(key, storeInitializer[key]);
                }
            }
        }
    }

    subscribe(observer: StoreObserver): () => void {
        if (this.subscribers.indexOf(observer) === -1) {
            // Subscribe a component to this store
            this.subscribers.push(observer);
        }

        const unsubscribe = () => {
            this.subscribers = this.subscribers.filter(
                subscriber => subscriber !== observer
            );
        }

        return unsubscribe
    }

    private onStoreUpdate(key: string, value: unknown): void {
        this.subscribers.forEach(subscriber => {
            subscriber(key, value);
        });
    }

    persist(config: PersistenceConfig): void {
        if (config.saveState) {
            this.persistentStorage.saveState = config.saveState;
        }
        if (config.loadState) {
            this.persistentStorage.loadState = config.loadState;
        }
        if (config.removeState) {
            this.persistentStorage.removeState = config.removeState;
        }
        if (config.clear) {
            this.persistentStorage.clear = config.clear;
        }
        if (config.PERSIST_ENTIRE_STORE) {
            this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT = config.PERSIST_ENTIRE_STORE;
        }
    }

    setState<T>(
        key: string,
        initialValue: StateInitializer<T> | T,
        { persist }: { persist?: boolean } = {}
    ): void {

        const shouldPersist: boolean = persist === undefined ?
            this.persistentStorage.SHOULD_PERSIST_BY_DEFAULT : persist;

        let shouldSaveToPersistentStorage = false;

        if (shouldPersist) {
            // Try to load state from persistent storage
            const savedState = this.persistentStorage.loadState(key, EMPTY);

            if (savedState !== EMPTY) {
                // We have a saved state, so we use it as the initialValue
                initialValue = savedState as T;
            }
            else {
                // We don't have a saved state so we have to set/save it
                // Here we set this flag to true but we'll save later after creating a state successfully
                shouldSaveToPersistentStorage = true;
            }
        }


        const onStateChange = (newValue: unknown) => {
            // Note key & persist variables depends on scope

            this.onStoreUpdate(key, newValue);

            if (shouldPersist) {
                this.persistentStorage.saveState(key, newValue, false);
            }
        }

        // Create a state
        const state: State<T> = createState<T>(initialValue);
        const unsubscribe = state.subscribe({
            observer: onStateChange,
            selector: (st) => st
        });
        const storeState = {
            "state": state,
            "unsubscribe": unsubscribe,
            "persist": shouldPersist
        }
        // Add state to the store
        this.states.set(key, storeState);

        if (shouldSaveToPersistentStorage) {
            // Saving state to persistent storage after we've created it successfully
            this.persistentStorage.saveState(key, state.getValue(), true);
        }
    }

    getState<T>(
        key: string,
        config: { default?: StateInitializer<T> | T, persist?: boolean } = {}
    ): State<T> {
        let defaultValue;
        if (config.hasOwnProperty('default')) {
            // Use has set default explicitly
            defaultValue = config.default
        }
        else {
            // No default value
            defaultValue = EMPTY;
        }

        // Get key based state
        if (!this.has(key)) {  // state is not found
            if (defaultValue !== EMPTY) {  // Default value is found
                // Create a state and use defaultValue as the initial value
                this.setState<T>(
                    key,
                    defaultValue as (StateInitializer<T> | T),  // Make sure we don't pass EMPTY value
                    { persist: config.persist }
                );
            }
            else {
                // state is not found and the default value is not specified
                const errorMsg = [
                    `There is no state with the key '${key}', `,
                    `You are either trying to access a `,
                    `state that doesn't exist or it was deleted.`
                ];
                throw Error(errorMsg.join(""));
            }
        }
        return this.states.get(key).state as State<T>;
    }

    has(key: string) {
        // Check if we have a state in a store
        return this.states.has(key);
    }

    items(): Array<[key: string, state: unknown, persist: boolean]> {
        const storeItems = [];
        this.states.forEach((storeState, key) => {
            storeItems.push([key, storeState.state.getValue(), storeState.persist]);
        })
        return storeItems;
    }

    getStateValue<ST, T = unknown>(key: string, selector?): T | ST {
        const state = this.getState<T>(key);
        return state.getValue<ST>(selector);
    }

    clear(fn?: () => void): void {
        // Copy store
        const storeCopy = this.states;

        // Clear store
        this.states = new Map();
        if (this.persistentStorage.clear) {
            try {
                this.persistentStorage.clear()
            } catch (error) {
                // Ignore errors in clearing states
            }
        }

        if (fn) {
            // Run store re-initialization
            fn();
        }

        storeCopy.forEach((oldState, key) => {
            // Unsubscribe from an old state 
            oldState.unsubscribe()
            // Notify subscribers to a store that a state has been removed
            if (this.has(key)) {
                const newState = this.getState(key);
                this.onStoreUpdate(key, newState.getValue());
            }
            // Rerender all components using this state
            oldState.state.refresh();
        })
    }

    remove(Statekey: string | string[], fn?: () => void): void {
        let keys: string[] = [];
        if (typeof Statekey === 'string') {
            keys = [Statekey];
        }
        else {
            keys = Statekey;
        }

        const StatesToRemove: Map<string, StoreState<unknown>> = new Map();
        keys.forEach(key => {
            // Copy state to remove from a store
            StatesToRemove.set(key, this.states.get(key));

            // Remove state from a store
            this.states.delete(key);
            if (
                StatesToRemove.get(key).persist &&  // Is state persisted
                this.persistentStorage.removeState  // Is removeState Implemented
            ) {
                try {
                    this.persistentStorage.removeState(key);
                } catch (error) {
                    // Ignore error in removing state
                }
            }
        });

        if (fn) {
            // Run state re-initialization
            fn();
        }

        StatesToRemove.forEach((oldState, key) => {
            // Unsubscribe from an old state 
            oldState.unsubscribe()
            // Notify subscribers to a store that a state has been removed
            if (this.has(key)) {
                const newState = this.getState(key);
                this.onStoreUpdate(key, newState.getValue());
            }

            // Rerender all components depending on this state
            oldState.state.refresh();
        })
    }


    useState<T>(
        key: string,
        config?: { default?: StateInitializer<T> | T, persist?: boolean }
    ): [
            state: T,
            setState: SetState<T>,
            updateState: UpdateState<T>,
            stateObject: State<T>
        ];

    useState<ST, T>(
        key: string,
        config: { selector: Selector<ST>, default?: StateInitializer<T> | T, persist?: boolean },
    ): [
            state: ST,
            setState: SetState<T>,
            updateState: UpdateState<T>,
            stateObject: State<T>
        ];

    useState<ST, T>(
        key: string,
        config: { selector: Selector<ST>, patcher: Patcher<ST>, default?: StateInitializer<T> | T, persist?: boolean },
    ): [
            state: ST,
            setState: SetState<ST>,
            updateState: UpdateState<ST>,
            stateObject: State<T>
        ]

    useState(
        key: string,
        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown>, default?: unknown, persist?: boolean } = {}
    ): [
            state: unknown,
            setState: SetState<unknown>,
            updateState: UpdateState<unknown>,
            stateObject: State<unknown>
        ] {
        const storeStateConfig = config as { default?, persist?};
        const stateConfig = config as { selector?, patcher?};

        const state = this.getState(key, storeStateConfig);
        return state.useState(stateConfig);
    }


    useReducer<T, A>(
        reducer: Reducer<T, A>,
        key: string,
        config?: { default?: StateInitializer<T> | T, persist?: boolean }
    ): [
            state: T,
            dispatch: (action: A) => void,
            stateObject: State<T>
        ];

    useReducer<ST, A, T = unknown>(
        reducer: Reducer<ST, A>,
        key: string,
        config: { selector?: Selector<ST>, default?: StateInitializer<T> | T | never, persist?: boolean }
    ): [
            state: ST,
            dispatch: (action: A) => void,
            stateObject: State<T>
        ];

    useReducer<ST, A, T = unknown>(
        reducer: Reducer<ST, A>,
        key: string,
        config: { selector?: Selector<ST>, patcher?: Patcher<ST>, default?: StateInitializer<T> | T | never, persist?: boolean }
    ): [
            state: ST,
            dispatch: (action: A) => void,
            stateObject: State<T>
        ]

    useReducer(
        reducer: Reducer<unknown, unknown>,
        key: string,
        config: { selector?: Selector<unknown>, patcher?: Patcher<unknown>, default?: unknown, persist?: boolean } = {}
    ): [
            state: unknown,
            dispatch: unknown,
            stateObject: State<unknown>
        ] {
        const storeStateConfig = config as { default?, persist?};
        const stateConfig = config as { selector?, patcher?};

        const state = this.getState(key, storeStateConfig);
        return state.useReducer(reducer, stateConfig);
    }
}


export function createStore(storeInitializer?: StoreInitializer): Store {
    // Create a store for key based state
    return new Store(storeInitializer);
}


================================================
FILE: src/index.ts
================================================
import State, { createState, DerivedState, createDerivedState } from './State';
import Store, { createStore } from './Store';
import useReducer from './useReducer';
import useState from './useState';


export {
    State, createState,
    Store, createStore,
    useState, useReducer,
    DerivedState, createDerivedState,
};


const StatePool = {
    State, createState,
    Store, createStore,
    useState, useReducer,
    DerivedState, createDerivedState,
}

export default StatePool;

================================================
FILE: src/types.ts
================================================
// Note; In all cases ST stands for type of selected state and T for base/original state

// Function to call to unsubscribe from a state or a store
export type Unsubscribe = () => void

// Reducer tha's passed in useReducer hook
export type Reducer<ST, A> = (state: ST, action: A) => ST

// What's important is the type of what's returned, lib is the one passing state, so noworries
export type Selector<ST> = (state: any) => ST

// What's important is the type of value(to set), the lib is the one passing state, so noworries
export type Patcher<ST> = (state: any, value: ST) => void

// Function for initializing state
export type StateInitializer<T> = () => T

// What's important is the export type of what's returned, lib is the one passing state
export type StateUpdater<ST> = (state: ST) => ST

// Given the obj to modify, it does modifications and return nothing
export type StateModifier<ST> = (state: ST) => void

// Setter returned by useState hook
export type SetState<ST> = (newState: ST | StateUpdater<ST>) => void

// Updater returned by useState hook
export type UpdateState<ST> = (updater: StateModifier<ST>) => void

================================================
FILE: src/useReducer.ts
================================================
import React from 'react';
import State, { createState } from './State';
import { Patcher, Reducer, Selector, StateInitializer } from './types';



function useStateObject(state) {
    // This is for internal use only
    const localStateRef = React.useMemo(() => {
        if (state instanceof State) {
            // We have a global state, so we'll simply pass it out
            return null;
        }
        else {
            // We have a local state, so we create state obj and keep its ref for futer renders
            return createState(state);
        }
    }, [])

    let stateObject: State<unknown>;
    if (localStateRef instanceof State) {
        stateObject = localStateRef;
    }
    else {
        stateObject = state as State<unknown>;
    }

    return stateObject;
}


export default function useReducer<T, A>(
    reducer: Reducer<T, A>,
    state: State<T> | StateInitializer<T> | T,
    config?: {}
): [
        state: T,
        dispatch: (action: A) => void,
        stateObject: State<T>
    ];

export default function useReducer<ST, A, T = unknown>(
    reducer: Reducer<ST, A>,
    state: State<T | never> | StateInitializer<T> | T,
    config: { selector: Selector<ST> }
): [
        state: ST,
        dispatch: (action: A) => void,
        stateObject: State<T>
    ];

export default function useReducer<ST, A, T = unknown>(
    reducer: Reducer<ST, A>,
    state: State<T | never> | StateInitializer<T> | T,
    config: { selector: Selector<ST>, patcher: Patcher<ST> }
): [
        state: ST,
        dispatch: (action: A) => void,
        stateObject: State<T>
    ];

export default function useReducer(
    reducer: Reducer<unknown, unknown>,
    state: State<unknown> | unknown,
    config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {}
): [
        state: unknown,
        dispatch: unknown,
        stateObject: State<unknown>
    ] {
    const [, setState] = React.useState(null);
    const isMounted = React.useRef(false);

    const stateObject = useStateObject(state);

    const currentState = stateObject.getValue(config.selector);

    function reRender() {
        // re-render if the component is mounted
        if (isMounted.current) {
            setState({});
        }
    }

    function observer(newState) {
        if (currentState === newState) {
            // Do nothing because the selected state is up-to-date
        }
        else {
            reRender();
        }
    }

    const subscription = {
        observer: observer,
        selector: config.selector ?
            config.selector :
            (state) => state,  // Select the whole state if selector is not specified
        refresh: reRender
    }

    React.useEffect(() => {
        const unsubscribe = stateObject.subscribe(subscription);
        isMounted.current = true;

        return () => {
            unsubscribe();
            isMounted.current = false;
        }
    }, [currentState, State])

    function dispatch(action: unknown) {
        const newState = reducer(currentState, action);
        stateObject.setValue(newState, config);
    }

    return [currentState, dispatch, stateObject]
}


================================================
FILE: src/useState.ts
================================================
import React from 'react';
import useReducer from './useReducer';
import State, { createState } from './State';
import { Patcher, Selector, SetState, StateInitializer, UpdateState } from './types';



export default function useState<T>(
    state: State<T> | StateInitializer<T> | T,
    config?: {}
): [
        state: T,
        setState: SetState<T>,
        updateState: UpdateState<T>,
        stateObject: State<T>
    ];

export default function useState<ST, T = unknown>(
    state: State<T | never> | StateInitializer<T> | T,
    config: { selector: Selector<ST> },
): [
        state: ST,
        setState: SetState<T>,
        updateState: UpdateState<T>,
        stateObject: State<T>
    ];

export default function useState<ST, T = unknown>(
    state: State<T | never> | StateInitializer<T> | T,
    config: { selector: Selector<ST>, patcher: Patcher<ST> },
): [
        state: ST,
        setState: SetState<ST>,
        updateState: UpdateState<ST>,
        stateObject: State<T>
    ];

export default function useState(
    state: State<unknown> | unknown,
    config: { selector?: Selector<unknown>, patcher?: Patcher<unknown> } = {},
): [
        state: unknown,
        setState: SetState<unknown>,
        updateState: UpdateState<unknown>,
        stateObject: State<unknown>
    ] {

    function reducer(currentState, newState) {
        return newState;
    }

    const [stateValue, setStateValue, stateObject] = useReducer(reducer, state, config);

    function updateStateValue(updater): void {
        stateObject.updateValue(updater, config);
    }

    return [stateValue, setStateValue, updateStateValue, stateObject];
}

================================================
FILE: tests/store.clear.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { createStore } from '../src/';


const store = createStore();
store.setState("count", 0);

test('should clear the entire store and initialize `count` with 5', () => {
    const hook1 = renderHook(() => store.useState("count"))

    act(() => {
        hook1.result.current[1](count => 1)
    })

    act(() => {
        store.clear(()=>{ store.setState("count", 5); })
    })

    expect(hook1.result.current[0]).toStrictEqual(5)
})


const store2 = createStore();
store2.setState("count", 0);

test('should clear the entire store and initialize `age` with 18', () => {
    const hook2 = renderHook(() => store2.useState("age", {default: 18}));

    act(() => {
        hook2.result.current[1](age => age + 2)
    })

    act(() => {
        store2.clear(()=>{ })
    })

    expect(hook2.result.current[0]).toStrictEqual(18)
})



================================================
FILE: tests/store.getState.test.ts
================================================
import StatePool, { State } from '../src/';


const store = StatePool.createStore({count: 0});

test('should get user values', () => {
    const isStateInstance = store.getState("count") instanceof State;
    expect(isStateInstance).toStrictEqual(true)
})

================================================
FILE: tests/store.getStateValue.test.ts
================================================
import React from 'react';
import StatePool from '../src/';


const store = StatePool.createStore({
    user: { name: "Yezy", age: 20 }
});

test('should get user values', () => {
    const selector = (user): string => user.name;

    expect(store.getStateValue("user")).toStrictEqual({ name: "Yezy", age: 20 })
    expect(store.getStateValue("user", selector)).toStrictEqual("Yezy")
})

================================================
FILE: tests/store.has.test.ts
================================================
import StatePool from '../src/';


const store = StatePool.createStore({ count: 0 });

test('should get user values', () => {
    const inStore = store.has("count");
    const notInStore = store.has("user");

    expect(inStore).toStrictEqual(true);
    expect(notInStore).toStrictEqual(false);
})

================================================
FILE: tests/store.items.test.ts
================================================
import StatePool from '../src/';


const store = StatePool.createStore({
    width: 10,
    height: 15
});

test('should get user values', () => {
    const [item1, item2] = store.items()

    expect(item1).toStrictEqual(["width", 10, false]);
    expect(item2).toStrictEqual(["height", 15, false]);
})

================================================
FILE: tests/store.persist.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { createStore } from '../src/';


const store = createStore();

let storage: {count?: number, age?: number} = {
    "count": 10  // Pre-set count state to storage
}

store.persist({
    saveState: (key, value) => {
        storage[key] = value;
    },
    loadState: (key, noState) => {
        if (storage.hasOwnProperty(key)) {
            return storage[key]
        }
        return noState;
    },
    removeState: (key) => {
        delete storage[key];
    },
    clear: () => {
        storage = {};  // Clear a store
    }
})

store.setState("count", 0, {persist: true});

test('should update count', () => {
    const { result } = renderHook(() => store.useState("count"))

    act(() => {
        result.current[1](count => count + 1)  // Will use the value from storage instead of 0
    })

    expect(result.current[0]).toStrictEqual(11)
})


test('should create `age` state with the given default value', () => {
    const { result } = renderHook(() => store.useState("age", {default: 18, persist: true}));

    // age state will be saved to a store
    expect(storage.age).toStrictEqual(18);

    act(() => {
        result.current[1](age => age + 2);  // Will use the default value 18
    })

    expect(result.current[0]).toStrictEqual(20);
    expect(storage.age).toStrictEqual(20);
})


test('should remove count state from store and storage', () => {
    const { result } = renderHook(() => store.useState("count"))

    act(() => {
        store.remove("count", () => {
            store.setState("count", 5, {persist: true});
        });  // This will remove count state from a store and reset it
    })

    expect(result.current[0]).toStrictEqual(5);
    expect(storage.count).toStrictEqual(5);
    expect(storage.age).toStrictEqual(20);
})


test('should clear both store and storage', () => {
    const { result } = renderHook(() => store.useState("count"))

    act(() => {
        store.clear(() => {
            store.setState("count", 10, {persist: true});
        });  // This will clear a store and reset count state
    })

    expect(result.current[0]).toStrictEqual(10);
    expect(storage.count).toStrictEqual(10);
    expect(storage.age).toStrictEqual(undefined);
})




// Test PERSIST_ENTIRE_STORE = True

const store2 = createStore();

let storage2: {count?: number, age?: number, weight?: number} = {
    "count": 10  // Pre-set count state to storage2
}

store2.persist({
    PERSIST_ENTIRE_STORE: true,
    saveState: (key, value) => {
        storage2[key] = value;
    },
    loadState: (key, noState) => {
        if (storage2.hasOwnProperty(key)) {
            return storage2[key]
        }
        return noState;
    },
    removeState: (key) => {
        delete storage2[key];
    },
    clear: () => {
        storage2 = {};  // Clear a store2
    }
})

store2.setState("count", 0);
store2.setState("weight", 50, {persist: false})  // Won't save this to permanent storage

test('should update count', () => {
    const { result } = renderHook(() => store2.useState("count"))

    act(() => {
        result.current[1](count => count + 1)  // Will use the value from storage2 instead of 0
    })

    expect(result.current[0]).toStrictEqual(11)
})


test('should not save weight to storage2', () => {
    const { result } = renderHook(() => store2.useState("weight"))

    act(() => {
        result.current[1](55)
    })

    expect(result.current[0]).toStrictEqual(55)
    expect(storage2.weight).toStrictEqual(undefined);
})


test('should create `age` state with the given default value', () => {
    const { result } = renderHook(() => store2.useState("age", {default: 18}));

    // age state will be saved to a store2
    expect(storage2.age).toStrictEqual(18);

    act(() => {
        result.current[1](age => age + 2);  // Will use the default value 18
    })

    expect(result.current[0]).toStrictEqual(20);
    expect(storage2.age).toStrictEqual(20);
})


================================================
FILE: tests/store.remove.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { createStore } from '../src/';


const store = createStore();
store.setState("count", 0);

test('should remove `count` state and re-initialize it with 5', () => {
    const hook1 = renderHook(() => store.useState("count"))

    act(() => {
        hook1.result.current[2](count => 1)
    })

    act(() => {
        store.remove("count", ()=>{ store.setState("count", 5); })
    })

    expect(hook1.result.current[0]).toStrictEqual(5)
})


const store2 = createStore();
store2.setState("count", 0);

test('should remove `age` state and re-initialize it with 18', () => {
    const hook2 = renderHook(() => store2.useState("age", {default: 18}));

    act(() => {
        hook2.result.current[2](age => age + 2)
    })

    act(() => {
        store2.remove("age")
    })

    expect(hook2.result.current[0]).toStrictEqual(18)
})



================================================
FILE: tests/store.useReducer.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { createStore } from '../src/';


const store = createStore();
store.setState("count", 0);

test('should update count', () => {
    const reducer = (state, newState) => newState;

    const { result } = renderHook(() => store.useReducer(reducer, "count"))

    act(() => {
        result.current[1](1)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('should create `age` state with the given default value', () => {
    const reducer = (state: number, newState: number): number => newState;

    const { result } = renderHook(() => store.useReducer(reducer, "age", {default: 18}));

    act(() => {
        result.current[1](result.current[0] + 2)
    })

    expect(result.current[0]).toStrictEqual(20)
})



================================================
FILE: tests/store.useState.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import StatePool from '../src/';


const store = StatePool.createStore({ count: 0 });  // initialize store during instantiation

test('should update count', () => {
    const { result } = renderHook(() => store.useState("count"))

    act(() => {
        result.current[1](count => 1)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('should create `age` state with the given default value', () => {
    const { result } = renderHook(() => store.useState("age", { default: 18 }));

    act(() => {
        result.current[1](age => age + 2)
    })

    expect(result.current[0]).toStrictEqual(20)
})


store.setState<{ name: string, age: number }>("user", { name: "Yezy", age: 20 });

test('should update name', () => {
    const selector = (user): string => user.name;
    const patcher = (user, name: string) => { user.name = name }

    const { result } = renderHook(() => store.useState("user", { selector, patcher }))

    act(() => {
        result.current[1]((name) => "Yezy Ilomo")
    })

    expect(result.current[0]).toStrictEqual("Yezy Ilomo")
})


test('should create `birthYear` state with the given state initializer on default', () => {
    const { result } = renderHook(() => store.useState("birthYear", { default: () => 1995 }));

    act(() => {
        result.current[1](birthYear => birthYear + 2)
    })

    expect(result.current[0]).toStrictEqual(1997)
})

================================================
FILE: tests/subscription.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { createState, useState, createStore } from '../src/';


const count = createState(0);

let testVal1 = 0;

test('should update testVal1 through a subscriber', () => {
    const { result } = renderHook(() => useState(count))

    act(() => {
        count.subscribe((value) => {
            testVal1 = ++testVal1;
        })
        result.current[1](count => 1)
    })

    expect(testVal1).toStrictEqual(1);
})


const user = createState({ name: "Yezy", weight: 65 });

let testVal2 = 0;

test('should increment testVal2 twice through subscribers', () => {
    const { result } = renderHook(() => useState(user))

    act(() => {
        user.select(user => user.weight).subscribe((value) => {
            testVal2 = ++testVal2;
        })

        user.select(user => user.name).subscribe((value) => {
            testVal2 = ++testVal2;
        })

        result.current[2](user => { user.weight = 66; user.name = "Ilomo"; });
    })

    expect(testVal2).toStrictEqual(2);
})


const store = createStore();
store.setState("count", 0);

let testVal3 = 0;

test('should update testVal3 through subscribers', () => {
    const { result } = renderHook(() => store.useState("count"))

    act(() => {
        store.subscribe((key, value) => {
            testVal3 = ++testVal3;
        })
        result.current[1](count => 1)
    })

    expect(testVal3).toStrictEqual(1);
})

================================================
FILE: tests/useReducer.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { useReducer, createState } from '../src/';


const count = createState(0);

test('should update count', () => {
    const reducer = (state, action) => action;

    const { result } = renderHook(() => useReducer(reducer, count));

    act(() => {
        result.current[1](1)
    })

    expect(result.current[0]).toStrictEqual(1)
})


const user = createState({ name: "Yezy", age: 20 });

test('should update name', () => {
    const reducer = (state: string, action: string): string => action;

    const selector = (user): string => user.name;
    const patcher = (user, name: string) => { user.name = name }

    const { result } = renderHook(() => useReducer(reducer, user, { selector, patcher }))

    act(() => {
        result.current[1]("Yezy Ilomo")
    })

    expect(result.current[0]).toStrictEqual("Yezy Ilomo")
})


test('Test local state: should update count', () => {
    const reducer = (state, action) => action;

    const { result } = renderHook(() => useReducer(reducer, 0));

    act(() => {
        result.current[1](1)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('Test local state: should update name', () => {
    const reducer = (state: string, action: string): string => action;

    const selector = (user): string => user.name;
    const patcher = (user, name: string) => { user.name = name }

    const { result } = renderHook(() => useReducer(reducer, { name: "Yezy", age: 20 }, { selector, patcher }))

    act(() => {
        result.current[1]("Ilomo")
    })

    expect(result.current[0]).toStrictEqual("Ilomo")
})


test('Test local state with state initializer: should update count', () => {
    const reducer = (state, action) => action;

    const { result } = renderHook(() => useReducer(reducer, () => 0));

    act(() => {
        result.current[1](1)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('Should return state object as the last item in array', () => {
    const reducer = (state, action) => action;

    const { result } = renderHook(() => useReducer(reducer, 0));

    act(() => {
        result.current[1](1)
    })

    expect(result.current[2].getValue()).toStrictEqual(1)
})

================================================
FILE: tests/useState.test.ts
================================================
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { useState, createState } from '../src/';


const count = createState(0);

test('should update count', () => {
    const { result } = renderHook(() => useState(count))

    act(() => {
        result.current[1](count => ++count)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('should set count', () => {
    const { result } = renderHook(() => useState(count))

    act(() => {
        result.current[1](5)
    })

    expect(result.current[0]).toStrictEqual(5)
})



const user = createState<{ name: string, age: number }>({ name: "Yezy", age: 20 });

test('should update name', () => {
    const selector = (user) => user.name;
    const patcher = (user, name) => { user.name = name }

    const { result } = renderHook(() => useState(user, { selector, patcher }))

    act(() => {
        result.current[1]((name) => "Yezy Ilomo")
    })

    expect(result.current[0]).toStrictEqual("Yezy Ilomo")
})


test('should set name', () => {
    // If you specify the type of what you're selecting & patcher it'll automatically know what to return
    const selector = (user) => user.name;
    const patcher = (user, name) => { user.name = name }

    const { result } = renderHook(() => useState(user, { selector, patcher }))

    act(() => {
        result.current[1]("Ilomo Yezy")
    })

    expect(result.current[0]).toStrictEqual("Ilomo Yezy")
})


test('should update name without patcher', () => {
    const selector = (user) => user.name;

    const { result } = renderHook(() => user.useState({ selector }))

    act(() => {
        result.current[2]((usr) => { usr.name = "Ilomo" })
    })

    expect(result.current[0]).toStrictEqual("Ilomo")
})


test('Test local state: should update count', () => {
    const { result } = renderHook(() => useState(0))

    act(() => {
        result.current[1](count => ++count)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('Test local state: should set name', () => {
    // If you specify the type of what you're selecting & patcher it'll automatically know what to return
    const selector = (user) => user.name;
    const patcher = (user, name) => { user.name = name }

    const { result } = renderHook(() => useState({ name: "Yezy", age: 27 }, { selector, patcher }))

    act(() => {
        result.current[1]("Ilomo Yezy")
    })

    expect(result.current[0]).toStrictEqual("Ilomo Yezy")
})


test('Test local state with state initializer: should update count', () => {
    const { result } = renderHook(() => useState(() => 0))

    act(() => {
        result.current[1](count => ++count)
    })

    expect(result.current[0]).toStrictEqual(1)
})


test('Should return state object as the last item in array', () => {
    const { result } = renderHook(() => useState(0))

    act(() => {
        result.current[1](count => ++count)
    })

    expect(result.current[3].getValue()).toStrictEqual(1)
})




================================================
FILE: tsconfig.json
================================================
{
    "compilerOptions": {
        "target": "ES5",
        "module": "commonjs",
        "allowJs": true,
        "outDir": "dist",
        "strict": false,
        "jsx": "preserve",
        "declaration": true,
        "esModuleInterop": true,
        "moduleResolution": "node",
        "baseUrl": ".",
        "paths": {
          "state-pool": [
            "./src/index.ts"
          ]
        }
    },
    
    "include": [
        "src/**/*",
        "tests/**/*"
    ],
    "exclude": [
        "node_modules",
        "dist"
    ]
}

================================================
FILE: website/.gitignore
================================================
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


================================================
FILE: website/README.md
================================================
# Website

This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.

### Installation

```
$ yarn
```

### Local Development

```
$ yarn start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

### Build

```
$ yarn build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

### Deployment

Using SSH:

```
$ USE_SSH=true yarn deploy
```

Not using SSH:

```
$ GIT_USER=<Your GitHub username> yarn deploy
```

If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.


================================================
FILE: website/babel.config.js
================================================
module.exports = {
  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};


================================================
FILE: website/blog/2019-05-28-first-blog-post.md
================================================
---
slug: first-blog-post
title: First Blog Post
authors:
  name: Gao Wei
  title: Docusaurus Core Team
  url: https://github.com/wgao19
  image_url: https://github.com/wgao19.png
tags: [hola, docusaurus]
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet


================================================
FILE: website/blog/2019-05-29-long-blog-post.md
================================================
---
slug: long-blog-post
title: Long Blog Post
authors: endi
tags: [hello, docusaurus]
---

This is the summary of a very long blog post,

Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.

<!--truncate-->

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet


================================================
FILE: website/blog/2021-08-01-mdx-blog-post.mdx
================================================
---
slug: mdx-blog-post
title: MDX Blog Post
authors: [slorber]
tags: [docusaurus]
---

Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).

:::tip

Use the power of React to create interactive blog posts.

```js
<button onClick={() => alert('button clicked!')}>Click me!</button>
```

<button onClick={() => alert('button clicked!')}>Click me!</button>

:::


================================================
FILE: website/blog/2021-08-26-welcome/index.md
================================================
---
slug: welcome
title: Welcome
authors: [slorber, yangshun]
tags: [facebook, hello, docusaurus]
---

[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).

Simply add Markdown files (or folders) to the `blog` directory.

Regular blog authors can be added to `authors.yml`.

The blog post date can be extracted from filenames, such as:

- `2019-05-30-welcome.md`
- `2019-05-30-welcome/index.md`

A blog post folder can be convenient to co-locate blog post images:

![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg)

The blog supports tags as well!

**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.


================================================
FILE: website/blog/authors.yml
================================================
endi:
  name: Endilie Yacop Sucipto
  title: Maintainer of Docusaurus
  url: https://github.com/endiliey
  image_url: https://github.com/endiliey.png

yangshun:
  name: Yangshun Tay
  title: Front End Engineer @ Facebook
  url: https://github.com/yangshun
  image_url: https://github.com/yangshun.png

slorber:
  name: Sébastien Lorber
  title: Docusaurus maintainer
  url: https://sebastienlorber.com
  image_url: https://github.com/slorber.png


================================================
FILE: website/docs/api_reference/_category_.json
================================================
{
    "label": "API Reference",
    "position": 4
}
  

================================================
FILE: website/docs/api_reference/high_level_api/_category_.json
================================================
{
    "label": "High Level API",
    "position": 2
}
  

================================================
FILE: website/docs/api_reference/high_level_api/createStore.md
================================================
---
sidebar_position: 1
---

# createStore
Store 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 

```js
import { createStore } from 'state-pool';

const store = createStore();

// Or with initialization as 

const store = createStore({"state1": value1, "state2": value2, ...});
```


================================================
FILE: website/docs/api_reference/high_level_api/store.clear.md
================================================
---
sidebar_position: 8
---

# store.clear
This 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. 

:::important

 The function runs before components subscribed to all states in a store rerenders.

:::

```js
// Signature
store.clear(fn: Function)
```

Below is an example showing how to use it

```jsx
import React from 'react';
import { createStore } from 'state-pool';


const store = createStore();

const user = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}
    
const profile = {
    url: "https://yezyilomo.me",
    rating: 5
}
store.setState("user", user);
store.setState("profile", profile);


function UserInfo(props){
    const [user, setUser, updateUser] = store.useState("user");

    const updateName = (e) => {
        updateUser(user => {
            user.name = e.target.value;
        });
    }

    const reinitializeStore = () => {
        const user = {name: "Yezy", age: 25, email: "yezy@me.com"}
        const profile = {url: "https://yezyilomo.me", rating: 5}
        store.setState("user", user);
        store.setState("profile", profile);
    }

    const resetStore = (e) => {
        store.clear(initializeStore);
    }

    return (
        <div>
            Name: {user.name}
            <br/>
            <input type="text" value={user.name} onChange={updateName}/>
             <button onClick={resetStore}>Reset Store</button>
        </div>
    );
}

ReactDOM.render(UserInfo, document.querySelector("#root"));
```
From 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.


**NOTE:** both `store.remove` and `store.clear` when executed causes all components subscribed to states which are removed to rerender.


================================================
FILE: website/docs/api_reference/high_level_api/store.getState.md
================================================
---
sidebar_position: 5
---

# store.getState
`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.

```js
// Signature
store.getState(key: String, config?: {default: Any, persist: Boolean})
```

Here is how to use it

```js
const State = store.getState(key);
```



================================================
FILE: website/docs/api_reference/high_level_api/store.getStateValue.md
================================================
---
sidebar_position: 12
---

# store.getStateValue
This 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.

```js
const userName = store.getStateValue("user", (user) => user.name);
```

================================================
FILE: website/docs/api_reference/high_level_api/store.has.md
================================================
---
sidebar_position: 10
---

# store.has
`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.

Here is an example of `store.has` in action


```js
// We want to access user state in a store but first we have to check if it's available
if(store.has("user")) {
    const user = store.getState("user");
}
else {
    // There is not user state in a store
}

```

================================================
FILE: website/docs/api_reference/high_level_api/store.items.md
================================================
---
sidebar_position: 11
---

# store.items
`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.


Here is how to use it.

```js
store.items().map(([key, value, persist]) => {
    // Do whatever you want with these values
})
```

================================================
FILE: website/docs/api_reference/high_level_api/store.persist.md
================================================
---
sidebar_position: 9
---

# store.persist
Sometimes 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).

**State pool** makes it very easy to save your states in your preferred permanent storage, all you need to do is:

1. Tell **state-pool** how to save your state by using `store.persist`
2. Use `persist` configuration to tell state-pool to save your state in your preferred storage when creating your state.

When telling **state-pool**  how to save state to a permanent storage we need to implement four functions which are 

1. `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
2. `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
3. `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
4. `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.

Now the way to implement these is by calling `store.persist` and pass them as shown below 

```js
store.persist({
    saveState: function(key, value, isInitialSet){/*your code to save state */},
    loadState: function(key, noState){/*your code to load state */},
    removeState: function(key){/*your code to remove state */},
    clear: function(){/*your code to clear storage */}
})
```

After 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.

As 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

```js
store.setState(
    key: String,
    initialState: Any,
    config?: {persist: Boolean}
)
```

```js
store.useState(
    key: String,
    config?: {default: Any, persist: Boolean, ...otherConfigs}
)
```

```js
store.useReducer(
    reducer: Function,
    key: String,
    config?: {default: Any, persist: Boolean, ...otherConfigs}
)
```

By 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.

What'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.

Below is an example showing how you could implement state persistance in local storage.

```js
import { createStore } from 'state-pool';

const store = createStore();

function debounce(func, timeout) {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => { func.apply(this, args); }, timeout);
    };
}

store.persist({
    PERSIST_ENTIRE_STORE: true,  // Use this only if you want to persist the entire store
    saveState: function (key, value, isInitialSet) {
        
        const doStateSaving = () => {
            try {
                const serializedState = JSON.stringify(value);
                window.localStorage.setItem(key, serializedState);
            } catch {
                // Ignore write errors
            }
        }

        if (isInitialSet) {
            // Here we don't debounce saving state since it's the initial set
            // so it's called only once and we need our storage to be updated
            // right away
            doStateSaving();
        }
        else {
            // Here we debounce saving state because it's the update and this function
            // is called every time the store state changes. However, it should not
            // be called too often because it triggers the expensive `JSON.stringify` operation.
            const DEBOUNCE_TIME = 1000 // In milliseconds
             // Debounce doStateSaving before calling it
            const processStateSaving = debounce(doStateSaving, DEBOUNCE_TIME);
            processStateSaving()  // save State
        }
    },
    loadState: function (key, noState) {
        try {
            const serializedState = window.localStorage.getItem(key);
            if (serializedState === null) {
                // No state saved
                return noState;
            }
            return JSON.parse(serializedState);
        } catch (err) {
            // Failed to load state
            return undefined
        }
    },
    removeState: function (key) {
        window.localStorage.removeItem(key);
    },
    clear: function () {
        window.localStorage.clear();
    }
})
```

:::important

When 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.

:::

================================================
FILE: website/docs/api_reference/high_level_api/store.remove.md
================================================
---
sidebar_position: 7
---

# store.remove
This 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.

:::important

The function runs before components subscribed to removed state(s) re-renders.

:::

```js
// Signature
store.remove(key: String, fn: Function)
```

Below is an example showing how to use it

```jsx
import React from 'react';
import { createStore } from 'state-pool';


const store = createStore();
store.setState("count", 0);

function ClicksCounter(props){
    const [count, setCount, updateCount] = store.useState("count");

    const incrementCount = (e) => {
        setCount(count+1);
    }

    const reinitializeCountState = () => {
        store.setState("count", 0);
    }

    const resetCounter = (e) => {
        store.remove("count", reinitializeCountState)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
            <button onClick={resetCounter}>Reset</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

From an example above, when you click `Reset` button `store.remove` will remove `count` state and create it again by executing `initializeStore`.


**NOTE:** If we had more than one state to delete we could do

```js
store.remove([key1, key2, key3, ...], initializeStore);
```


================================================
FILE: website/docs/api_reference/high_level_api/store.setState.md
================================================
---
sidebar_position: 2
---

# store.setState
This 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.

```js
// Signature
store.setState(key: String, initialState: Any, config?: {persist: Boolean});

// Or with lazy state initializer

store.setState(key: String, stateInitializer: () => Any, config?: {persist: Boolean})
```

Here is how to use it

```js
const userState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}
store.setState("user", userState);
```

:::important

`store.setState` should be used outside of a react component.

:::



================================================
FILE: website/docs/api_reference/high_level_api/store.subscribe.md
================================================
---
sidebar_position: 6
---

# store.subscribe
If 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 

```js
// Subscribe to store changes
const unsubscribe = store.subscribe(function(key: String, value: Any){
    // key is the key for a state that has changed 
    // value is the new value of a state
})

// You can unsubscribe by calling the result
unsubscribe();
```

If you want to subscribe to a single state you can use 

```js
// Subscribe to store changes
const unsubscribe = store.getState(key).subscribe(function(value){
    // value is the new value of a state
})

// You can unsubscribe by calling the result
unsubscribe();
```

You can even subscribe to a deeply nested state by using a selector as 

```js
store.getState(key).subscribe({
    observer:  function(value){
        // value is the new value of a state 
    },
    selector: function(value){
        return  selected_state
    })
})
```
With this observer function will only be called when the selected state changes.


Another way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as

```js
store.getState(key).select(state => selected_state).subscribe(value =>{
        // Do your thing here
    }
)
```

================================================
FILE: website/docs/api_reference/high_level_api/store.useReducer.md
================================================
---
sidebar_position: 4
---

# store.useReducer
This 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`.

```js
// Signature
store.useReducer(
    reducer: Function,
    key: String,
    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}
)
```

Below is a simple example showing how to use `store.useReducer` hook

```js
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

store.setState("user", initialState);

function myReducer(state, action){
    // This could be any reducer
    // Do whatever you want to do here
    return newState
}

function Component(props){
    const [name, dispatch] = store.useReducer(myReducer, "user");

    // Other stuff ...
}
```


Below is an example with `selector` and `patcher` parameters

```js
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

store.setState("user", initialState);


function myReducer(state, action){
    // This could be any reducer
    // Do whatever you want to do here
    return newState
}

function UserInfo(props){
    const selector = (user) => user.name;
    const patcher = (user, name) => {user.name = name};
    
    const [name, dispatch] = store.useReducer(myReducer, "user", {selector, patcher});

    // Other stuff
}
```


================================================
FILE: website/docs/api_reference/high_level_api/store.useState.md
================================================
---
sidebar_position: 3
---

# store.useState
`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.

```js
// Signature
store.useState(
    key: String,
    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}
)

// Or with lazy state initializer as 

store.useState(
    key: String,
    config?: {default: () => Any, persist: Boolean, selector: Function, patcher: Function}
)
```

Below is an example showing how to use `store.useState` hook

```js
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

store.setState("user", initialState);

function Component(props){
    const [user, setUser, updateUser] = store.useState("user");
    // Other stuff
}
```

Here `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

```js
updateUser(function(user){
    user.name = "Yezy Ilomo";
    user.age = 26;
})
```

Or you could just use `setUser` instead of `updateUser` i.e

```js
setUser({name: "Yezy Ilomo", age: 26, email: "yezy@me.com"});
```

Or

```js
setUser(function(user){
    return {
        name: "Yezy Ilomo",
        age: 26,
        email: user.email
    }
})
```

As stated earlier `store.useState` takes a second optional parameter which is a configuration object, available configurations are:
- `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

  ```js
  const [user, setUser, updateUser] = store.useState("user", {default: null});

  // You can also use lazy initialization on `default` option as
    const [user, setUser, updateUser] = store.useState(
        "user", 
        {default: () => { 
            // your expensive computation here
            return null  // Return your initial state
        }}); 
  ```

  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`.

- 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).
<br/>

Other allowed configurations are `selector` & `patcher`. These are used for specifying a way to select deeply nested state and update it.

- `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.

- `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.

  Example.
  ```jsx
  const initialState = {
      name: "Yezy",
      age: 25,
      email: "yezy@me.com"
  }
  
  store.setState("user", initialState);
  
  
  function UserName(props){
      const selector = (user) => user.name;  // Subscribe to user.name only
      const patcher = (user, name) => {user.name = name};  // Update user.name
  
      const [name, setName] = store.useState("user", {selector: selector, patcher: patcher});
  
      const handleNameChange = (e) => {
          setName(e.target.value);
      }
  
      return (
          <div>
              Name: {name}
              <br/>
              <input type="text" value={name} onChange={handleNameChange}/>
          </div>
      );
  }
  ```


================================================
FILE: website/docs/api_reference/intro.md
================================================
---
sidebar_position: 1
---

# Intro
State pool API is divided into two parts. 
1. High Level API(Store based API)
2. Low Level API(Non-Store based API)

In 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.

Here is a simple example using high level API

```jsx
import React from 'react';
import { createStore } from 'state-pool';

// Create a store
const store = createStore();

// Create count state and initialize it with 0
const count = store.setState("count", 0);

function ClicksCounter(props){
    // Use count state
    const [count, setCount] = store.useState("count");

    const incrementCount = (e) => {
        setCount(count+1);
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

On 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.

So 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.

Here is the same example as the previous one re-written using low level API

```jsx
import React from 'react';
import { createState } from 'state-pool';


// Create count state and initialize it with 0
const count = createState(0);

function ClicksCounter(props){
    // Use count state
    const [count, setCount] = count.useState();

    const incrementCount = (e) => {
        setCount(count+1);
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

Or if you want to import `useState` from **state-pool**

```jsx
import React from 'react';
import { createState, useState } from 'state-pool';


// Create count state and initialize it with 0
const count = createState(0);

function ClicksCounter(props){
    // Use count state
    const [count, setCount] = useState(count);

    const incrementCount = (e) => {
        setCount(count+1);
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

Now let's explore these two APIs


================================================
FILE: website/docs/api_reference/low_level_api/_category_.json
================================================
{
    "label": "Low Level API",
    "position": 3
}
  

================================================
FILE: website/docs/api_reference/low_level_api/createState.md
================================================
---
sidebar_position: 1
---

# createState
This 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.

```js
// Signature
createState(initialValue: Any)

// Or

createState(initializer: () => Any)
```

Here is how to use it

```js
import { createState } from 'state-pool';

const userName = createState("Yezy");

// Or if you have expensive computations during initialization you could use lazy initialization

function lazyInitializer(){
  // Perform expensive computation here
  
  return "Yezy";  // Return your initial state
}

const userName = createState(lazyInitializer);
```

Here are some of the mostly used methods available in a state object.

- `useState`: This is used to subscribe a component to a state, it's a hook which should be used inside a react component.
  ```js
  // Signature
  state.useState(config?: {selector: Function, patcher: Function});
  ```
- `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.
  ```js
  // Signature
  state.useReducer(reducer: Function, config?: {selector: Function, patcher: Function});
  ```
- `getValue`: This is used to get the value of a state
  ```js
  // Signature
  state.getValue(selector?: Function);
  ```
- `setValue`: This is used to set the value of a state
  ```js
  // Signature
  state.setValue(value | stateUpdater: Any | Function, config?: {selector, patcher});
  ```
- `updateValue`: This is used to update the value of a state
  ```js
  // Signature
  state.updateValue(updater: Function, config?: {selector, patcher});
  ```
- `subscribe`: This is used to listen to all changes from a state
  ```js
  // Signature
  state.subscribe(observer: Function | Subscription: {observer, selector});
  ```
- `select`: This is used to derive another state or select a deeply nested state
  ```js
  // Signature
  state.select(selector: Function);
  ```
  This returns `DerivedState` that you can subscribe to by calling `subscribe` on it as
  ```js
  // Signature
  state.select(selector: Function).subscribe(observer: Function);
  ```

Below is an example showing all of them in action
```js
import { createState } from 'state-pool';

const count = createState(0);

count.useState()  // This subscribe its component to count state

count.getValue()  // This will give 0

count.setValue(1)  // This set the value of count to 1

// This will print whenever count change
const unsubscribe = count.subscribe(val => console.log(val)) 

unsubscribe()  // This will unsubscribe the observer above

// An example for nested state
const user = createState({name: "Yezy", weight: 65});

user.updateValue(user => {user.weight += 1})  // This will increment the weight

// Select user name and subscribe to it,
// this will be printing whenever user name changes
user.select(user => user.name).subscribe(name => console.log(name));
```


:::important

`createState` should be used outside of a react component. 

:::

:::tip

`createState` is used to implement `store.setState` API. 

:::

================================================
FILE: website/docs/api_reference/low_level_api/useReducer.md
================================================
---
sidebar_position: 3
---

# useReducer
This 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`.


```js
// Signature
useReducer(
    reducer: Function,
    state: State,
    config?: {selector: Function, patcher: Function}
)

// Or in local state as

useReducer(
    reducer: Function,
    initialState: Any,
    config?: {selector: Function, patcher: Function}
)

// Or with lazy state initializer
useReducer(
    reducer: Function,
    stateInitializer: () => Any,
    config?: {selector: Function, patcher: Function}
)
```

Below is a simple example showing how to use `useReducer`

```js
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

const user = createState(initialState);

function myReducer(state, action){
    // This could be any reducer
    // Do whatever you want to do here
    return newState
}

function Component(props){
    const [name, dispatch] = useReducer(myReducer, user);
    
    // Other stuff ...
}
```

Below is the same example with `selector` and `patcher` parameters

```js
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

const user = createState(initialState);


function myReducer(state, action){
    // This could be any reducer
    // Do whatever you want to do here
    return newState
}

function UserInfo(props){
    const selector = (user) => user.name;
    const patcher = (user, name) => {user.name = name};
    
    const [name, dispatch] = useReducer(myReducer, user, {selector, patcher});

    // Other stuffs
}
```


# Using useReducer to manage local state
Just like in `useState`, `useReducer` can be used to manage local state too.

Here is an example for managing local state with `useReducer`
```jsx
import React from 'react';
import { useReducer } from 'state-pool';


const myReducer = (state, action) => {
   // Your computaton here
   return action;
}

function ClicksCounter(props){
    // Here `useReducer` hook will create "count" state and initialize it with 0
    // Note: the `useReducer` hook used here is impored from state-pool and not react
    const [count, dispatch] = useReducer(myReducer, 0);

    const incrementCount = (e) => {
        dispatch(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```
<br/>

If you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,


:::tip

`useState` hook is derived from `useReducer` hook, also this hook is used to implement `store.useReducer`.

:::

================================================
FILE: website/docs/api_reference/low_level_api/useState.md
================================================
---
sidebar_position: 2
---

# useState
`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`.

```js
// Signature
useState(state: State, config?: {selector: Function, patcher: Function})

// Or in local state as

useState(initialState: Any, config?: {selector: Function, patcher: Function})

// Or with lazy state initializer

useState(stateInitializer: () => Any, config?: {selector: Function, patcher: Function})
```

Below is a simple example showing how to use `useState` hook

```jsx
import React from 'react';
import { createState, useState } from 'state-pool';


const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

const user = createState(initialState);

function Component(props){
    const [user, setUser, updateUser] = useState(user);
    // Other stuff ...
}
```

Below is the same example with `selector` and `patcher` configurations

```jsx
const initialState = {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
}

const user = createState(initialState);


function UserName(props){
    const selector = (user) => user.name;  // Subscribe to user.name only
    const patcher = (user, name) => {user.name = name};  // Update user.name

    const [name, setName] = useState(user, {selector: selector, patcher: patcher});

    const handleNameChange = (e) => {
        setName(e.target.value);
    }

    return (
        <div>
            Name: {name}
            <br/>
            <input type="text" value={name} onChange={handleNameChange}/>
        </div>
    );
}
```

# Using useState to manage local state
With **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.

Here is an example for managing local state with `useState`
```jsx
import React from 'react';
import { useState } from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    // Note: the `useState` hook used here is impored from state-pool and not react
    const [count, setCount] = useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```
<br/>

If you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,

Here is an example
```jsx
// Example 2.
import React from 'react';
import StatePool from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    const [count, setCount] = StatePool.useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

Here is an example with nested data
```jsx
import { useState } from 'state-pool';


function UserName(props){
    const [user, setUser, updateUser] = useState({name: "Yezy", age: 25, email: "yezy@me.com"});

    const handleNameChange = (e) => {
        updateUser((user) => {
            user.name = e.target.value
        })
    }

    const handleAgeChange = (e) => {
        updateUser((user) => {
            user.age = e.target.value
        })
    }

    return (
        <div>
            <div>Name: {user.name} </div>
            <div>Age: {user.age} </div>
            <input type="text" value={user.name} onChange={handleNameChange}/>
            <input type="text" value={user.age} onChange={handleAgeChange}/>
        </div>
    );
}
```

:::tip

`useState` is used to implement `store.useState` hook.

:::

================================================
FILE: website/docs/api_reference/typing-state.md
================================================
---
sidebar_position: 4
---


# Typing State
All state related functions support implicity and explicity typing.

Examples

```ts
store.setState<number>('count', 0);

store.useState<number>('count');

store.useReducer<number, action>(reducer, 'count');

// For none key based
const count = createState<number>(0);

useState<number>(count);

useReducer<number, action>(reducer, count);


// Typing with selector
store.setState<{name: string, age: number}>('user', {name: 'Yezy', age: 25});

store.useState<string>('user', {selector: user => user.name});
store.useState<number>('age', {selector: user => user.age});

store.useReducer<string, action>(reducer, 'user', {selector: user => user.name});
store.useReducer<number, action>(reducer, 'user', {selector: user => user.age});

// For none key based
const user = createState<{name: string, age: number}>({name: 'Yezy', age: 25});

useState<string>(user, {selector: user => user.name});
useState<number>(user, {selector: user => user.age});

useReducer<string, action>(reducer, user, {selector: user => user.name});
useReducer<number, action>(reducer, user, {selector: user => user.age});
```

<br/><br/>

# Blue print for typing hooks
**Note:** `T` is for base/original state type, `ST` for selected state type and `A` for reducer action.

```ts
// useState.js   (For useState)

const [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = useState<T>(state: State<T> | T)

const [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = useState<ST, T>(state: State<T> | T, { selector: Selector<ST> })

const [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = useState<ST, T>(state: State<T> | T, { selector: Selector<ST>, patcher: Patcher<ST> })


// State.js   (For state.useState)

const [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = state<T>.useState()

const [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = state<T>.useState<ST>({ selector: Selector<ST> })

const [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = state<T>.useState<ST>({ selector: Selector<ST>, patcher: Patcher<ST> })

// Store.js   (For store.useState)

const [state: T, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = store.useState<T>(key, { default: T });

const [state: ST, setState: SetState<T>, updateState: UpdateState<T>, stateObj: State<T>] = store.useState<ST, T>(key, { selector: Selector<ST>, default: T })

const [state: ST, setState: SetState<ST>, updateState: UpdateState<ST>, stateObj: State<T>] = store.useState<ST, T>(key, { selector: Selector<ST>, patcher: Patcher<ST>, default: T })


// useReducer.js   (For useReducer)

type Reducer = (state: T, action: A) => T
const [state: T, dispatch: (action: A) => void, stateObj: State<T>] = useReducer<T, A>(type Reducer = Reducer<T, A>, state: State<T> | T)

type Reducer = (state: T, action: A) => T
const [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> })

type Reducer = (state: ST, action: A) => ST
const [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> })


// State.js  (For state.useReducer)

type Reducer = (state: T, action: A) => T
const [state: T, dispatch: (action: A) => void, stateObj: State<T>] = state<T>.useReducer<T, A>(type Reducer = Reducer<T, A>)

type Reducer = (state: T, action: A) => T
const [state: ST, dispatch: (action: A) => void, stateObj: State<T>] = state<T>.useReducer<ST, A>(type Reducer = Reducer<T, A>, { selector: Selector<ST> })

type Reducer = (state: ST, action: A) => ST
const [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> })


// Store.js   (For store.useReducer)

type Reducer = (state: T, action: A) => T
const [state: T, dispatch: (action: A) => void, stateObj: State<T>] = store.useReducer<T, A>(type Reducer = Reducer<T, A>, key, { default: T });

type Reducer = (state: T, action: A) => T
const [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 })

type Reducer = (state: ST, action: A) => ST
const [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 })
```


================================================
FILE: website/docs/basic_concepts/_category_.json
================================================
{
    "label": "Basic Concepts",
    "position": 2
}
  

================================================
FILE: website/docs/basic_concepts/derived_state.md
================================================
---
sidebar_position: 3
---

# Derived & Nested State
With 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.

Here is a simple example showing how to use `selector` & `Patcher` options

```jsx
// With store API
const user = createState({
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
});


function UserName(props){
    const selector = (user) => user.name;  // Subscribe to user.name only
    const patcher = (user, name) => {user.name = name};  // Update user.name

    const [name, setName] = user.useState({selector: selector, patcher: patcher});

    const handleNameChange = (e) => {
        setName(e.target.value);
    }

    return (
        <div>
            Name: {name} <br/>
            <input type="text" value={name} onChange={handleNameChange}/>
        </div>
    );
}
```

Or with store API

```jsx
// With store API
store.setState("user", {
    name: "Yezy",
    age: 25,
    email: "yezy@me.com"
});


function UserName(props){
    const selector = (user) => user.name;  // Subscribe to user.name only
    const patcher = (user, name) => {user.name = name};  // Update user.name

    const [name, setName] = store.useState("user", {selector: selector, patcher: patcher});

    const handleNameChange = (e) => {
        setName(e.target.value);
    }

    return (
        <div>
            Name: {name} <br/>
            <input type="text" value={name} onChange={handleNameChange}/>
        </div>
    );
}
```
Here `selector` & `patcher` are used for specifying a way to select deeply nested state(derive new state) and update it.

- `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.

- `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.

================================================
FILE: website/docs/basic_concepts/managing_subscriptions.md
================================================
---
sidebar_position: 4
---

# Managing Subscriptions
If 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


```js
const state = createState(value);


// Subscribe to state changes
const unsubscribe = state.subscribe(function(value){
    // value is the new value of a state
})

// You can unsubscribe by calling the result
unsubscribe();
```

You can even subscribe to a deeply nested state by using a selector as 

```js
state.subscribe({
    observer:  function(value){
        // value is the new value of a state 
    },
    selector: function(value){
        return  selected_state
    }
})
```
With this, observer function will only be called when the selected state changes.


Another way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as

```js
state.select(state => selected_state).subscribe(value =>{
        // Do your thing here
    }
)
```

# Subscriptions in a store
If 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

```js
// Subscribe to store changes
const unsubscribe = store.subscribe(function(key: String, value: Any){
    // key is the key for a state that has changed 
    // value is the new value of a state
})

// You can unsubscribe by calling the result
unsubscribe();
```

If you want to subscribe to a single state you can use 

```js
// Subscribe to store changes
const unsubscribe = store.getState(key).subscribe(function(value){
    // value is the new value of a state
})

// You can unsubscribe by calling the result
unsubscribe();
```

You can even subscribe to a deeply nested state by using a selector as 

```js
store.getState(key).subscribe({
    observer:  function(value){
        // value is the new value of a state 
    },
    selector: function(value){
        return  selected_state
    })
})
```
With this, observer function will only be called when the selected state changes.


Another way to subscribe to nested state or derived state is to call `select` on a state then subscribe to it as

```js
store.getState(key).select(state => selected_state).subscribe(value =>{
        // Do your thing here
    }
)
```

================================================
FILE: website/docs/basic_concepts/state_persistence.md
================================================
---
sidebar_position: 5
---

# State Persistence
State 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.

The way to implement these is by calling `store.persist` and pass them as shown below 

```js
store.persist({
    saveState: function(key, value, isInitialSet){/*your code to save state */},
    loadState: function(key, noState){/*your code to load state */},
    removeState: function(key){/*your code to remove state */},
    clear: function(){/*your code to clear storage */}
})
```

After 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.

Both `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

```js
store.setState(
    key: String,
    initialState: Any,
    config?: {persist: Boolean}
)
```

```js
store.useState(
    key: String,
    config?: {default: Any, persist: Boolean, ...otherConfigs}
)
```

```js
store.useReducer(
    reducer: Function,
    key: String,
    config?: {default: Any, persist: Boolean, ...otherConfigs}
)
```

By 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.

What'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.

Below is an example showing how you could implement state persistance in local storage.

```js
import { createStore } from 'state-pool';

const store = createStore();

function debounce(func, timeout) {
    let timer;
    return (...args) => {
        clearTimeout(timer);
        timer = setTimeout(() => { func.apply(this, args); }, timeout);
    };
}

store.persist({
    PERSIST_ENTIRE_STORE: true,  // Use this only if you want to persist the entire store
    saveState: function (key, value, isInitialSet) {
        
        const doStateSaving = () => {
            try {
                const serializedState = JSON.stringify(value);
                window.localStorage.setItem(key, serializedState);
            } catch {
                // Ignore write errors
            }
        }

        if (isInitialSet) {
            // Here we don't debounce saving state since it's the initial set
            // so it's called only once and we need our storage to be updated
            // right away
            doStateSaving();
        }
        else {
            // Here we debounce saving state because it's the update and this function
            // is called every time the store state changes. However, it should not
            // be called too often because it triggers the expensive `JSON.stringify` operation.
            const DEBOUNCE_TIME = 1000 // In milliseconds
             // Debounce doStateSaving before calling it
            const processStateSaving = debounce(doStateSaving, DEBOUNCE_TIME);
            processStateSaving()  // save State
        }
    },
    loadState: function (key, noState) {
        try {
            const serializedState = window.localStorage.getItem(key);
            if (serializedState === null) {
                // No state saved
                return noState;
            }
            return JSON.parse(serializedState);
        } catch (err) {
            // Failed to load state
            return undefined
        }
    },
    removeState: function (key) {
        window.localStorage.removeItem(key);
    },
    clear: function () {
        window.localStorage.clear();
    }
})
```

:::important

When 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.

:::

================================================
FILE: website/docs/basic_concepts/store.md
================================================
---
sidebar_position: 1
---

# Store
A 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 

```js
import { createStore } from 'state-pool';

const store = createStore();
```

## Adding states to a store

Since 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.

```js
// Signature
store.setState(key: String, initialState: Any, config?: {persist: Boolean})
```

Here is an example showing how to use `store.setState`

```js
store.setState("count", 0);
```

<br/>

Another 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

```js
import { createStore } from 'state-pool';

const store = createStore({"count": 0});
```

```js
// createStore Signature
createStore({key1: stateValue1, key1, stateValue2, ...})
```


:::important

`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.

:::

================================================
FILE: website/docs/basic_concepts/using_store_state.md
================================================
---
sidebar_position: 2
---

# Using Store State
After 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.

`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]`.

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 are discussed in detail on [`store.useState` API](/docs/api_reference/high_level_api/store.useState).

```js
// Signature
store.useState(
    key: String,
    config?: {default: Any, persist: Boolean, selector: Function, patcher: Function}
)
```

Below is an example showing how to use `store.useState` hook

```js
store.setState("user", {name: "Yezy", email: "yezy@me.com"});

function Component(props){
    const [user, setUser, updateUser] = store.useState("user");
    // Other stuff
}
```

Here `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

```js
updateUser(function(user){
    user.name = "Yezy Ilomo";
    user.email = "hello@yezy.com";
})
```

Or you could just use `setUser` instead of `updateUser` i.e

```js
setUser({name: "Yezy Ilomo", email: "hello@yezy.com"});
```

Or 

```js
setUser(function(user){
    return {
        name: "Yezy Ilomo",
        email: "hello@yezy.com"
    }
})
```


<br/>

Another 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).

`store.useReducer` accepts a reducer and a key for the state as parameters, it returns the current state paired with a dispatch method.

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`.


Below is a simple example showing how to use it

```js
store.setState("user", {name: "Yezy", email: "yezy@me.com"});

function myReducer(state, action){
    // This could be any reducer
    // Do whatever you want to do here
    return newState
}

function Component(props){
    const [name, dispatch] = store.useReducer(myReducer, "user");

    // Other stuff ...
}
```

You can learn more about `store.useReducer` on [`store.useReducer` API section](/docs/api_reference/high_level_api/store.useReducer)

<br/>


:::tip
Both `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

  ```js
  const [user, setUser] = store.useState("user", {default: null});
  ```

  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.
:::

================================================
FILE: website/docs/basic_tutorial/_category_.json
================================================
{
    "label": "Basic Tutorial",
    "position": 3
}
  

================================================
FILE: website/docs/basic_tutorial/intro.md
================================================
---
sidebar_position: 1
---

# Intro

## Coming soon....

================================================
FILE: website/docs/introduction/_category_.json
================================================
{
    "label": "Introduction",
    "position": 1
}
  

================================================
FILE: website/docs/introduction/getting_started.md
================================================
---
sidebar_position: 3
---

# Getting Started
Using **state-pool** to manage state is very simple, all you need to do is
1. Create and initialize a state by using `createState`
2. Use your state in your component through `useState` hooks

These two steps summarises pretty much everything you need to use **state-pool**.

Below are few examples showing how to use **state-pool** to manage states.

```jsx
// Example 1.
import React from 'react';
import { createState } from 'state-pool';


const count = createState(0);  // Create "count" state and initialize it with 0


function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = count.useState();

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

The other way to do it is using `useState` from `state-pool`
```jsx
// Example 2.
import React from 'react';
import { createState, useState } from 'state-pool';


const count = createState(0);  // Create "count" state and initialize it with 0


function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = useState(count);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

# What about local state?
With **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.

Here is an example for managing local state
```jsx
// Example 1.
import React from 'react';
import { useState } from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    // Note: the `useState` hook used here is impored from state-pool and not react
    const [count, setCount] = useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```
<br/>

If you don't want **state-pool's** `useState` to collide with **React's** `useState` you can import `StatePool` and use the hook from there,

Here is an example
```jsx
// Example 2.
import React from 'react';
import StatePool from 'state-pool';


function ClicksCounter(props){
    // Here `useState` hook will create "count" state and initialize it with 0
    const [count, setCount] = StatePool.useState(0);

    const incrementCount = (e) => {
        setCount(count+1)
    }

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={incrementCount}>Click</button>
        </div>
    );
}

ReactDOM.render(ClicksCounter, document.querySelector("#root"));
```

<br/>

# Isn't `StatePool.useState` the same thing as `React.useState`?
**Definitely. not!...**

Both 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`.

Here is an example of `StatePool.useState` in action, updating nested data
```jsx
// Example 2.
import React from 'react';
import StatePool from 'state-pool';


const user = StatePool.createState({name: "Yezy", age: 25});

function UserInfo(props){
    const [user, setUser, updateUser] = StatePool.useState(user);

    const updateName = (e) => {
        updateUser(user => {
            user.name = e.target.value;
        });
    }

    return (
        <div>
            Name: {user.name}
            <br/>
            <input type="text" value={user.name} onChange={updateName}/>
        </div>
    );
}

ReactDOM.render(UserInfo, document.querySelector("#root"));
```

With `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. 

That'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/).



# Store based example
If 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.

Here are steps for managing state with a store
1. Create a store(which is basically a container for your state)
1. Create and initialize a state by using `store.setState`
2. Use your state in your component through `store.useState` hooks

These three steps summarises pretty much everything you need to manage state with a store.

Below are few examples of store in action

```jsx
// Example 1.
import { createStore } from 'state-pool';


const store = createStore();  // Create store for storing our state
store.setState("count", 0);  // Create "count" state and add it to the store

function ClicksCounter(props){
    // Use "count" state
    const [count, setCount] = store.useState("count");

    return (
        <div>
            Count: {count}
            <br/>
            <button onClick={e => setCount(++count)}>Click</button>
        </div>
    );
}
```

<br/>

```jsx
// Example 2.
import { createStore } from 'state-pool';


// Instead of using createStore and store.setState,
// you can combine store creation and initialization as follows

const store = createStore({"user", {name: "Yezy", age: 25}});  // create store and initialize it with user

function UserInfo(props){
    const [user, setUser, updateUser] = store.useState("user");

    const updateName = (e) => {
        updateUser(user => {
            user.name = e.target.value;
        });
    }

    return (
        <div>
            Name: {user.name}
            <br/>
            <input type="text" value={user.name} onChange={updateName}/>
        </div>
    );
}
```

<br/>

**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.

<br/>

Pretty cool, right?

================================================
FILE: website/docs/introduction/installation.md
================================================
---
sidebar_position: 2
---

# Installation
```bash
npm install state-pool
```

Or 

```bash
yarn add state-pool
```

================================================
FILE: website/docs/introduction/motivation.md
================================================
---
sidebar_position: 1
---

# Motivation

![Build Status](https://github.com/yezyilomo/state-pool/actions/workflows/node.js.yml/badge.svg?branch=master)
[![Build Size](https://img.shields.io/bundlephobia/minzip/state-pool?label=bundle-size&style=flat)](https://bundlephobia.com/result?p=state-pool)
[![Version](https://img.shields.io/npm/v/state-pool?style=flat)](https://www.npmjs.com/package/state-pool)
[![Downloads](https://img.shields.io/npm/dt/state-pool.svg?style=flat)](https://www.npmjs.com/package/state-pool)

Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨

## Features & Advantages
- Simple, familiar, flexible and very minimal core API but powerful
- Built-in support for state persistence
- Very easy to learn because its API is very similar to react state hook's API
- Support selecting deeply nested state
- Support creating state dynamically
- Can be used outside react components
- Doesn't wrap your app in context providers
- Very organized API, You can do almost everything with a single import


## State Flow
1. Create a state

2. Subscribe a component(s) to the state created

3. If a component wants to update the state, it sends update request

4. 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)

You can try live examples [Here](https://yezyilomo.github.io/state-pool-examples)

================================================
FILE: website/docusaurus.config.js
================================================
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion

const lightCodeTheme = require('prism-react-renderer/themes/dracula');
const darkCodeTheme = require('prism-react-renderer/themes/dracula');

/** @type {import('@docusaurus/types').Config} */
const config = {
  title: 'State Pool',
  tagline: 'Transform your React app with our state management library! Declare global and local states like variables, powered by the magic of React hooks 🪄✨',
  url: 'https://yezyilomo.github.io',
  baseUrl: '/state-pool/',
  onBrokenLinks: 'throw',
  onBrokenMarkdownLinks: 'warn',
  favicon: 'img/favicon.png',
  organizationName: 'yezyilomo', // Usually your GitHub org/user name.
  projectName: 'state-pool', // Usually your repo name.

  presets: [
    [
      'classic',
      /** @type {import('@docusaurus/preset-classic').Options} */
      ({
        docs: {
          sidebarPath: require.resolve('./sidebars.js'),
          // Please change this to your repo.
          editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
        },
        blog: {
          showReadingTime: true,
          // Please change this to your repo.
          editUrl:
            'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
        },
        theme: {
          customCss: require.resolve('./src/css/custom.css'),
        },
      }),
    ],
  ],

  themeConfig:
    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
    ({
      navbar: {
        title: 'State Pool',
        logo: {
          alt: 'State Pool Logo',
          src: 'img/logo.svg',
        },
        items: [
          {
            type: 'doc',
            docId: 'introduction/motivation',
            position: 'left',
            label: 'Docs',
          },
          /*{to: '/blog', label: 'Blog', position: 'left'},*/
          {
            position: 'left',
            label: 'Concepts',
            to: '/docs/basic_concepts/store',
          },
          {
            href: 'https://github.com/yezyilomo/state-pool',
            label: 'GitHub',
            position: 'right',
          },
        ],
      },
      footer: {
        style: 'dark',
        links: [
          {
            title: 'Docs',
            items: [
              {
                label: 'Tutorial',
                to: '/docs/basic_tutorial/intro',
              },
            ],
          },
          {
            title: 'Community',
            items: [
              {
                label: 'Twitter',
                href: 'https://twitter.com/yezyilomo',
              },
            ],
          },
          {
            title: 'More',
            items: [
              /*
              {
                label: 'Blog',
                to: '/blog',
              },
              */
              {
                label: 'GitHub',
                href: 'https://github.com/yezyilomo/state-pool/',
              },
            ],
          },
        ],
        copyright: `Copyright © ${new Date().getFullYear()} State Pool, Inc. Built with Docusaurus.`,
      },
      prism: {
        theme: lightCodeTheme,
        darkTheme: darkCodeTheme,
      },
    }),
};

module.exports = config;


================================================
FILE: website/package.json
================================================
{
  "name": "website",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "docusaurus": "docusaurus",
    "start": "docusaurus start",
    "build": "docusaurus build",
    "swizzle": "docusaurus swizzle",
    "deploy": "docusaurus deploy",
    "clear": "docusaurus clear",
    "serve": "docusaurus serve",
    "write-translations": "docusaurus write-translations",
    "write-heading-ids": "docusaurus write-heading-ids"
  },
  "dependencies": {
    "@docusaurus/core": "2.2.0",
    "@docusaurus/preset-classic": "2.2.0",
    "@mdx-js/react": "^1.6.22",
    "clsx": "^1.1.1",
    "prism-react-renderer": "^1.2.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1"
  },
  "browserslist": {
    "production": [
      ">0.5%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}


================================================
FILE: website/sidebars.js
================================================
/**
 * Creating a sidebar enables you to:
 - create an ordered group of docs
 - render a sidebar for each doc of that group
 - provide next/previous navigation

 The sidebars can be generated from the filesystem, or explicitly defined here.

 Create as many sidebars as you want.
 */

// @ts-check

/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
  // By default, Docusaurus generates a sidebar from the docs folder structure
  tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],

  // But you can create a sidebar manually
  /*
  tutorialSidebar: [
    {
      type: 'category',
      label: 'Tutorial',
      items: ['hello'],
    },
  ],
   */
};

module.exports = sidebars;


================================================
FILE: website/src/components/HomepageFeatures/index.js
================================================
import React from 'react';
import clsx from 'clsx';
import styles from './styles.module.css';

const FeatureList = [
  {
    title: 'Simple and Familiar',
    Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
    description: (
      <>
        State pool comes with a very simple and intuitive API which
        follows built in state management patterns in React.
      </>
    ),
  },
  {
    title: 'Very Minimal Core API',
    Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
    description: (
      <>
        State pool comes with a very minimal API which enables developers to manage
        global state easly without struggling.
      </>
    ),
  },
  {
    title: 'Powerful',
    Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
    description: (
      <>
        Despite having minimal API, State pool is very powerful.
      </>
    ),
  },
];

function Feature({Svg, title, description}) {
  return (
    <div className={clsx('col col--4')}>
      <div className="text--center">
        <Svg className={styles.featureSvg} role="img" />
      </div>
      <div className="text--center padding-horiz--md">
        <h3>{title}</h3>
        <p>{description}</p>
      </div>
    </div>
  );
}

export default function HomepageFeatures() {
  return (
    <section className={styles.features}>
      <div className="container">
        <div className="row">
          {FeatureList.map((props, idx) => (
            <Feature key={idx} {...props} />
          ))}
        </div>
      </div>
    </section>
  );
}


================================================
FILE: website/src/components/HomepageFeatures/styles.module.css
================================================
.features {
  display: flex;
  align-items: center;
  padding: 2rem 0;
  width: 100%;
}

.featureSvg {
  height: 200px;
  width: 200px;
}


================================================
FILE: website/src/css/custom.css
================================================
/**
 * Any CSS included here will be global. The classic template
 * bundles Infima by default. Infima is a CSS framework designed to
 * work well for content-centric websites.
 */

/* You can override the default Infima variables here. */
:root {
  --ifm-color-primary: #2e8555;
  --ifm-color-primary-dark: #29784c;
  --ifm-color-primary-darker: #277148;
  --ifm-color-primary-darkest: #205d3b;
  --ifm-color-primary-light: #33925d;
  --ifm-color-primary-lighter: #359962;
  --ifm-color-primary-lightest: #3cad6e;
  --ifm-code-font-size: 95%;
}

/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
  --ifm-color-primary: #25c2a0;
  --ifm-color-primary-dark: #21af90;
  --ifm-color-primary-darker: #1fa588;
  --ifm-color-primary-darkest: #1a8870;
  --ifm-color-primary-light: #29d5b0;
  --ifm-color-primary-lighter: #32d8b4;
  --ifm-color-primary-lightest: #4fddbf;
}

.docusaurus-highlight-code-line {
  background-color: rgba(0, 0, 0, 0.1);
  display: block;
  margin: 0 calc(-1 * var(--ifm-pre-padding));
  padding: 0 var(--ifm-pre-padding);
}

[data-theme='dark'] .docusaurus-highlight-code-line {
  background-color: rgba(0, 0, 0, 0.3);
}


================================================
FILE: website/src/pages/index.js
================================================
import React from 'react';
import clsx from 'clsx';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import styles from './index.module.css';
import HomepageFeatures from '@site/src/components/HomepageFeatures';

function HomepageHeader() {
  const {siteConfig} = useDocusaurusContext();
  return (
    <header className={clsx('hero hero--primary', styles.heroBanner)}>
      <div className="container">
        <h1 className="hero__title">{siteConfig.title}</h1>
        <p className="hero__subtitle">{siteConfig.tagline}</p>
        <div className={styles.buttons}>
          <Link
            className="button button--secondary button--lg"
            to="/docs/introduction/getting_started">
            Get started - 5min ⏱️
          </Link>
        </div>
      </div>
    </header>
  );
}

export default function Home() {
  const {siteConfig} = useDocusaurusContext();
  return (
    <Layout
      title={`Hello from ${siteConfig.title}`}
      description="Description will go into a meta tag in <head />">
      <HomepageHeader />
      <main>
        <HomepageFeatures />
      </main>
    </Layout>
  );
}


================================================
FILE: website/src/pages/index.module.css
================================================
/**
 * CSS files with the .module.css suffix will be treated as CSS modules
 * and scoped locally.
 */

.heroBanner {
  padding: 4rem 0;
  text-align: center;
  position: relative;
  overflow: hidden;
}

@media screen and (max-width: 996px) {
  .heroBanner {
    padding: 2rem;
  }
}

.buttons {
  display: flex;
  align-items: center;
  justify-content: center;
}


================================================
FILE: website/src/pages/markdown-page.md
================================================
---
title: Markdown page example
---

# Markdown page example

You don't need React to write simple standalone pages.


================================================
FILE: website/static/.nojekyll
================================================
Download .txt
gitextract_iwqcu_93/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── node.js.yml
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── src/
│   ├── State.ts
│   ├── Store.ts
│   ├── index.ts
│   ├── types.ts
│   ├── useReducer.ts
│   └── useState.ts
├── tests/
│   ├── store.clear.test.ts
│   ├── store.getState.test.ts
│   ├── store.getStateValue.test.ts
│   ├── store.has.test.ts
│   ├── store.items.test.ts
│   ├── store.persist.test.ts
│   ├── store.remove.test.ts
│   ├── store.useReducer.test.ts
│   ├── store.useState.test.ts
│   ├── subscription.test.ts
│   ├── useReducer.test.ts
│   └── useState.test.ts
├── tsconfig.json
└── website/
    ├── .gitignore
    ├── README.md
    ├── babel.config.js
    ├── blog/
    │   ├── 2019-05-28-first-blog-post.md
    │   ├── 2019-05-29-long-blog-post.md
    │   ├── 2021-08-01-mdx-blog-post.mdx
    │   ├── 2021-08-26-welcome/
    │   │   └── index.md
    │   └── authors.yml
    ├── docs/
    │   ├── api_reference/
    │   │   ├── _category_.json
    │   │   ├── high_level_api/
    │   │   │   ├── _category_.json
    │   │   │   ├── createStore.md
    │   │   │   ├── store.clear.md
    │   │   │   ├── store.getState.md
    │   │   │   ├── store.getStateValue.md
    │   │   │   ├── store.has.md
    │   │   │   ├── store.items.md
    │   │   │   ├── store.persist.md
    │   │   │   ├── store.remove.md
    │   │   │   ├── store.setState.md
    │   │   │   ├── store.subscribe.md
    │   │   │   ├── store.useReducer.md
    │   │   │   └── store.useState.md
    │   │   ├── intro.md
    │   │   ├── low_level_api/
    │   │   │   ├── _category_.json
    │   │   │   ├── createState.md
    │   │   │   ├── useReducer.md
    │   │   │   └── useState.md
    │   │   └── typing-state.md
    │   ├── basic_concepts/
    │   │   ├── _category_.json
    │   │   ├── derived_state.md
    │   │   ├── managing_subscriptions.md
    │   │   ├── state_persistence.md
    │   │   ├── store.md
    │   │   └── using_store_state.md
    │   ├── basic_tutorial/
    │   │   ├── _category_.json
    │   │   └── intro.md
    │   └── introduction/
    │       ├── _category_.json
    │       ├── getting_started.md
    │       ├── installation.md
    │       └── motivation.md
    ├── docusaurus.config.js
    ├── package.json
    ├── sidebars.js
    ├── src/
    │   ├── components/
    │   │   └── HomepageFeatures/
    │   │       ├── index.js
    │   │       └── styles.module.css
    │   ├── css/
    │   │   └── custom.css
    │   └── pages/
    │       ├── index.js
    │       ├── index.module.css
    │       └── markdown-page.md
    └── static/
        └── .nojekyll
Download .txt
SYMBOL INDEX (60 symbols across 7 files)

FILE: src/State.ts
  type Refresh (line 12) | type Refresh = () => void
  type Observer (line 15) | type Observer<ST> = (newState: ST) => void
  type Subscriber (line 18) | type Subscriber<ST> = {
  class State (line 25) | class State<T> {
    method constructor (line 29) | constructor(initialValue: StateInitializer<T> | T) {
    method getValue (line 39) | getValue<ST>(selector?: Selector<ST>): T | ST {
    method refresh (line 46) | refresh(): void {
    method setValue (line 68) | setValue<ST>(
    method updateValue (line 108) | updateValue<ST>(
    method __updateValue (line 121) | private __updateValue<ST>(stateUpdater: StateUpdater<T | ST> | StateMo...
    method subscribe (line 161) | subscribe<ST>(itemToSubscribe: Subscriber<T | ST> | Observer<T | ST>):...
    method select (line 188) | select<ST>(selector: Selector<ST>): DerivedState<T, ST> {
    method useState (line 218) | useState<ST>(
    method useReducer (line 257) | useReducer(
  class DerivedState (line 270) | class DerivedState<T, ST> {
    method constructor (line 274) | constructor(State: State<unknown>, selector: Selector<ST>) {
    method getValue (line 279) | getValue(): ST {
    method subscribe (line 283) | subscribe(observer?: Observer<ST>, refresh?: Refresh): Unsubscribe {
  function createDerivedState (line 295) | function createDerivedState<T, ST>(State: State<T>, selector: Selector<S...
  function createState (line 300) | function createState<T>(initialValue: StateInitializer<T> | T): State<T> {

FILE: src/Store.ts
  type StoreObserver (line 10) | type StoreObserver = (key: string, value: unknown) => void
  type PersistenceConfig (line 12) | type PersistenceConfig = {
  type StoreState (line 20) | type StoreState<T> = {
  type StoreInitializer (line 26) | type StoreInitializer = { [key: string]: unknown } | (() => { [key: stri...
  class Empty (line 39) | class Empty { }  // Class for empty state/value
  constant EMPTY (line 40) | const EMPTY = new Empty();
  class PersistentStorage (line 42) | class PersistentStorage {
    method loadState (line 45) | loadState(key: string, noState: Empty): unknown {
    method saveState (line 49) | saveState(key: string, state: unknown, isInitialSet?: boolean) {
  class Store (line 59) | class Store {
    method constructor (line 64) | constructor(storeInitializer?: StoreInitializer) {
    method subscribe (line 82) | subscribe(observer: StoreObserver): () => void {
    method onStoreUpdate (line 97) | private onStoreUpdate(key: string, value: unknown): void {
    method persist (line 103) | persist(config: PersistenceConfig): void {
    method setState (line 121) | setState<T>(
    method getState (line 178) | getState<T>(
    method has (line 215) | has(key: string) {
    method items (line 220) | items(): Array<[key: string, state: unknown, persist: boolean]> {
    method getStateValue (line 228) | getStateValue<ST, T = unknown>(key: string, selector?): T | ST {
    method clear (line 233) | clear(fn?: () => void): void {
    method remove (line 265) | remove(Statekey: string | string[], fn?: () => void): void {
    method useState (line 343) | useState(
    method useReducer (line 390) | useReducer(
  function createStore (line 408) | function createStore(storeInitializer?: StoreInitializer): Store {

FILE: src/types.ts
  type Unsubscribe (line 4) | type Unsubscribe = () => void
  type Reducer (line 7) | type Reducer<ST, A> = (state: ST, action: A) => ST
  type Selector (line 10) | type Selector<ST> = (state: any) => ST
  type Patcher (line 13) | type Patcher<ST> = (state: any, value: ST) => void
  type StateInitializer (line 16) | type StateInitializer<T> = () => T
  type StateUpdater (line 19) | type StateUpdater<ST> = (state: ST) => ST
  type StateModifier (line 22) | type StateModifier<ST> = (state: ST) => void
  type SetState (line 25) | type SetState<ST> = (newState: ST | StateUpdater<ST>) => void
  type UpdateState (line 28) | type UpdateState<ST> = (updater: StateModifier<ST>) => void

FILE: src/useReducer.ts
  function useStateObject (line 7) | function useStateObject(state) {
  function useReducer (line 62) | function useReducer(

FILE: src/useState.ts
  function useState (line 38) | function useState(

FILE: website/src/components/HomepageFeatures/index.js
  function Feature (line 37) | function Feature({Svg, title, description}) {
  function HomepageFeatures (line 51) | function HomepageFeatures() {

FILE: website/src/pages/index.js
  function HomepageHeader (line 9) | function HomepageHeader() {
  function Home (line 28) | function Home() {
Condensed preview — 76 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (146K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 19,
    "preview": "patreon: yezyilomo\n"
  },
  {
    "path": ".github/workflows/node.js.yml",
    "chars": 804,
    "preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
  },
  {
    "path": ".gitignore",
    "chars": 316,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2020 Yezy Ilomo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 9190,
    "preview": "# [State Pool](https://yezyilomo.github.io/state-pool/)\n\n![Build Status](https://github.com/yezyilomo/state-pool/actions"
  },
  {
    "path": "babel.config.js",
    "chars": 100,
    "preview": "// babel.config.js\nmodule.exports = {\n    presets: ['@babel/preset-env', '@babel/preset-react'],\n};\n"
  },
  {
    "path": "package.json",
    "chars": 2151,
    "preview": "{\n    \"name\": \"state-pool\",\n    \"private\": true,\n    \"version\": \"0.10.2\",\n    \"description\": \"Transform your React app w"
  },
  {
    "path": "src/State.ts",
    "chars": 8498,
    "preview": "import { produce, nothing } from \"immer\";\nimport {\n    StateInitializer, Selector, Patcher,\n    Reducer, Unsubscribe, St"
  },
  {
    "path": "src/Store.ts",
    "chars": 12885,
    "preview": "import State, { createState } from './State';\nimport {\n    StateInitializer, Selector, Patcher,\n    Reducer, SetState, U"
  },
  {
    "path": "src/index.ts",
    "chars": 488,
    "preview": "import State, { createState, DerivedState, createDerivedState } from './State';\nimport Store, { createStore } from './St"
  },
  {
    "path": "src/types.ts",
    "chars": 1134,
    "preview": "// Note; In all cases ST stands for type of selected state and T for base/original state\n\n// Function to call to unsubsc"
  },
  {
    "path": "src/useReducer.ts",
    "chars": 3163,
    "preview": "import React from 'react';\nimport State, { createState } from './State';\nimport { Patcher, Reducer, Selector, StateIniti"
  },
  {
    "path": "src/useState.ts",
    "chars": 1655,
    "preview": "import React from 'react';\nimport useReducer from './useReducer';\nimport State, { createState } from './State';\nimport {"
  },
  {
    "path": "tests/store.clear.test.ts",
    "chars": 929,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '"
  },
  {
    "path": "tests/store.getState.test.ts",
    "chars": 255,
    "preview": "import StatePool, { State } from '../src/';\n\n\nconst store = StatePool.createStore({count: 0});\n\ntest('should get user va"
  },
  {
    "path": "tests/store.getStateValue.test.ts",
    "chars": 386,
    "preview": "import React from 'react';\nimport StatePool from '../src/';\n\n\nconst store = StatePool.createStore({\n    user: { name: \"Y"
  },
  {
    "path": "tests/store.has.test.ts",
    "chars": 297,
    "preview": "import StatePool from '../src/';\n\n\nconst store = StatePool.createStore({ count: 0 });\n\ntest('should get user values', ()"
  },
  {
    "path": "tests/store.items.test.ts",
    "chars": 302,
    "preview": "import StatePool from '../src/';\n\n\nconst store = StatePool.createStore({\n    width: 10,\n    height: 15\n});\n\ntest('should"
  },
  {
    "path": "tests/store.persist.test.ts",
    "chars": 4016,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '"
  },
  {
    "path": "tests/store.remove.test.ts",
    "chars": 930,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '"
  },
  {
    "path": "tests/store.useReducer.test.ts",
    "chars": 823,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createStore } from '"
  },
  {
    "path": "tests/store.useState.test.ts",
    "chars": 1485,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport StatePool from '../src"
  },
  {
    "path": "tests/subscription.test.ts",
    "chars": 1473,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { createState, useStat"
  },
  {
    "path": "tests/useReducer.test.ts",
    "chars": 2270,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { useReducer, createSt"
  },
  {
    "path": "tests/useState.test.ts",
    "chars": 2994,
    "preview": "import React from 'react';\nimport { renderHook, act } from '@testing-library/react-hooks';\nimport { useState, createStat"
  },
  {
    "path": "tsconfig.json",
    "chars": 543,
    "preview": "{\n    \"compilerOptions\": {\n        \"target\": \"ES5\",\n        \"module\": \"commonjs\",\n        \"allowJs\": true,\n        \"outD"
  },
  {
    "path": "website/.gitignore",
    "chars": 233,
    "preview": "# 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.lo"
  },
  {
    "path": "website/README.md",
    "chars": 770,
    "preview": "# Website\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\n### I"
  },
  {
    "path": "website/babel.config.js",
    "chars": 89,
    "preview": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "website/blog/2019-05-28-first-blog-post.md",
    "chars": 389,
    "preview": "---\nslug: first-blog-post\ntitle: First Blog Post\nauthors:\n  name: Gao Wei\n  title: Docusaurus Core Team\n  url: https://g"
  },
  {
    "path": "website/blog/2019-05-29-long-blog-post.md",
    "chars": 3116,
    "preview": "---\nslug: long-blog-post\ntitle: Long Blog Post\nauthors: endi\ntags: [hello, docusaurus]\n---\n\nThis is the summary of a ver"
  },
  {
    "path": "website/blog/2021-08-01-mdx-blog-post.mdx",
    "chars": 439,
    "preview": "---\nslug: mdx-blog-post\ntitle: MDX Blog Post\nauthors: [slorber]\ntags: [docusaurus]\n---\n\nBlog posts support [Docusaurus M"
  },
  {
    "path": "website/blog/2021-08-26-welcome/index.md",
    "chars": 783,
    "preview": "---\nslug: welcome\ntitle: Welcome\nauthors: [slorber, yangshun]\ntags: [facebook, hello, docusaurus]\n---\n\n[Docusaurus blogg"
  },
  {
    "path": "website/blog/authors.yml",
    "chars": 446,
    "preview": "endi:\n  name: Endilie Yacop Sucipto\n  title: Maintainer of Docusaurus\n  url: https://github.com/endiliey\n  image_url: ht"
  },
  {
    "path": "website/docs/api_reference/_category_.json",
    "chars": 54,
    "preview": "{\n    \"label\": \"API Reference\",\n    \"position\": 4\n}\n  "
  },
  {
    "path": "website/docs/api_reference/high_level_api/_category_.json",
    "chars": 55,
    "preview": "{\n    \"label\": \"High Level API\",\n    \"position\": 2\n}\n  "
  },
  {
    "path": "website/docs/api_reference/high_level_api/createStore.md",
    "chars": 513,
    "preview": "---\nsidebar_position: 1\n---\n\n# createStore\nStore is a container for state, it comes with several methods which are used "
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.clear.md",
    "chars": 1984,
    "preview": "---\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 anym"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.getState.md",
    "chars": 540,
    "preview": "---\nsidebar_position: 5\n---\n\n# store.getState\n`store.getState` is used to get a state object from a store, it accepts on"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.getStateValue.md",
    "chars": 344,
    "preview": "---\nsidebar_position: 12\n---\n\n# store.getStateValue\nThis method is used to get state value directly from a store given i"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.has.md",
    "chars": 632,
    "preview": "---\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 yo"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.items.md",
    "chars": 317,
    "preview": "---\nsidebar_position: 11\n---\n\n# store.items\n`store.items` is used to iterate over an entire store, it returns an array c"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.persist.md",
    "chars": 5900,
    "preview": "---\nsidebar_position: 9\n---\n\n# store.persist\nSometimes you might want to save your states in a permanent storage probabl"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.remove.md",
    "chars": 1499,
    "preview": "---\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 "
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.setState.md",
    "chars": 995,
    "preview": "---\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 "
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.subscribe.md",
    "chars": 1317,
    "preview": "---\nsidebar_position: 6\n---\n\n# store.subscribe\nIf you want to listen to changes in a store you can subscribe to it by us"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.useReducer.md",
    "chars": 1882,
    "preview": "---\nsidebar_position: 4\n---\n\n# store.useReducer\nThis is an alternative to `store.useState`, it works just like `React.us"
  },
  {
    "path": "website/docs/api_reference/high_level_api/store.useState.md",
    "chars": 4285,
    "preview": "---\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"
  },
  {
    "path": "website/docs/api_reference/intro.md",
    "chars": 2835,
    "preview": "---\nsidebar_position: 1\n---\n\n# Intro\nState pool API is divided into two parts. \n1. High Level API(Store based API)\n2. Lo"
  },
  {
    "path": "website/docs/api_reference/low_level_api/_category_.json",
    "chars": 54,
    "preview": "{\n    \"label\": \"Low Level API\",\n    \"position\": 3\n}\n  "
  },
  {
    "path": "website/docs/api_reference/low_level_api/createState.md",
    "chars": 3137,
    "preview": "---\nsidebar_position: 1\n---\n\n# createState\nThis is the basic unit of **state-pool**, it's a function which is used to cr"
  },
  {
    "path": "website/docs/api_reference/low_level_api/useReducer.md",
    "chars": 3285,
    "preview": "---\nsidebar_position: 3\n---\n\n# useReducer\nThis is an alternative to `useState`, it works just like `React.useReducer` ho"
  },
  {
    "path": "website/docs/api_reference/low_level_api/useState.md",
    "chars": 4693,
    "preview": "---\nsidebar_position: 2\n---\n\n# useState\n`useState` is a hook that used within a react component to subscribe to a state."
  },
  {
    "path": "website/docs/api_reference/typing-state.md",
    "chars": 4756,
    "preview": "---\nsidebar_position: 4\n---\n\n\n# Typing State\nAll state related functions support implicity and explicity typing.\n\nExampl"
  },
  {
    "path": "website/docs/basic_concepts/_category_.json",
    "chars": 55,
    "preview": "{\n    \"label\": \"Basic Concepts\",\n    \"position\": 2\n}\n  "
  },
  {
    "path": "website/docs/basic_concepts/derived_state.md",
    "chars": 2155,
    "preview": "---\nsidebar_position: 3\n---\n\n# Derived & Nested State\nWith state pool you can subscribe to deeply nested or derived stat"
  },
  {
    "path": "website/docs/basic_concepts/managing_subscriptions.md",
    "chars": 2301,
    "preview": "---\nsidebar_position: 4\n---\n\n# Managing Subscriptions\nIf you want to listen to changes from a state you can subscribe to"
  },
  {
    "path": "website/docs/basic_concepts/state_persistence.md",
    "chars": 4349,
    "preview": "---\nsidebar_position: 5\n---\n\n# State Persistence\nState pool has a built in support for state persistence through store A"
  },
  {
    "path": "website/docs/basic_concepts/store.md",
    "chars": 1625,
    "preview": "---\nsidebar_position: 1\n---\n\n# Store\nA store is a container for states. Store implements and encapsulates everything you"
  },
  {
    "path": "website/docs/basic_concepts/using_store_state.md",
    "chars": 3452,
    "preview": "---\nsidebar_position: 2\n---\n\n# Using Store State\nAfter creating a store and setting states to it we need to use our stat"
  },
  {
    "path": "website/docs/basic_tutorial/_category_.json",
    "chars": 55,
    "preview": "{\n    \"label\": \"Basic Tutorial\",\n    \"position\": 3\n}\n  "
  },
  {
    "path": "website/docs/basic_tutorial/intro.md",
    "chars": 56,
    "preview": "---\nsidebar_position: 1\n---\n\n# Intro\n\n## Coming soon...."
  },
  {
    "path": "website/docs/introduction/_category_.json",
    "chars": 53,
    "preview": "{\n    \"label\": \"Introduction\",\n    \"position\": 1\n}\n  "
  },
  {
    "path": "website/docs/introduction/getting_started.md",
    "chars": 6932,
    "preview": "---\nsidebar_position: 3\n---\n\n# Getting Started\nUsing **state-pool** to manage state is very simple, all you need to do i"
  },
  {
    "path": "website/docs/introduction/installation.md",
    "chars": 116,
    "preview": "---\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",
    "chars": 1509,
    "preview": "---\nsidebar_position: 1\n---\n\n# Motivation\n\n![Build Status](https://github.com/yezyilomo/state-pool/actions/workflows/nod"
  },
  {
    "path": "website/docusaurus.config.js",
    "chars": 3292,
    "preview": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require('pris"
  },
  {
    "path": "website/package.json",
    "chars": 909,
    "preview": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"star"
  },
  {
    "path": "website/sidebars.js",
    "chars": 727,
    "preview": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that gr"
  },
  {
    "path": "website/src/components/HomepageFeatures/index.js",
    "chars": 1587,
    "preview": "import React from 'react';\nimport clsx from 'clsx';\nimport styles from './styles.module.css';\n\nconst FeatureList = [\n  {"
  },
  {
    "path": "website/src/components/HomepageFeatures/styles.module.css",
    "chars": 138,
    "preview": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureSvg {\n  height: 200px;\n"
  },
  {
    "path": "website/src/css/custom.css",
    "chars": 1196,
    "preview": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framewor"
  },
  {
    "path": "website/src/pages/index.js",
    "chars": 1213,
    "preview": "import React from 'react';\nimport clsx from 'clsx';\nimport Layout from '@theme/Layout';\nimport Link from '@docusaurus/Li"
  },
  {
    "path": "website/src/pages/index.module.css",
    "chars": 365,
    "preview": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  "
  },
  {
    "path": "website/src/pages/markdown-page.md",
    "chars": 118,
    "preview": "---\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",
    "chars": 0,
    "preview": ""
  }
]

About this extraction

This page contains the full source code of the yezyilomo/state-pool GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 76 files (132.5 KB), approximately 35.2k tokens, and a symbol index with 60 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!