Skip to content

Commit b58a7c9

Browse files
committed
feat(async-event-listener): add capability to listen to async-events
1 parent 87635a4 commit b58a7c9

File tree

5 files changed

+46
-25
lines changed

5 files changed

+46
-25
lines changed

src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77
ReadonlyKeys,
88
ShadowElement,
99
} from "./types";
10-
import { dispatchError } from "./utils";
10+
import { dispatchError, PlusnewAsyncEvent, PlusnewErrorEvent } from "./utils";
1111

1212
export type { ShadowElement } from "./types";
1313

@@ -99,8 +99,8 @@ export function createComponent<
9999
}
100100
> & {
101101
children?: ShadowElement;
102-
onplusnewerror?: (evt: CustomEvent<unknown>) => void;
103-
onplusnewasyncevent?: (evt: CustomEvent<Promise<unknown>>) => void;
102+
onplusnewerror?: (evt: PlusnewErrorEvent) => void;
103+
onplusnewasyncevent?: (evt: PlusnewAsyncEvent) => void;
104104
},
105105
): T;
106106
} {

src/reconciler/host.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ export const hostReconcile: Reconciler = (opt) => {
9191
}
9292

9393
if (result instanceof Promise) {
94-
dispatchAsyncEvent(opt.shadowCache.node as Element, result);
94+
dispatchAsyncEvent(
95+
opt.shadowCache.node as Element,
96+
evt,
97+
result,
98+
);
9599
if (active.eventPromises !== null) {
96100
active.eventPromises.push(result);
97101
}

src/types.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { PlusnewAsyncEvent, PlusnewErrorEvent } from "./utils";
2+
13
export const PLUSNEW_ELEMENT_TYPE = Symbol("plusnew-element-type");
24

35
export function Fragment(props: { children: ShadowElement }) {
@@ -79,22 +81,22 @@ export namespace JSX {
7981
HTMLElementTagNameMap[Tag]
8082
> & {
8183
children?: ShadowElement;
82-
onplusnewerror?: (evt: CustomEvent<unknown>) => void;
83-
onplusnewasyncevent?: (evt: CustomEvent<Promise<unknown>>) => void;
84+
onplusnewerror?: (evt: PlusnewErrorEvent) => void;
85+
onplusnewasyncevent?: (evt: PlusnewAsyncEvent) => void;
8486
};
8587
} & {
8688
[Tag in keyof SVGElementTagNameMap]: IntrinsicElementAttributes<
8789
SVGElementTagNameMap[Tag]
8890
> & {
8991
children?: ShadowElement;
90-
onplusnewerror?: (evt: CustomEvent<unknown>) => void;
91-
onplusnewasyncevent?: (evt: CustomEvent<Promise<unknown>>) => void;
92+
onplusnewerror?: (evt: PlusnewErrorEvent) => void;
93+
onplusnewasyncevent?: (evt: PlusnewAsyncEvent) => void;
9294
};
9395
};
9496

9597
export interface IntrinsicAttributes {
96-
onplusnewerror?: () => void;
97-
onplusnewasyncevent?: (evt: CustomEvent<Promise<unknown>>) => void;
98+
onplusnewerror?: (evt: PlusnewErrorEvent) => void;
99+
onplusnewasyncevent?: (evt: PlusnewAsyncEvent) => void;
98100
}
99101
}
100102

src/utils.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
const ERROR = "plusnewerror";
22
const ASYNC_EVENT = "plusnewasyncevent";
33

4-
export function dispatchError(element: Element, error: unknown) {
5-
const result = element.dispatchEvent(
6-
new CustomEvent(ERROR, {
4+
export class PlusnewErrorEvent extends CustomEvent<unknown> {
5+
constructor(error: unknown) {
6+
super(ERROR, {
77
detail: error,
88
cancelable: true,
99
bubbles: true,
1010
composed: true,
11-
}),
12-
);
11+
});
12+
}
13+
}
14+
15+
export class PlusnewAsyncEvent extends CustomEvent<{
16+
promise: Promise<unknown>;
17+
cause: Event;
18+
}> {
19+
constructor(originalEvent: Event, promise: Promise<unknown>) {
20+
super(ASYNC_EVENT, {
21+
detail: { promise, cause: originalEvent },
22+
cancelable: true,
23+
bubbles: true,
24+
composed: true,
25+
});
26+
}
27+
}
28+
29+
export function dispatchError(element: Element, error: unknown) {
30+
const result = element.dispatchEvent(new PlusnewErrorEvent(error));
1331

1432
if (result === true) {
1533
throw error;
@@ -18,14 +36,8 @@ export function dispatchError(element: Element, error: unknown) {
1836

1937
export function dispatchAsyncEvent(
2038
element: Element,
39+
originalEvent: Event,
2140
promise: Promise<unknown>,
2241
) {
23-
element.dispatchEvent(
24-
new CustomEvent(ASYNC_EVENT, {
25-
detail: promise,
26-
cancelable: true,
27-
bubbles: true,
28-
composed: true,
29-
}),
30-
);
42+
element.dispatchEvent(new PlusnewAsyncEvent(originalEvent, promise));
3143
}

test/async.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,13 @@ describe("webcomponent", () => {
7878
<span
7979
className={this.#loading.value === true ? "loading" : ""}
8080
onplusnewasyncevent={async (evt) => {
81-
if ((evt.target as HTMLElement).tagName === "BUTTON") {
81+
if (
82+
(evt.target as HTMLElement).tagName === "BUTTON" &&
83+
evt.detail.cause.type === "click"
84+
) {
8285
this.#loading.value = true;
8386
try {
84-
await evt.detail;
87+
await evt.detail.promise;
8588
} catch (_err) {}
8689
this.#loading.value = false;
8790
}

0 commit comments

Comments
 (0)