Skip to content

Commit

Permalink
Detached event bus (#3)
Browse files Browse the repository at this point in the history
* external weakmapped eventbus

* updated package version

* updated dependencies + added engines specs

* updated readme
  • Loading branch information
donnikitos authored Jun 1, 2022
1 parent 48b96c3 commit c4d0ec5
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 187 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ on variables mutability has started and developed into the current reactive exec

#### Is it ready to use?

At the current stage mutableJS is still in research stage and can (thought to) be used with the `@mutablejs/dom` package.
The package is still pretty experimental, but is already used in some small usable web-apps.\
`@mutablejs/core` is primarily used with the [@mutablejs/dom](https://www.npmjs.com/package/@mutablejs/dom) package, see the [Starter Repository](https://github.com/mutableJS/template-starter-typescript).

#### Accompanying packages?

Currently there is 1 more package: [@mutablejs/dom](https://www.npmjs.com/package/@mutablejs/dom) and 1 more repo: [mutableJS / Demo repo](https://github.com/mutableJS/demo).
Currently there is 1 more package: [@mutablejs/dom](https://www.npmjs.com/package/@mutablejs/dom) and 2 more repos: [mutableJS / TypeScript Starter Template](https://github.com/mutableJS/template-starter-typescript), [mutableJS / Demo Repo](https://github.com/mutableJS/demo).

## Installation

Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mutablejs/core",
"version": "0.1.81",
"version": "0.2.0",
"description": "Mutable state, with reactive functions - automatic recalculations on state changes",
"keywords": [
"mutable state",
Expand Down Expand Up @@ -39,9 +39,12 @@
},
"license": "MIT",
"devDependencies": {
"@types/node": "^17.0.31",
"typescript": "^4.6.4",
"vite": "^2.9.8"
"@types/node": "^17.0.38",
"typescript": "^4.7.2",
"vite": "^2.9.9"
},
"engines": {
"node": ">=17.0.0"
},
"dependencies": {}
}
28 changes: 12 additions & 16 deletions src/lib/eventBus.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
// TBD: Events clean up needed?
import { Mutable } from './types';

export type MutationCallback<Value = any> = (newVal: Value, oldVal: Value) => void;
type Callback<T> = (newVal: T, oldVal: T) => void;

function eventBus() {
const refs: MutationCallback[] = [];
const eventBus = new WeakMap<object, Callback<any>[]>();

const change: MutationCallback = (...data) => {
refs.forEach((fn) => fn(...data));
};
export function listen<T>(mutable: Mutable<T>, callback: Callback<T>) {
const listeners = eventBus.get(mutable) || [];
listeners.push(callback);

const changeHandler = (callback: MutationCallback) => {
refs.push(callback);
};

return {
change,
changeHandler,
};
eventBus.set(mutable, listeners);
}

export default eventBus;
export function emit<T>(mutable: Mutable<T>, newVal: T, oldVal?: T) {
eventBus.get(mutable)?.forEach((fn) => {
fn(newVal, oldVal);
});
}
29 changes: 13 additions & 16 deletions src/lib/mutable.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
import { Mutable } from './types';
import isRegularObject from './utils/isRegularObject';
import eventBus from './eventBus';
import { emit } from './eventBus';

export function mutable<Value extends any>(initialValue?: Value) {
const events = eventBus();

const obj = new Proxy(
{
value:
isRegularObject(initialValue) || Array.isArray(initialValue)
? mutableObject(initialValue, (newVal, oldVal) =>
events.change(newVal, oldVal),
)
? mutableObject(initialValue, handleChange)
: initialValue,
},
{
get(target, prop) {
switch (prop) {
case '_mutable':
return true;
case 'onChange':
return (callback: Mutable<Value>['onChange']) => {
events.changeHandler(callback);
};
default:
return target.value;
}
},
set(...[target, , value]) {
const prevValue = target.value;
set(target, prop, value) {
const oldVal = target.value;

if (value !== prevValue) {
if (value !== oldVal) {
target.value = value;
events.change(value, prevValue);

handleChange(value, oldVal);
}

return true;
},
},
);
) as Mutable<Value>;

function handleChange(newVal: Value, oldVal: any) {
emit(obj, newVal, oldVal);
}

return obj as Mutable<Value>;
return obj;
}

function mutableObject<Obj extends object | unknown[]>(
Expand Down
5 changes: 3 additions & 2 deletions src/lib/mutableFn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MaybeMutable, Mutable } from './types';
import mutable from './mutable';
import isMutable from './isMutable';
import { listen } from './eventBus';

type MaybeMutableTuple<Input extends [...any[]]> = Input extends [
infer First,
Expand Down Expand Up @@ -30,7 +31,7 @@ export function mutableFn<Params extends any[], ReturnType>(
const pureParams = [] as unknown as Params;
params.forEach((arg, i) => {
if (isMutable(arg)) {
arg.onChange((newVal) => {
listen(arg, (newVal) => {
pureParams[i] = newVal;

rerun();
Expand All @@ -42,7 +43,7 @@ export function mutableFn<Params extends any[], ReturnType>(

Object.entries(arg).forEach(([key, item]) => {
if (isMutable(item)) {
item.onChange((newVal) => {
listen(item, (newVal) => {
pureParams[i][key] = newVal;

rerun();
Expand Down
3 changes: 2 additions & 1 deletion src/lib/processMaybeMutable.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { MaybeMutable } from './types';
import isMutable from './isMutable';
import { listen } from './eventBus';

export function processMaybeMutable<Data extends any>(
actionFn: (data: Data) => void,
) {
return (data: MaybeMutable<Data>) => {
if (isMutable(data)) {
data.onChange(actionFn);
listen(data, actionFn);

actionFn(data.value);
} else if (data) {
Expand Down
3 changes: 0 additions & 3 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { MutationCallback } from './eventBus';

export type Mutable<Value> = {
readonly _mutable: true;
readonly onChange: (callback: MutationCallback<Value>) => void;
value: Value;
};

Expand Down
Loading

0 comments on commit c4d0ec5

Please sign in to comment.