hermes-io 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# hermes-io
|
|
2
|
+
A lightweight javascript library that allows communication between Reactjs components by using the observer pattern and the hook api.
|
|
3
|
+
|
|
4
|
+
# Installation
|
|
5
|
+
```
|
|
6
|
+
npm i hermes-io --save
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
# Get started
|
|
10
|
+
In order to use `hermes-io` you need to create a react project by using something like [Create-react-app](https://create-react-app.dev/), hermes-io is Reactjs hook that communication between components,
|
|
11
|
+
let's see it in action, follow the next example:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
// observers.js
|
|
15
|
+
export const AddProductObserver = new Observer();
|
|
16
|
+
export const RemoveProductObserver = new Observer();
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
// App.js
|
|
20
|
+
import { useState } from 'react';
|
|
21
|
+
import { useObserver, Observer } from 'hermes-io';
|
|
22
|
+
import { RemoveProductObserver, AddProductObserver } from './observers';
|
|
23
|
+
import { Products } from './components/Products';
|
|
24
|
+
import { ShoppingCar } from './components/ShoppingCar';
|
|
25
|
+
|
|
26
|
+
export const App = (props = {}) => {
|
|
27
|
+
const [productsToBy, setProductsToBy] = useState([]);
|
|
28
|
+
const productsStore = useProductStore(); // get products from some store
|
|
29
|
+
const products = productsStore.get();
|
|
30
|
+
|
|
31
|
+
const handleRemoveProduct = (product = {}) => {
|
|
32
|
+
const newProducts = [...productsToBy].filter(({ id = '' }) => id !== product.id);
|
|
33
|
+
setProductsToBy(newProducts);
|
|
34
|
+
productsStore.remove(product);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const handleAddProduct = (product = {}) => {
|
|
38
|
+
setProductsToBy([...productsToBy, product]);
|
|
39
|
+
productsStore.update(product, { selected: true });
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
useObserver({
|
|
43
|
+
observer: AddProductObserver,
|
|
44
|
+
listener: handleAddProduct,
|
|
45
|
+
from: ['products-list'],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
useObserver({
|
|
49
|
+
observer: RemoveProductObserver,
|
|
50
|
+
listener: handleRemoveProduct,
|
|
51
|
+
from: ['shopping-car'],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return <div>
|
|
55
|
+
<Products data={products} />
|
|
56
|
+
<ShoppingCar data={productsToBy}/>
|
|
57
|
+
</div>
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// ShoppingCar.js
|
|
62
|
+
import { RemoveProductObserver } from '../observers';
|
|
63
|
+
|
|
64
|
+
export const ShoppingCar = (props = {}) => {
|
|
65
|
+
const handleRemoveProduct = (product = {}) => {
|
|
66
|
+
RemoveProductObserver.notify({ value: product, from 'shopping-car' });
|
|
67
|
+
};
|
|
68
|
+
return <div>
|
|
69
|
+
<ul>
|
|
70
|
+
{
|
|
71
|
+
data.map((product = {}) =>
|
|
72
|
+
<li key={product.id}>
|
|
73
|
+
<span>{product.name}</<span>
|
|
74
|
+
<p>{product.description}</p>
|
|
75
|
+
<small>${product.price}</<small>
|
|
76
|
+
<button onClick={() => handleRemoveProduct(product)}>Remove</<button>
|
|
77
|
+
</li>
|
|
78
|
+
))
|
|
79
|
+
}
|
|
80
|
+
</ul>
|
|
81
|
+
</div>
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Products.js
|
|
85
|
+
import { AddProductObserver } from '../observers';
|
|
86
|
+
|
|
87
|
+
export const Products = (props = {}) => {
|
|
88
|
+
const { data = [] } = props;
|
|
89
|
+
|
|
90
|
+
const handleAddProduct = (product = {}) => {
|
|
91
|
+
AddProductObserver.notify({ value: product, from 'products-list' });
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return <ul>
|
|
95
|
+
{
|
|
96
|
+
data.map((product = {}) =>
|
|
97
|
+
<li key={product.id}>
|
|
98
|
+
<span>{product.name}</<span>
|
|
99
|
+
<p>{product.description}</p>
|
|
100
|
+
<small>${product.price}</<small>
|
|
101
|
+
<button disabled={product.selected} onClick={() => handleAddProduct(product)}>Add to car</<button>
|
|
102
|
+
</li>
|
|
103
|
+
))
|
|
104
|
+
}
|
|
105
|
+
</ul>
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
package/context.js
CHANGED
|
@@ -1,7 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
let recording = false;
|
|
2
|
+
let collection = [];
|
|
3
|
+
|
|
4
|
+
const handleMessageFromDevtools = (event) => {
|
|
5
|
+
const { source, payload } = event.data;
|
|
6
|
+
if (source === "hermes-io-devtools") {
|
|
7
|
+
if (payload === "START_RECORDING") {
|
|
8
|
+
recording = true;
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (payload === "STOP_RECORDING") {
|
|
12
|
+
recording = false;
|
|
13
|
+
}
|
|
14
|
+
if (payload === "RESET_RECORDING") {
|
|
15
|
+
collection = [];
|
|
16
|
+
recording = false;
|
|
17
|
+
}
|
|
18
|
+
if (payload?.type === "SET_CONTEXT") {
|
|
19
|
+
const context = collection.find((context) => context._internalId === payload.id);
|
|
20
|
+
if (context) {
|
|
21
|
+
context.listener(context.value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
window.addEventListener("message", handleMessageFromDevtools);
|
|
2
28
|
|
|
3
29
|
export class Context {
|
|
4
30
|
id = null;
|
|
31
|
+
_internalId = null;
|
|
5
32
|
date = null;
|
|
6
33
|
value = null;
|
|
7
34
|
listener = null;
|
|
@@ -9,18 +36,39 @@ export class Context {
|
|
|
9
36
|
constructor(description) {
|
|
10
37
|
this.id = Symbol(description);
|
|
11
38
|
}
|
|
12
|
-
update({ value, listener }) {
|
|
39
|
+
update = ({ value, listener }) => {
|
|
13
40
|
this.date = new Date();
|
|
14
41
|
this.value = value;
|
|
15
42
|
this.stackTrace = this.getStackTrace();
|
|
16
43
|
this.listener = listener;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
if (recording) {
|
|
45
|
+
this.sendSnapshot();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
sendSnapshot = () => {
|
|
49
|
+
const snapshot = this.takeSnapshot();
|
|
50
|
+
const { listener, stackTrace, value, date, _internalId } = snapshot;
|
|
51
|
+
collection.push(snapshot);
|
|
52
|
+
window.postMessage(
|
|
53
|
+
{
|
|
54
|
+
type: "CONTEXT_SNAPSHOT",
|
|
55
|
+
payload: { value: JSON.stringify(value.value), listener: listener.name, stackTrace, date, id: _internalId },
|
|
56
|
+
source: "hermes-io",
|
|
57
|
+
},
|
|
58
|
+
"*"
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
takeSnapshot = () => {
|
|
62
|
+
return {
|
|
63
|
+
_internalId: crypto.randomUUID(),
|
|
64
|
+
value: this.value,
|
|
65
|
+
date: this.date,
|
|
66
|
+
listener: this.listener,
|
|
67
|
+
stackTrace: this.stackTrace,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
getStackTrace = () => {
|
|
23
71
|
const err = new Error();
|
|
24
72
|
return err.stack;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -44,9 +44,10 @@ function App() {
|
|
|
44
44
|
setProducts([...productsStore.get('collection')]);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
const handleAddProduct = ({ value: product = {} }) => {
|
|
47
|
+
const handleAddProduct = ({ value: product = {} }, resolve) => {
|
|
48
48
|
product.selected = true;
|
|
49
49
|
setProducts([...productsStore.get('collection')]);
|
|
50
|
+
resolve();
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
useObserver({
|
|
@@ -15,8 +15,9 @@ import * as contexts from "@contexts";
|
|
|
15
15
|
const Products = (props = {}) => {
|
|
16
16
|
const { data = [] } = props;
|
|
17
17
|
|
|
18
|
-
const handleAddProduct = (product = {}) => {
|
|
19
|
-
ProductsObserver.add.notify({ value: product, context: contexts.products });
|
|
18
|
+
const handleAddProduct = async (product = {}) => {
|
|
19
|
+
const result = await ProductsObserver.add.notify({ value: product, context: contexts.products });
|
|
20
|
+
console.log({ result });
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const handleRemoveProduct = (product = {}) => {
|
package/hooks/useObserver.js
CHANGED
|
@@ -3,12 +3,12 @@ import React, { useEffect } from "react";
|
|
|
3
3
|
export const useObserver = (props = {}) => {
|
|
4
4
|
useEffect(() => {
|
|
5
5
|
const { observer, listener, contexts = [] } = props;
|
|
6
|
-
function handleAction(payload) {
|
|
6
|
+
function handleAction(payload, resolve) {
|
|
7
7
|
const hasfromList = contexts.length !== 0;
|
|
8
8
|
const hasValidList = hasfromList && contexts.find((ctx) => ctx.id === payload?.context?.id);
|
|
9
9
|
if (hasValidList) {
|
|
10
10
|
payload?.context?.update({ value: payload, listener });
|
|
11
|
-
listener?.(payload);
|
|
11
|
+
listener?.(payload, resolve);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
observer.subscribe(handleAction);
|
package/main.js
CHANGED
|
@@ -7,6 +7,8 @@ export class Observer {
|
|
|
7
7
|
this.subscriptors.splice(this.subscriptors.findIndex(cb => cb === callback), 1);
|
|
8
8
|
}
|
|
9
9
|
notify(args = {}) {
|
|
10
|
-
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
this.subscriptors.forEach(callback => callback(args, resolve));
|
|
12
|
+
})
|
|
11
13
|
}
|
|
12
14
|
}
|
package/package.json
CHANGED