-
-
Notifications
You must be signed in to change notification settings - Fork 231
/
client.ts
80 lines (74 loc) · 2.41 KB
/
client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import 'zone.js';
import {
EnvironmentProviders,
Provider,
reflectComponentType,
ɵComponentType as ComponentType,
} from '@angular/core';
import { ApplicationRef, NgZone, createComponent } from '@angular/core';
import { createApplication } from '@angular/platform-browser';
import { Observable, Subject, takeUntil } from 'rxjs';
export default (element: HTMLElement) => {
return (
Component: ComponentType<unknown> & {
clientProviders?: (Provider | EnvironmentProviders)[];
},
props?: Record<string, unknown>,
_childHTML?: unknown
) => {
createApplication({
providers: [...(Component.clientProviders || [])],
}).then((appRef: ApplicationRef) => {
const zone = appRef.injector.get(NgZone);
zone.run(() => {
const componentRef = createComponent(Component, {
environmentInjector: appRef.injector,
hostElement: element,
});
const mirror = reflectComponentType(Component);
if (props && mirror) {
for (const [key, value] of Object.entries(props)) {
if (
mirror.inputs.some(
({ templateName, propName }) =>
templateName === key || propName === key
)
) {
componentRef.setInput(key, value);
}
}
}
if (mirror?.outputs.length && props?.['data-analog-id']) {
const destroySubject = new Subject<void>();
element.setAttribute(
'data-analog-id',
props['data-analog-id'] as string
);
mirror.outputs.forEach(({ templateName, propName }) => {
const outputName = templateName || propName;
const component = componentRef.instance as Record<
string,
Observable<unknown>
>;
component[outputName]
.pipe(takeUntil(destroySubject))
.subscribe((detail) => {
const event = new CustomEvent(outputName, {
bubbles: true,
cancelable: true,
composed: true,
detail,
});
element.dispatchEvent(event);
});
});
appRef.onDestroy(() => {
destroySubject.next();
destroySubject.complete();
});
}
appRef.attachView(componentRef.hostView);
});
});
};
};