Skip to content

Commit

Permalink
chore: add state manager
Browse files Browse the repository at this point in the history
  • Loading branch information
soub4i committed Sep 17, 2020
1 parent a86273f commit c150ad8
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 3 deletions.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,42 @@ use `<web-merge>` element to load you fragment into web page
```html
<web-merge lazy content="./fragments/fragment-1.html"></web-merge>
```
### State management

Web-merge includes a build-in simple state management system based on event (not Event bus).

The fragment `parent` expose a state object that can help you to mutate and get new store

```js

// fragment-3.html

const { state } = parent;

//initial state

state.init({ count: 0 })

//event name

const COUNT_CHANGE = "countChange";

//Apply side effects
state.on(COUNT_CHANGE, ({ count }) => {
document.querySelector("span.value").textContent = count;
});

//mutations

document.getElementById("inc").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count + 1 }));
});

document.getElementById("dec").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count - 1 }));
});

```


![](preview-2.gif)
3 changes: 3 additions & 0 deletions examples/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ <h3>Basic usage with a frontend app</h3>
<web-merge lazy content="http://localhost:4200"></web-merge>
<web-merge content="http://localhost:3000"></web-merge>

<h3>Basic usage with a State management</h3>
<web-merge content="./fragments/fragment-3.html"></web-merge>
<web-merge content="./fragments/fragment-4.html"></web-merge>

<script type="module" src="/lib/index.js"></script>

Expand Down
47 changes: 47 additions & 0 deletions examples/fragments/fragment-3.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">

<head>
<style>
.block {
margin: 25px;
border-style: dotted;
}
</style>
</head>

<body>

<div class="block">
Fragment 3

<div class="counter">Counter <span class="value">0</span></div>
<button id="inc">+</button>
<button id="dec">-</button>


</div>

<script>
const { state } = parent;


const COUNT_CHANGE = "countChange";

state.on(COUNT_CHANGE, ({ count }) => {
document.querySelector("span.value").textContent = count;
});

document.getElementById("inc").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count + 1 }));
});

document.getElementById("dec").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count - 1 }));
});

</script>

</body>

</html>
49 changes: 49 additions & 0 deletions examples/fragments/fragment-4.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">

<head>
<style>
.block {
margin: 25px;
border-style: dotted;
}
</style>
</head>

<body>

<div class="block">
Fragment 4

<div class="counter">Counter <span class="value">0</span></div>
<button id="inc">+</button>
<button id="dec">-</button>


</div>


<script>
const { state } = parent;

state.init({ count: 0 })

const COUNT_CHANGE = "countChange";

state.on(COUNT_CHANGE, ({ count }) => {
document.querySelector("span.value").textContent = count;
});

document.getElementById("inc").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count + 1 }));
});

document.getElementById("dec").addEventListener("click", function () {
state.dispatch(COUNT_CHANGE, ({ count }) => ({ count: count - 1 }));
});

</script>

</body>

</html>
2 changes: 0 additions & 2 deletions lib/fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ export default class WebFragment extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });

this.content = document.createElement('iframe')
this.content.style.border = 0
this.content.loading = "eager"
this.content.innerHTML = '<slot/>'

this.shadowRoot.append(this.content)
}
connectedCallback() {
Expand Down
5 changes: 5 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import WebFragment from "./fragment.js"
import State from "./state.js"


if (!window.state) {
window.state = new State;
}

customElements.define('web-merge', WebFragment)
78 changes: 78 additions & 0 deletions lib/state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const deepFreeze = (o) => {
Object.freeze(o);

Object.keys(o).forEach(key => {
if (
o.hasOwnProperty(key) &&
o[key] !== null &&
(typeof o[key] === "object" || typeof o[key] === "function") &&
!Object.isFrozen(o[key])
) {
deepFreeze(o[key]);
}
});

return o;
}


export default class Stater {

constructor(initialStore = {}) {
this.store = initialStore;
this.events = {}
}

init(initialStore) {
this.store = { ...this.store, ...initialStore };
}

dispatch(eventName, payload) {

if (typeof payload == "function") payload = payload(this.store);

if (Object.prototype.toString.call(payload) !== "[object Object]") {
console.error("Payload should be an object");
return false;
}

if (!this.events.hasOwnProperty(eventName)) {
console.error(`Event "${eventName}" does not exists`);
return false;
}

this.store = { ...this.store, ...payload };

this.events[eventName].forEach(({ dep, cb }) => {
if (dep.length == 0) cb(deepFreeze(this.store));
else {
const t = {};
dep.forEach(k => {
if (this.store.hasOwnProperty(k)) t[k] = store[k];
});

cb(deepFreeze(t));
}
});
}

on(eventName, cb, dep = []) {
if (typeof cb !== "function") {
console.error("on() method expects 2nd argument as a callback function");
return false;
}

if (Object.prototype.toString.call(dep) !== "[object Array]") {
console.error("on() method expects 3nd argument as an array");
return false;
}

if (!this.events.hasOwnProperty(eventName)) this.events[eventName] = [];

this.events[eventName].push({ dep, cb });

return true;
}


}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@soubai/web-merge",
"version": "1.0.2",
"version": "1.1.2",
"description": "Declarative custom element for micro-frontend architecture",
"main": "lib/index.js",
"author": "Abderrahim SOUBAI-ELIDRISI",
Expand Down
Binary file added preview-2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c150ad8

Please sign in to comment.