diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..6778380
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: aromalanil
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: ['https://paypal.me/aromalanil','https://www.buymeacoffee.com/aromalanil']
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dbded66
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,30 @@
+---
+name: Bug report
+about: "\U0001F41E Found a bug? Report it here."
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Short Title**
+Give a short title for the issue
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See an error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Additional context**
+Add any other context about the problem here.
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..76add87
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+dist
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..430b399
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,3 @@
+tsconfig.json
+src
+.github
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..f5f7589
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "printWidth": 100,
+ "tabWidth": 2,
+ "singleQuote": true,
+ "trailingComma": "all",
+ "bracketSpacing": true,
+ "jsxBracketSameLine": true,
+ "parser": "flow",
+ "semi": true,
+ "useTabs": false,
+ "quoteProps": "as-needed",
+ "jsxSingleQuote": true,
+ "arrowParens": "always",
+ "endOfLine": "lf"
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0ef108b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,70 @@
+# 🦏 React Rhino
+
+React Rhino is a simple yet powerful state management library for [React](https://http://reactjs.org/)
+
+## Installation
+
+```bash
+# If you use npm:
+npm install react-rhino
+
+# Or if you use Yarn:
+yarn add react-rhino
+```
+
+## Usage
+
+### Step 1
+1. Create a `states.js` file in your `src` folder
+2. Import `createRhinoState` from `react-rhino`
+
+```js
+import createRhinoState from 'react-rhino'
+```
+
+3. Pass an object to the `createRhinoState` function where the keys uniquely identify the state and values will be the initial value of the corresponding state.
+
+```js
+const { RhinoProvider, useRhinoState } = createRhinoState({
+ name: "John Doe",
+ isLoggedIn: true
+})
+```
+4. `export` the `RhinoProvider` and `useRhinoState` from the file
+
+```js
+export { RhinoProvider, useRhinoState }
+```
+
+### Step 2
+1. Import the `RhinoProvider` from the file and wrap the `App` component with it.
+
+```js
+import { RhinoProvider } from './states.js`
+import App from "./App";
+
+const rootElement = document.getElementById("root");
+ReactDOM.render(
+
+
+ ,
+ rootElement
+);
+
+```
+
+### Step 3
+1. Import `useRhinoState` from the `states.js` to whichever component you want to use your global state.
+```js
+import { useRhinoState } from './states.js`
+```
+2. `useRhinoState` shares similar syntax with `useState` function. The only difference is that you pass a key to the hook instead of the initial value.
+```js
+const [name,setName] = useRhinoState("name")
+```
+
+> Note: Here "name" is the key identifying the state in the object we passed to `createRhinoState` function.
+
+
+## Author
+[Aromal Anil](https://aromalanil.tech)
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f259130
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,60 @@
+{
+ "name": "react-rhino",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@types/prop-types": {
+ "version": "15.7.3",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
+ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
+ },
+ "@types/react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==",
+ "requires": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "csstype": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
+ "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "react": {
+ "version": "17.0.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
+ "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "typescript": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz",
+ "integrity": "sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9779d46
--- /dev/null
+++ b/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "react-rhino",
+ "version": "1.0.0",
+ "description": "A simple state management library using React context",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "tsc"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/aromalanil/react-rhino.git"
+ },
+ "keywords": [
+ "react-state",
+ "state-management",
+ "react-state-management",
+ "react-rhino",
+ "rhino"
+ ],
+ "author": "Aromal Anil (https://aromalanil.tech)",
+ "bugs": {
+ "url": "https://github.com/aromalanil/react-rhino/issues"
+ },
+ "homepage": "https://github.com/aromalanil/react-rhino#readme",
+ "license": "MIT",
+ "devDependencies": {
+ "typescript": "^4.2.2"
+ },
+ "dependencies": {
+ "@types/react": "^17.0.2",
+ "react": "^17.0.1"
+ }
+}
diff --git a/src/create-single-rhino-state.tsx b/src/create-single-rhino-state.tsx
new file mode 100644
index 0000000..ea86c4a
--- /dev/null
+++ b/src/create-single-rhino-state.tsx
@@ -0,0 +1,51 @@
+import * as React from 'react';
+import { createContext, useContext, useState } from 'react';
+
+export interface ProviderProps {
+ children: React.ReactChildren | React.ReactChild;
+}
+
+/**
+ *
+ * Function to create a global state using React Context API,
+ * which returns the ContextProvider and hooks to get the
+ * state and updater function
+ *
+ * @param initialValue Initial value of the state
+ */
+function createSingleRhinoState(initialValue: T) {
+ //Creating Context for state value & state updater function
+ const ValueContext = React.createContext(initialValue);
+ const UpdaterContext = createContext>>(() => null);
+
+ /**
+ *
+ * React hook which returns the stateful value
+ * @return Global State
+ */
+ const useStateValue = () => useContext(ValueContext);
+
+ /**
+ *
+ * React hook which returns a function to update the global state
+ * @return Global state updater function
+ */
+ const useStateUpdate = () => useContext(UpdaterContext);
+
+ /**
+ *
+ * Provider Component which makes the state available to all the nested components
+ */
+ const Provider = ({ children }: ProviderProps) => {
+ const [state, setState] = useState(initialValue);
+
+ return (
+
+ {children}
+
+ );
+ };
+
+ return { Provider, useStateValue, useStateUpdate };
+}
+export default createSingleRhinoState;
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..1cfa9db
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,106 @@
+import * as React from 'react';
+import createSingleRhinoState, { ProviderProps } from './create-single-rhino-state';
+
+interface StateObject {
+ [key: string]: any | (() => any);
+}
+
+interface StateList {
+ provider: ({ children }: ProviderProps) => JSX.Element;
+ stateHook: () => T;
+ updaterHook: () => React.Dispatch>;
+}
+
+/**
+ *
+ * Function to creates global state using rhino
+ * @param globalStatesObject An Object containing all the global states to be created
+ * @example Sample Use of createRhinoState
+ * const { Provider, useRhinoState }=createRhinoState({user:"John Doe",isLoggedIn:true});
+ */
+const createRhinoState = (globalStatesObject: StateObject) => {
+ const stateListData: { [key: string]: StateList } = {};
+
+ Object.keys(globalStatesObject).forEach((key) => {
+ const initialValue = globalStatesObject[key];
+ const { Provider, useStateValue, useStateUpdate } = createSingleRhinoState(initialValue);
+
+ stateListData[key] = {
+ provider: Provider,
+ stateHook: useStateValue,
+ updaterHook: useStateUpdate,
+ };
+ });
+
+ /**
+ *
+ * Provider Component which makes the states available to all the nested components
+ */
+ const RhinoProvider = ({ children }: ProviderProps) => {
+ const stateList = Object.values(stateListData);
+ const listLength = stateList.length;
+
+ let RootProvider = ({ children }: ProviderProps) => <>{children}>;
+
+ for (let i = 0; i < listLength; i++) {
+ const Provider = stateList[i].provider;
+ const OldRootProvider = RootProvider;
+ RootProvider = ({ children }) => (
+
+ {children}
+
+ );
+ }
+ return {children};
+ };
+
+ /**
+ *
+ * React hook which returns the stateful value
+ * corresponding to the key provided
+ * @param key Key which represents the state
+ */
+ const useRhinoValue = (key: string): T => {
+ if (key in stateListData) {
+ return stateListData[key].stateHook();
+ } else {
+ throw new Error(`${key} is an invalid key`);
+ }
+ };
+
+ /**
+ *
+ * React hook which returns a function to update the global state
+ * corresponding to the key provided
+ * @param key Key which represents the state
+ */
+ const useSetRhinoState = (
+ key: string,
+ ): React.Dispatch> => {
+ if (key in stateListData) {
+ return stateListData[key].updaterHook();
+ } else {
+ throw new Error(`${key} is an invalid key`);
+ }
+ };
+
+ /**
+ *
+ * React hook which returns the stateful value corresponding to the key
+ * provided and a function to update it
+ * @param key Key which represents the state
+ */
+ const useRhinoState = (
+ key: string,
+ ): [T, React.Dispatch>] => {
+ if (key in stateListData) {
+ return [useRhinoValue(key), useSetRhinoState(key)];
+ } else {
+ throw new Error(`${key} is an invalid key`);
+ }
+ };
+
+ return { RhinoProvider, useRhinoState, useRhinoValue, useSetRhinoState };
+};
+
+export default createRhinoState;
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..85739b6
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "es2017",
+ "module": "commonjs",
+ "declaration": true,
+ "outDir": "./dist",
+ "strict": true,
+ "jsx": "react"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "**/__tests__/*"]
+}