Compare commits
19 Commits
2102e9c8cf
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ad774185c2 | |||
| c513a54717 | |||
| 7e53db5785 | |||
| f463dec7f1 | |||
| 7f55ae0d4e | |||
| 6f52c56857 | |||
| cfdcdf1def | |||
| f8cdfe131f | |||
| 95f85aedaa | |||
| 5c7cf36cf3 | |||
| 2a84086828 | |||
| 1dcdc17436 | |||
| 466e95cb14 | |||
| 7ef7c44cf7 | |||
| bf31d5371e | |||
| fc4e96ab37 | |||
| 7af635a19b | |||
| 665dd28f93 | |||
| e026dcdb15 |
2
index.js
2
index.js
@@ -1,2 +0,0 @@
|
|||||||
import { Interactor, Action, Reaction } from "./interactor.js";
|
|
||||||
export { Interactor, Action, Reaction };
|
|
||||||
@@ -1,52 +1,81 @@
|
|||||||
import { Stream } from './stream.js';
|
import { Stream } from "@brycethorup/stream";
|
||||||
|
|
||||||
export class Interactor {
|
export class Interactor {
|
||||||
_actions = new Stream();
|
#actions = new Stream();
|
||||||
_reactions = new Stream();
|
#reactions = new Stream();
|
||||||
_latestReaction;
|
#latestReaction;
|
||||||
|
#latestReactions = {};
|
||||||
|
|
||||||
constructor(initialReaction = new Reaction()) {
|
constructor(initialReaction = new Reaction()) {
|
||||||
this._latestReactions = {};
|
this.#actions.listen((action) => {
|
||||||
this._actions.listen((action) => this._interaction(action));
|
let funcRef = `_handle${action.constructor.name}`;
|
||||||
|
if (!this[funcRef])
|
||||||
|
throw `${this.constructor.name} does not have a handler defined for the action "${action.constructor.name}". Create one by adding a function definition named "${funcRef}" in the ${this.constructor.name} class.`;
|
||||||
|
this[funcRef](action);
|
||||||
|
});
|
||||||
this._react(initialReaction);
|
this._react(initialReaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
act(action) {
|
act(action) {
|
||||||
if (!(action instanceof Action)) throw 'invalid action';
|
if (!(action instanceof Action)) throw "invalid action";
|
||||||
this._actions.add(action);
|
this.#actions.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(reactionHandler, provideLatestReaction = true) {
|
observe(reactionHandler, provideLatestReaction = true) {
|
||||||
if (provideLatestReaction) reactionHandler(this._latestReaction);
|
if (provideLatestReaction) reactionHandler(this.#latestReaction);
|
||||||
let listener = (reaction) => {
|
let listener = (reaction) => {
|
||||||
if (!(reaction instanceof Reaction)) throw 'invalid reaction';
|
if (!(reaction instanceof Reaction)) throw "invalid reaction";
|
||||||
reactionHandler(reaction);
|
reactionHandler(reaction);
|
||||||
};
|
};
|
||||||
this._reactions.listen(listener);
|
this.#reactions.listen(listener);
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
ignore(listener) {
|
ignore(listener) {
|
||||||
this._reactions.ignore(listener);
|
this.#reactions.ignore(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
_interaction(action) {}
|
|
||||||
|
|
||||||
_react(reaction) {
|
_react(reaction) {
|
||||||
if (!(reaction instanceof Reaction)) throw 'invalid reaction';
|
if (!(reaction instanceof Reaction)) throw "invalid reaction";
|
||||||
let latest = this._latestReactions[reaction.constructor.name];
|
let latest = this.#latestReactions[reaction.constructor.name];
|
||||||
if (!reaction.equals(latest)) {
|
if (!reaction.equals(latest)) {
|
||||||
this._latestReaction = reaction;
|
this.#latestReaction = reaction;
|
||||||
this._latestReactions[reaction.constructor.name] = reaction;
|
this.#latestReactions[reaction.constructor.name] = reaction;
|
||||||
this._reactions.add(reaction);
|
this.#reactions.add(reaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Action {}
|
export class Action {}
|
||||||
|
|
||||||
|
export class ActionBundle {
|
||||||
|
add(action) {
|
||||||
|
if (!(action.prototype instanceof Action)) {
|
||||||
|
throw "Only classes extended by `Action` can be added to a `ActionBundle`";
|
||||||
|
}
|
||||||
|
let actionName = action.name;
|
||||||
|
this[`#${actionName}`] = action;
|
||||||
|
Object.defineProperty(this, actionName, {
|
||||||
|
get: () => this[`#${actionName}`],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Reaction {
|
export class Reaction {
|
||||||
equals(reaction) {
|
equals(reaction) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ReactionBundle {
|
||||||
|
add(reaction) {
|
||||||
|
if (!(reaction.prototype instanceof Reaction)) {
|
||||||
|
throw "Only classes extended by `Reaction` can be added to a `ReactionBundle`";
|
||||||
|
}
|
||||||
|
let reactionName = reaction.name;
|
||||||
|
this[`#${reactionName}`] = reaction;
|
||||||
|
Object.defineProperty(this, reactionName, {
|
||||||
|
get: () => this[`#${reactionName}`],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "interactor",
|
"name": "@brycethorup/interactor",
|
||||||
"version": "1.0.4",
|
"version": "1.1.5",
|
||||||
"description": "Cross-element communications and state management utility.",
|
"description": "Cross-element communications and state management utility.",
|
||||||
"author": "Bryce Thorup",
|
"author": "Bryce Thorup",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "index.js",
|
"main": "interactor.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"stream": "^1.0.0"
|
"@brycethorup/stream": "^1.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user