Skip to content

feat: introduce AbstractEvent and upgrade to node 20.x #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"message": "Use `globalThis` instead"
}
],
"prefer-rest-params": 0,
"require-yield": 0,
"eqeqeq": ["error", "smart"],
"spaced-comment": [
Expand Down
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,79 @@ master:[![pipeline status](https://gitlab.com/MatrixAI/open-source/js-events/bad

Events for push-flow abstractions.

### `AbstractEvent`

```ts
// For when you just want a regular event without `detail`
// Note that the `detail` type is `null`
class Event1 extends AbstractEvent {}

// For when you want a event with `detail`
class Event2 extends AbstractEvent<string> {}

// Allow caller to customise the `detail` type
// Note that the `detail` type is `unknown`
// This would be rare to use, prefer `Event4`
class Event3<T> extends AbstractEvent<T> {}

// Allow caller to customise the `detail` type
// But this is more accurate as not passing anything
// Would mean the `detail` is in fact `null`
class Event4<T = null> extends AbstractEvent<T> {}

// When you need to customise the constructor signature
class Event5 extends AbstractEvent<string> {
constructor(options: CustomEventInit<string>) {
// Make sure you pass `arguments`!
super(Event5.name, options, arguments);
}
}
```

When redispatching an event, you must call `event.clone()`. The same instance cannot be redispatched. When the event is cloned, all constructor parameters are shallow-copied.

### `Evented`

We combine `Evented` with `AbstractEvent` to gain type-safety and convenience of the wildcard any handler.

```ts
class EventCustom extends AbstractEvent {}

interface X extends Evented {}
@Evented()
class X {}

const x = new X();

// Handle specific event, use the `name` property as the key
x.addEventListener(EventCustom.name, (e) => {
console.log(e as EventCustom);
});

// Handle any event
x.addEventListener((e) => {
// This is the wrapped underlying event
console.log((e as EventAny).detail);
})
```

Note that all events pass through the any event handler, it is not a "fall through" handler.

You can use this style to handle relevant events to perform side-effects, as well as propagate upwards irrelevant events.

Note that some side-effects you perform may trigger an infinite loop by causing something to emit the specific event type that you are handling. In these cases you should specialise handling of those events with a `once: true` option, so that they are only handled once.

```ts
x.addEventListener(EventInfinite.name, (e) => {
console.log(e as EventInfinite);
performActionThatMayTriggerEventInfinite();
}, { once: true });
```

This will terminate the infinite loop on the first time it gets handled.

Therefore it is a good idea to always be as specific with your event types as possible.

## Installation

```sh
Expand Down
48 changes: 38 additions & 10 deletions docs/assets/highlight.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
:root {
--light-hl-0: #795E26;
--dark-hl-0: #DCDCAA;
--light-hl-1: #000000;
--dark-hl-1: #D4D4D4;
--light-hl-2: #A31515;
--dark-hl-2: #CE9178;
--light-hl-3: #0000FF;
--dark-hl-3: #569CD6;
--light-hl-4: #008000;
--dark-hl-4: #6A9955;
--light-hl-0: #008000;
--dark-hl-0: #6A9955;
--light-hl-1: #0000FF;
--dark-hl-1: #569CD6;
--light-hl-2: #000000;
--dark-hl-2: #D4D4D4;
--light-hl-3: #267F99;
--dark-hl-3: #4EC9B0;
--light-hl-4: #001080;
--dark-hl-4: #9CDCFE;
--light-hl-5: #795E26;
--dark-hl-5: #DCDCAA;
--light-hl-6: #0070C1;
--dark-hl-6: #4FC1FF;
--light-hl-7: #AF00DB;
--dark-hl-7: #C586C0;
--light-hl-8: #A31515;
--dark-hl-8: #CE9178;
--light-code-background: #FFFFFF;
--dark-code-background: #1E1E1E;
}
Expand All @@ -19,6 +27,10 @@
--hl-2: var(--light-hl-2);
--hl-3: var(--light-hl-3);
--hl-4: var(--light-hl-4);
--hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7);
--hl-8: var(--light-hl-8);
--code-background: var(--light-code-background);
} }

Expand All @@ -28,6 +40,10 @@
--hl-2: var(--dark-hl-2);
--hl-3: var(--dark-hl-3);
--hl-4: var(--dark-hl-4);
--hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7);
--hl-8: var(--dark-hl-8);
--code-background: var(--dark-code-background);
} }

Expand All @@ -37,6 +53,10 @@
--hl-2: var(--light-hl-2);
--hl-3: var(--light-hl-3);
--hl-4: var(--light-hl-4);
--hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7);
--hl-8: var(--light-hl-8);
--code-background: var(--light-code-background);
}

Expand All @@ -46,6 +66,10 @@
--hl-2: var(--dark-hl-2);
--hl-3: var(--dark-hl-3);
--hl-4: var(--dark-hl-4);
--hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7);
--hl-8: var(--dark-hl-8);
--code-background: var(--dark-code-background);
}

Expand All @@ -54,4 +78,8 @@
.hl-2 { color: var(--hl-2); }
.hl-3 { color: var(--hl-3); }
.hl-4 { color: var(--hl-4); }
.hl-5 { color: var(--hl-5); }
.hl-6 { color: var(--hl-6); }
.hl-7 { color: var(--hl-7); }
.hl-8 { color: var(--hl-8); }
pre, code { background: var(--code-background); }
2 changes: 1 addition & 1 deletion docs/assets/search.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading