ngx-reactify 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/esm2022/ngx-reactify.mjs +5 -0
- package/esm2022/public-api.mjs +3 -0
- package/esm2022/util/angular-to-react.mjs +116 -0
- package/esm2022/util/react-to-angular.mjs +75 -0
- package/fesm2022/ngx-reactify.mjs +196 -0
- package/fesm2022/ngx-reactify.mjs.map +1 -0
- package/index.d.ts +6 -0
- package/ngx-reactify.d.ts.map +1 -0
- package/package.json +36 -0
- package/public-api.d.ts +3 -0
- package/public-api.d.ts.map +1 -0
- package/util/angular-to-react.d.ts +34 -0
- package/util/angular-to-react.d.ts.map +1 -0
- package/util/react-to-angular.d.ts +31 -0
- package/util/react-to-angular.d.ts.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# ngx-reactify
|
|
2
|
+
|
|
3
|
+
> This project is currently in a beta phase and features will be added upon pull requests.
|
|
4
|
+
I will try to minimize breaking changes between minor version revisions but some may be made until we reach 1.0.0.
|
|
5
|
+
|
|
6
|
+
This project aims to make using Angular components in React not suck, and vice-versa. This is a dependency of my other library, ngx-xyflow.
|
|
7
|
+
|
|
8
|
+
### Getting started:
|
|
9
|
+
|
|
10
|
+
##### Install React
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i react react-dom
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i -D @types/react
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
##### Install ngx-reactify
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i ngx-reactify
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Embed React component in Angular
|
|
27
|
+
|
|
28
|
+
##### Create component Interface
|
|
29
|
+
Next, you.
|
|
30
|
+
> This step is necessary as it creates Angular bindings that can be used.
|
|
31
|
+
> Important: You can't use the normal stylesheet imports from React. Put your styles in the component.scss file.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
|
35
|
+
import * as React from 'react';
|
|
36
|
+
|
|
37
|
+
import { ReactDemoWrappableComponent } from './react-demo'; // tsx file
|
|
38
|
+
import { ReactifyNgComponent } from 'ngx-reactify';
|
|
39
|
+
|
|
40
|
+
@Component({
|
|
41
|
+
selector: 'app-react-demo',
|
|
42
|
+
template: ``,
|
|
43
|
+
styleUrls: ['./react-demo.component.scss'],
|
|
44
|
+
standalone: true,
|
|
45
|
+
encapsulation: ViewEncapsulation.None
|
|
46
|
+
})
|
|
47
|
+
export class ReactDemoComponent extends ReactifyNgComponent {
|
|
48
|
+
override readonly ngReactComponent = ReactDemoWrappableComponent;
|
|
49
|
+
|
|
50
|
+
@Output() onNodeClick = new EventEmitter<[MouseEvent, Node]>();
|
|
51
|
+
@Output() onNodeDoubleClick = new EventEmitter<[MouseEvent, Node]>();
|
|
52
|
+
|
|
53
|
+
@Input() nodeTypes?: NodeTypes | undefined;
|
|
54
|
+
@Input() edgeTypes?: EdgeTypes | undefined;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
##### Using the component
|
|
59
|
+
|
|
60
|
+
Last, import and use `ReactDemoComponent` elsewhere in your application.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
|
|
64
|
+
import { Component } from '@angular/core';
|
|
65
|
+
import { ReactDemoComponent } from './react-demo.component';
|
|
66
|
+
|
|
67
|
+
@Component({
|
|
68
|
+
selector: 'app-demo',
|
|
69
|
+
template: `
|
|
70
|
+
<app-react-demo
|
|
71
|
+
[nodeTypes]="[1,2,3,4]"
|
|
72
|
+
(onNodeClick)="onNodeClick($event)"
|
|
73
|
+
/>
|
|
74
|
+
`,
|
|
75
|
+
imports: [ ReactDemoComponent ],
|
|
76
|
+
standalone: true
|
|
77
|
+
})
|
|
78
|
+
export class DemoComponent {
|
|
79
|
+
|
|
80
|
+
onNodeClick(evt) {
|
|
81
|
+
console.log(evt)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Embed Angular component in React
|
|
87
|
+
|
|
88
|
+
> :warn: Under construction.
|
|
89
|
+
<!--
|
|
90
|
+
```ts
|
|
91
|
+
import React from 'react';
|
|
92
|
+
import { ReactifyReactComponent } from 'ngx-reactify';
|
|
93
|
+
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
|
94
|
+
import { ReactDemoComponent } from './react-demo.component';
|
|
95
|
+
|
|
96
|
+
@Component({
|
|
97
|
+
selector: 'app-demo',
|
|
98
|
+
template: `<div (click)="onNodeClick($event)"></div>`,
|
|
99
|
+
standalone: true
|
|
100
|
+
})
|
|
101
|
+
export class DemoComponent {
|
|
102
|
+
onNodeClick(evt) {
|
|
103
|
+
console.log(evt)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const AngularReactComponent = ReactifyReactComponent(DemoComponent)
|
|
108
|
+
|
|
109
|
+
export default function App() {
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<img src="https://picsum.photos/200" className={'picture'}></img>
|
|
113
|
+
|
|
114
|
+
<div>
|
|
115
|
+
|
|
116
|
+
</div>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
``` -->
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXJlYWN0aWZ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL25neC1yZWFjdGlmeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpYy1hcGknO1xuIl19
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from './util/angular-to-react';
|
|
2
|
+
export * from './util/react-to-angular';
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyx5QkFBeUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vdXRpbC9hbmd1bGFyLXRvLXJlYWN0JztcbmV4cG9ydCAqIGZyb20gJy4vdXRpbC9yZWFjdC10by1hbmd1bGFyJztcbiJdfQ==
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createComponent, EventEmitter } from '@angular/core';
|
|
2
|
+
import { createApplication } from '@angular/platform-browser';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { firstValueFrom } from 'rxjs';
|
|
5
|
+
// declare const Zone;
|
|
6
|
+
// const zone = Zone ? new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} }) : null;
|
|
7
|
+
/**
|
|
8
|
+
* Wrap an angular component inside of a React memo object.
|
|
9
|
+
* Will attempt to bind @Input and @Output properties if provided,
|
|
10
|
+
* and will bind the react arguments directly as @Input properties.
|
|
11
|
+
*
|
|
12
|
+
* @experimental
|
|
13
|
+
* @param componentClass Angular component
|
|
14
|
+
* @param envInjector An `EnvironmentInjector` instance to be used for the component
|
|
15
|
+
* @param injector An `ElementInjector` instance
|
|
16
|
+
* @param _inputs
|
|
17
|
+
* @param _outputs
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export const ReactifyReactComponent = ({ component, appRef, injector, ngZone, staticInputs, staticOutputs, preSiblings, postSiblings, additionalChildren, rootElementName, containerElementName }) => React.memo((args) => {
|
|
21
|
+
const id = Math.random().toString();
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
try {
|
|
24
|
+
const componentInstance = createComponent(component, {
|
|
25
|
+
environmentInjector: appRef.injector,
|
|
26
|
+
elementInjector: injector,
|
|
27
|
+
hostElement: document.getElementById(id)
|
|
28
|
+
});
|
|
29
|
+
appRef.attachView(componentInstance.hostView);
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
// component.hostView = hostView;
|
|
32
|
+
Object.assign(staticInputs, args);
|
|
33
|
+
const { inputs, outputs } = component['ɵcmp'];
|
|
34
|
+
// Returns a list of entries that need to be set
|
|
35
|
+
// This makes it so that unnecessary setters are not invoked.
|
|
36
|
+
const updated = Object.entries(inputs).filter(([parentKey, childKey]) => {
|
|
37
|
+
return componentInstance.instance[childKey] != staticInputs[parentKey];
|
|
38
|
+
});
|
|
39
|
+
updated.forEach(([parentKey, childKey]) => {
|
|
40
|
+
if (staticInputs.hasOwnProperty(parentKey))
|
|
41
|
+
componentInstance.instance[childKey] = staticInputs[parentKey];
|
|
42
|
+
});
|
|
43
|
+
const outputSubscriptions = {};
|
|
44
|
+
// Get a list of unregistered outputs
|
|
45
|
+
const newOutputs = Object.entries(outputs).filter(([parentKey, childKey]) => {
|
|
46
|
+
return !outputSubscriptions[parentKey];
|
|
47
|
+
});
|
|
48
|
+
// Reverse bind via subscription
|
|
49
|
+
newOutputs.forEach(([parentKey, childKey]) => {
|
|
50
|
+
if (!staticOutputs.hasOwnProperty(parentKey))
|
|
51
|
+
return;
|
|
52
|
+
const target = componentInstance.instance[childKey];
|
|
53
|
+
const outputs = staticOutputs;
|
|
54
|
+
const sub = target.subscribe((...args) => {
|
|
55
|
+
// Run the callback in the provided zone
|
|
56
|
+
ngZone.run(() => {
|
|
57
|
+
outputs[parentKey](...args);
|
|
58
|
+
});
|
|
59
|
+
}); // Subscription
|
|
60
|
+
outputSubscriptions[parentKey] = sub;
|
|
61
|
+
});
|
|
62
|
+
// Wrap the destroy method to safely release the subscriptions
|
|
63
|
+
const originalDestroy = componentInstance.onDestroy?.bind(componentInstance);
|
|
64
|
+
componentInstance.onDestroy = (cb) => {
|
|
65
|
+
Object.values(outputSubscriptions).forEach(s => s.unsubscribe());
|
|
66
|
+
originalDestroy?.(cb);
|
|
67
|
+
};
|
|
68
|
+
componentInstance.changeDetectorRef.detectChanges();
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error(err);
|
|
72
|
+
}
|
|
73
|
+
}, []);
|
|
74
|
+
const elements = [
|
|
75
|
+
...(preSiblings || []),
|
|
76
|
+
React.createElement(containerElementName || "div", { id }),
|
|
77
|
+
...(postSiblings || []),
|
|
78
|
+
...(additionalChildren || [])
|
|
79
|
+
].filter(e => e);
|
|
80
|
+
return React.createElement(rootElementName || "div", {}, ...elements);
|
|
81
|
+
});
|
|
82
|
+
export const ReactifyAngularComponent2 = (component, props) => {
|
|
83
|
+
const inputRef = React.useRef(null);
|
|
84
|
+
const ctx = this;
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
// Is there a better way to do this?
|
|
87
|
+
let subscriptions;
|
|
88
|
+
let app;
|
|
89
|
+
(async () => {
|
|
90
|
+
// Code to run when the component mounts
|
|
91
|
+
app = await createApplication({ providers: [] });
|
|
92
|
+
const base = app.bootstrap(component, inputRef.current);
|
|
93
|
+
const { instance } = base;
|
|
94
|
+
await firstValueFrom(app.isStable);
|
|
95
|
+
// App has now bootstrapped fully.
|
|
96
|
+
subscriptions = [];
|
|
97
|
+
Object.entries(instance).filter(([k, v]) => {
|
|
98
|
+
// @Outputs are always Event Emitters (I think)
|
|
99
|
+
if (v instanceof EventEmitter) {
|
|
100
|
+
subscriptions.push(instance[k]?.subscribe(evt => props[k].call(ctx, evt)));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
instance[k] = props[k];
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
})();
|
|
107
|
+
return () => {
|
|
108
|
+
// Code to run when the component unmounts
|
|
109
|
+
subscriptions?.forEach(s => s?.unsubscribe());
|
|
110
|
+
app?.destroy();
|
|
111
|
+
};
|
|
112
|
+
}, []); // Empty dependency array ensures this effect runs only once on mount and cleanup on unmount
|
|
113
|
+
const obj = {};
|
|
114
|
+
return React.createElement("div");
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci10by1yZWFjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlsL2FuZ3VsYXItdG8tcmVhY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUEwQyxlQUFlLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RHLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzlELE9BQU8sS0FBSyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQy9CLE9BQU8sRUFBRSxjQUFjLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBR3BELHNCQUFzQjtBQUN0QixrR0FBa0c7QUFFbEc7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxFQUNuQyxTQUFTLEVBQ1QsTUFBTSxFQUNOLFFBQVEsRUFDUixNQUFNLEVBQ04sWUFBWSxFQUNaLGFBQWEsRUFDYixXQUFXLEVBQ1gsWUFBWSxFQUNaLGtCQUFrQixFQUNsQixlQUFlLEVBQ2Ysb0JBQW9CLEVBYXZCLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtJQUV0QixNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDcEMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7UUFDakIsSUFBSSxDQUFDO1lBRUQsTUFBTSxpQkFBaUIsR0FBRyxlQUFlLENBQUMsU0FBUyxFQUFFO2dCQUNqRCxtQkFBbUIsRUFBRSxNQUFNLENBQUMsUUFBUTtnQkFDcEMsZUFBZSxFQUFFLFFBQVE7Z0JBQ3pCLFdBQVcsRUFBRSxRQUFRLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQzthQUMzQyxDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsVUFBVSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1lB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QUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRTtnQkFDdkMsK0NBQStDO2dCQUMvQyxJQUFJLENBQUMsWUFBWSxZQUFZLEVBQUUsQ0FBQztvQkFDNUIsYUFBYSxDQUFDLElBQUksQ0FDZCxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FDekQsQ0FBQztnQkFDTixDQUFDO3FCQUNJLENBQUM7b0JBQ0YsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDM0IsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQyxDQUFDLEVBQUUsQ0FBQTtRQUVKLE9BQU8sR0FBRyxFQUFFO1lBQ1IsMENBQTBDO1lBQzFDLGFBQWEsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztZQUM5QyxHQUFHLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDbkIsQ0FBQyxDQUFDO0lBQ04sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsNEZBQTRGO0lBRXBHLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztJQUVmLE9BQU8sS0FBSyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUNyQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBUeXBlLCBBcHBsaWNhdGlvblJlZiwgSW5qZWN0b3IsIE5nWm9uZSwgY3JlYXRlQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGNyZWF0ZUFwcGxpY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cblxuLy8gZGVjbGFyZSBjb25zdCBab25lO1xuLy8gY29uc3Qgem9uZSA9IFpvbmUgPyBuZXcgWm9uZShab25lLmN1cnJlbnQsIHsgbmFtZTogXCJAZG90Z2xpdGNoX21lbnVcIiwgcHJvcGVydGllczoge30gfSkgOiBudWxsO1xuXG4vKipcbiAqIFdyYXAgYW4gYW5ndWxhciBjb21wb25lbnQgaW5zaWRlIG9mIGEgUmVhY3QgbWVtbyBvYmplY3QuXG4gKiBXaWxsIGF0dGVtcHQgdG8gYmluZCBASW5wdXQgYW5kIEBPdXRwdXQgcHJvcGVydGllcyBpZiBwcm92aWRlZCxcbiAqIGFuZCB3aWxsIGJpbmQgdGhlIHJlYWN0IGFyZ3VtZW50cyBkaXJlY3RseSBhcyBASW5wdXQgcHJvcGVydGllcy5cbiAqXG4gKiBAZXhwZXJpbWVudGFsXG4gKiBAcGFyYW0gY29tcG9uZW50Q2xhc3MgQW5ndWxhciBjb21wb25lbnRcbiAqIEBwYXJhbSBlbnZJbmplY3RvciAgICBBbiBgRW52aXJvbm1lbnRJbmplY3RvcmAgaW5zdGFuY2UgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXBvbmVudFxuICogQHBhcmFtIGluamVjdG9yICAgICAgIEFuIGBFbGVtZW50SW5qZWN0b3JgIGluc3RhbmNlXG4gKiBAcGFyYW0gX2lucHV0c1xuICogQHBhcmFtIF9vdXRwdXRzXG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgY29uc3QgUmVhY3RpZnlSZWFjdENvbXBvbmVudCA9ICh7XG4gICAgY29tcG9uZW50LFxuICAgIGFwcFJlZixcbiAgICBpbmplY3RvcixcbiAgICBuZ1pvbmUsXG4gICAgc3RhdGljSW5wdXRzLFxuICAgIHN0YXRpY091dHB1dHMsXG4gICAgcHJlU2libGluZ3MsXG4gICAgcG9zdFNpYmxpbmdzLFxuICAgIGFkZGl0aW9uYWxDaGlsZHJlbixcbiAgICByb290RWxlbWVudE5hbWUsXG4gICAgY29udGFpbmVyRWxlbWVudE5hbWVcbn06IHtcbiAgICBjb21wb25lbnQ6IFR5cGU8YW55PixcbiAgICBhcHBSZWY6IE9taXQ8QXBwbGljYXRpb25SZWYsICdfcnVubmluZ1RpY2snPixcbiAgICBpbmplY3RvcjogSW5qZWN0b3IsXG4gICAgbmdab25lOiBOZ1pvbmUsXG4gICAgc3RhdGljSW5wdXRzPzogeyBba2V5OiBzdHJpbmddOiBhbnk7IH0sXG4gICAgc3RhdGljT3V0cHV0cz86IHsgW2tleTogc3RyaW5nXTogRnVuY3Rpb247IH0sXG4gICAgcHJlU2libGluZ3M/OiBSZWFjdC5SZWFjdE5vZGVbXSxcbiAgICBwb3N0U2libGluZ3M/OiBSZWFjdC5SZWFjdE5vZGVbXSxcbiAgICBhZGRpdGlvbmFsQ2hpbGRyZW4/OiBSZWFjdC5SZWFjdE5vZGVbXSxcbiAgICByb290RWxlbWVudE5hbWU/OiBQYXJhbWV0ZXJzPHR5cGVvZiBSZWFjdC5jcmVhdGVFbGVtZW50PlswXSxcbiAgICBjb250YWluZXJFbGVtZW50TmFtZT86IHN0cmluZztcbn0pID0+IFJlYWN0Lm1lbW8oKGFyZ3MpID0+IHtcblxuICAgIGNvbnN0IGlkID0gTWF0aC5yYW5kb20oKS50b1N0cmluZygpO1xuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIHRyeSB7XG5cbiAgICAgICAgICAgIGNvbnN0IGNvbXBvbmVudEluc3RhbmNlID0gY3JlYXRlQ29tcG9uZW50KGNvbXBvbmVudCwge1xuICAgICAgICAgICAgICAgIGVudmlyb25tZW50SW5qZWN0b3I6IGFwcFJlZi5pbmplY3RvcixcbiAgICAgICAgICAgICAgICBlbGVtZW50SW5qZWN0b3I6IGluamVjdG9yLFxuICAgICAgICAgICAgICAgIGhvc3RFbGVtZW50OiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZClcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBhcHBSZWYuYXR0YWNoVmlldyhjb21wb25lbnRJbnN0YW5jZS5ob3N0Vmlldyk7XG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAvLyBjb21wb25lbnQuaG9zdFZpZXcgPSBob3N0VmlldztcblxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihzdGF0aWNJbnB1dHMsIGFyZ3MpO1xuXG4gICAgICAgICAgICBjb25zdCB7IGlucHV0cywgb3V0cHV0cyB9ID0gY29tcG9uZW50WyfJtWNtcCddO1xuXG4gICAgICAgICAgICAvLyBSZXR1cm5zIGEgbGlzdCBvZiBlbnRyaWVzIHRoYXQgbmVlZCB0byBiZSBzZXRcbiAgICAgICAgICAgIC8vIFRoaXMgbWFrZXMgaXQgc28gdGhhdCB1bm5lY2Vzc2FyeSBzZXR0ZXJzIGFyZSBub3QgaW52b2tlZC5cbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZWQgPSBPYmplY3QuZW50cmllcyhpbnB1dHMpLmZpbHRlcigoW3BhcmVudEtleSwgY2hpbGRLZXldOiBbc3RyaW5nLCBzdHJpbmddKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbXBvbmVudEluc3RhbmNlLmluc3RhbmNlW2NoaWxkS2V5XSAhPSBzdGF0aWNJbnB1dHNbcGFyZW50S2V5XTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB1cGRhdGVkLmZvckVhY2goKFtwYXJlbnRLZXksIGNoaWxkS2V5XTogW3N0cmluZywgc3RyaW5nXSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChzdGF0aWNJbnB1dHMuaGFzT3duUHJvcGVydHkocGFyZW50S2V5KSlcbiAgICAgICAgICAgICAgICAgICAgY29tcG9uZW50SW5zdGFuY2UuaW5zdGFuY2VbY2hpbGRLZXldID0gc3RhdGljSW5wdXRzW3BhcmVudEtleV07XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgY29uc3Qgb3V0cHV0U3Vic2NyaXB0aW9uczogeyBba2V5OiBzdHJpbmddOiBTdWJzY3JpcHRpb247IH0gPSB7fTtcbiAgICAgICAgICAgIC8vIEdldCBhIGxpc3Qgb2YgdW5yZWdpc3RlcmVkIG91dHB1dHNcbiAgICAgICAgICAgIGNvbnN0IG5ld091dHB1dHMgPSBPYmplY3QuZW50cmllcyhvdXRwdXRzKS5maWx0ZXIoKFtwYXJlbnRLZXksIGNoaWxkS2V5XTogW3N0cmluZywgc3RyaW5nXSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiAhb3V0cHV0U3Vic2NyaXB0aW9uc1twYXJlbnRLZXldO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIFJldmVyc2UgYmluZCB2aWEgc3Vic2NyaXB0aW9uXG4gICAgICAgICAgICBuZXdPdXRwdXRzLmZvckVhY2goKFtwYXJlbnRLZXksIGNoaWxkS2V5XTogW3N0cmluZywgc3RyaW5nXSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghc3RhdGljT3V0cHV0cy5oYXNPd25Qcm9wZXJ0eShwYXJlbnRLZXkpKSByZXR1cm47XG5cbiAgICAgICAgICAgICAgICBjb25zdCB0YXJnZXQ6IEV2ZW50RW1pdHRlcjx1bmtub3duPiA9IGNvbXBvbmVudEluc3RhbmNlLmluc3RhbmNlW2NoaWxkS2V5XTtcbiAgICAgICAgICAgICAgICBjb25zdCBvdXRwdXRzID0gc3RhdGljT3V0cHV0cztcblxuICAgICAgICAgICAgICAgIGNvbnN0IHN1YiA9IHRhcmdldC5zdWJzY3JpYmUoKC4uLmFyZ3MpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUnVuIHRoZSBjYWxsYmFjayBpbiB0aGUgcHJvdmlkZWQgem9uZVxuICAgICAgICAgICAgICAgICAgICBuZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHNbcGFyZW50S2V5XSguLi5hcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7IC8vIFN1YnNjcmlwdGlvblxuXG4gICAgICAgICAgICAgICAgb3V0cHV0U3Vic2NyaXB0aW9uc1twYXJlbnRLZXldID0gc3ViO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIFdyYXAgdGhlIGRlc3Ryb3kgbWV0aG9kIHRvIHNhZmVseSByZWxlYXNlIHRoZSBzdWJzY3JpcHRpb25zXG4gICAgICAgICAgICBjb25zdCBvcmlnaW5hbERlc3Ryb3kgPSBjb21wb25lbnRJbnN0YW5jZS5vbkRlc3Ryb3k/LmJpbmQoY29tcG9uZW50SW5zdGFuY2UpO1xuICAgICAgICAgICAgY29tcG9uZW50SW5zdGFuY2Uub25EZXN0cm95ID0gKGNiKSA9PiB7XG4gICAgICAgICAgICAgICAgT2JqZWN0LnZhbHVlcyhvdXRwdXRTdWJzY3JpcHRpb25zKS5mb3JFYWNoKHMgPT4gcy51bnN1YnNjcmliZSgpKTtcbiAgICAgICAgICAgICAgICBvcmlnaW5hbERlc3Ryb3k/LihjYik7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjb21wb25lbnRJbnN0YW5jZS5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgICB9XG4gICAgfSwgW10pO1xuXG4gICAgY29uc3QgZWxlbWVudHMgPSBbXG4gICAgICAgIC4uLihwcmVTaWJsaW5ncyB8fCBbXSksXG4gICAgICAgIFJlYWN0LmNyZWF0ZUVsZW1lbnQoY29udGFpbmVyRWxlbWVudE5hbWUgfHwgXCJkaXZcIiwgeyBpZCB9KSxcbiAgICAgICAgLi4uKHBvc3RTaWJsaW5ncyB8fCBbXSksXG4gICAgICAgIC4uLihhZGRpdGlvbmFsQ2hpbGRyZW4gfHwgW10pXG4gICAgXS5maWx0ZXIoZSA9PiBlKTtcblxuICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KHJvb3RFbGVtZW50TmFtZSB8fCBcImRpdlwiLCB7fSwgLi4uZWxlbWVudHMpO1xufSk7XG5cblxuZXhwb3J0IGNvbnN0IFJlYWN0aWZ5QW5ndWxhckNvbXBvbmVudDIgPSAoXG4gICAgY29tcG9uZW50OiBUeXBlPGFueT4sXG4gICAgcHJvcHM6IGFueVxuKSA9PiB7XG4gICAgY29uc3QgaW5wdXRSZWYgPSBSZWFjdC51c2VSZWYobnVsbCk7XG4gICAgY29uc3QgY3R4ID0gdGhpcztcblxuICAgIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICAgIC8vIElzIHRoZXJlIGEgYmV0dGVyIHdheSB0byBkbyB0aGlzP1xuICAgICAgICBsZXQgc3Vic2NyaXB0aW9uczogU3Vic2NyaXB0aW9uW107XG4gICAgICAgIGxldCBhcHA6IEFwcGxpY2F0aW9uUmVmO1xuICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgLy8gQ29kZSB0byBydW4gd2hlbiB0aGUgY29tcG9uZW50IG1vdW50c1xuICAgICAgICAgICAgYXBwID0gYXdhaXQgY3JlYXRlQXBwbGljYXRpb24oeyBwcm92aWRlcnM6IFtdIH0pO1xuICAgICAgICAgICAgY29uc3QgYmFzZSA9IGFwcC5ib290c3RyYXAoY29tcG9uZW50LCBpbnB1dFJlZi5jdXJyZW50KTtcbiAgICAgICAgICAgIGNvbnN0IHsgaW5zdGFuY2UgfSA9IGJhc2U7XG5cbiAgICAgICAgICAgIGF3YWl0IGZpcnN0VmFsdWVGcm9tKGFwcC5pc1N0YWJsZSk7XG5cbiAgICAgICAgICAgIC8vIEFwcCBoYXMgbm93IGJvb3RzdHJhcHBlZCBmdWxseS5cbiAgICAgICAgICAgIHN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICAgICAgICAgIE9iamVjdC5lbnRyaWVzKGluc3RhbmNlKS5maWx0ZXIoKFtrLCB2XSkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEBPdXRwdXRzIGFyZSBhbHdheXMgRXZlbnQgRW1pdHRlcnMgKEkgdGhpbmspXG4gICAgICAgICAgICAgICAgaWYgKHYgaW5zdGFuY2VvZiBFdmVudEVtaXR0ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgc3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2Vba10/LnN1YnNjcmliZShldnQgPT4gcHJvcHNba10uY2FsbChjdHgsIGV2dCkpXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZVtrXSA9IHByb3BzW2tdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pKClcblxuICAgICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICAgICAgLy8gQ29kZSB0byBydW4gd2hlbiB0aGUgY29tcG9uZW50IHVubW91bnRzXG4gICAgICAgICAgICBzdWJzY3JpcHRpb25zPy5mb3JFYWNoKHMgPT4gcz8udW5zdWJzY3JpYmUoKSk7XG4gICAgICAgICAgICBhcHA/LmRlc3Ryb3koKTtcbiAgICAgICAgfTtcbiAgICB9LCBbXSk7IC8vIEVtcHR5IGRlcGVuZGVuY3kgYXJyYXkgZW5zdXJlcyB0aGlzIGVmZmVjdCBydW5zIG9ubHkgb25jZSBvbiBtb3VudCBhbmQgY2xlYW51cCBvbiB1bm1vdW50XG5cbiAgICBjb25zdCBvYmogPSB7fTtcblxuICAgIHJldHVybiBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpXG59XG4iXX0=
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { createRoot } from 'react-dom/client';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Extend this component to automatically generate
|
|
7
|
+
* bindings to a React component.
|
|
8
|
+
*
|
|
9
|
+
* ! You _must_ override the property `ngReactComponent`
|
|
10
|
+
* Failure to do so will result in errors
|
|
11
|
+
* `override readonly ngReactComponent = ReactFlowWrappableComponent;`
|
|
12
|
+
*/
|
|
13
|
+
export class ReactifyNgComponent {
|
|
14
|
+
constructor(ngContainer, ngZone) {
|
|
15
|
+
this.ngContainer = ngContainer;
|
|
16
|
+
this.ngZone = ngZone;
|
|
17
|
+
}
|
|
18
|
+
ngOnInit() {
|
|
19
|
+
if (!this.ngReactComponent) {
|
|
20
|
+
throw new Error("ReactMagicWrapperComponent cannot start without a provided ngReactComponent!");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
ngOnChanges(changes) {
|
|
24
|
+
this._render();
|
|
25
|
+
}
|
|
26
|
+
ngAfterViewInit() {
|
|
27
|
+
this._render();
|
|
28
|
+
}
|
|
29
|
+
ngOnDestroy() {
|
|
30
|
+
this._root?.unmount();
|
|
31
|
+
}
|
|
32
|
+
_render() {
|
|
33
|
+
if (!this.ngReactComponent) {
|
|
34
|
+
console.log("Render no component. May be context issue");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
;
|
|
38
|
+
this.ngZone.runOutsideAngular(() => {
|
|
39
|
+
try {
|
|
40
|
+
this._root ??= createRoot(this.ngContainer.element.nativeElement);
|
|
41
|
+
// List all keys that do not start with `_` nor `ng`
|
|
42
|
+
const keys = Object.keys(this).filter(k => !/^(?:_|ng)/.test(k));
|
|
43
|
+
// Get all property keys from the class
|
|
44
|
+
const propKeys = keys.filter(k => !k.startsWith("on"));
|
|
45
|
+
// Get all event handler keys from the class
|
|
46
|
+
const evtKeys = keys.filter(k => k.startsWith("on"));
|
|
47
|
+
const props = {};
|
|
48
|
+
// Project all key properties onto `props`
|
|
49
|
+
propKeys.forEach(k => props[k] = this[k]);
|
|
50
|
+
// Attempt to ensure no zone is lost during the event emitter fires
|
|
51
|
+
this.ngZone.runGuarded(() => {
|
|
52
|
+
// Bind all event handlers.
|
|
53
|
+
// ! important Angular uses EventEmitter, React uses
|
|
54
|
+
// a different method of event binding
|
|
55
|
+
evtKeys.forEach(k => props[k] = (...args) => this[k].next(args));
|
|
56
|
+
});
|
|
57
|
+
this._root.render(React.createElement(this.ngReactComponent, { props: props }));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.error(err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ReactifyNgComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
65
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ReactifyNgComponent, isStandalone: true, selector: "app-react-magic-wrapper", usesOnChanges: true, ngImport: i0, template: ``, isInline: true }); }
|
|
66
|
+
}
|
|
67
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ReactifyNgComponent, decorators: [{
|
|
68
|
+
type: Component,
|
|
69
|
+
args: [{
|
|
70
|
+
selector: 'app-react-magic-wrapper',
|
|
71
|
+
template: ``,
|
|
72
|
+
standalone: true
|
|
73
|
+
}]
|
|
74
|
+
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.NgZone }] });
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVhY3QtdG8tYW5ndWxhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlsL3JlYWN0LXRvLWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFpQyxTQUFTLEVBQXdLLE1BQU0sZUFBZSxDQUFDO0FBQy9PLE9BQU8sS0FBSyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQy9CLE9BQU8sRUFBRSxVQUFVLEVBQVEsTUFBTSxrQkFBa0IsQ0FBQzs7QUFHcEQ7Ozs7Ozs7R0FPRztBQU1ILE1BQU0sT0FBTyxtQkFBbUI7SUFXNUIsWUFDcUIsV0FBNkIsRUFDN0IsTUFBYztRQURkLGdCQUFXLEdBQVgsV0FBVyxDQUFrQjtRQUM3QixXQUFNLEdBQU4sTUFBTSxDQUFRO0lBRW5DLENBQUM7SUFFRCxRQUFRO1FBQ0osSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsOEVBQThFLENBQUMsQ0FBQztRQUNwRyxDQUFDO0lBQ0wsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUF1QjtRQUMvQixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVELGVBQWU7UUFDWCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVELFdBQVc7UUFDUCxJQUFJLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFTyxPQUFPO1FBQ1gsSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkNBQTJDLENBQUMsQ0FBQTtZQUN4RCxPQUFNO1FBQ1YsQ0FBQztRQUFBLENBQUM7UUFFRixJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsRUFBRTtZQUMvQixJQUFJLENBQUM7Z0JBQ0QsSUFBSSxDQUFDLEtBQUssS0FBSyxVQUFVLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBRWxFLG9EQUFvRDtnQkFDcEQsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFFakUsdUNBQXVDO2dCQUN2QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ3ZELDRDQUE0QztnQkFDNUMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFFckQsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUNqQiwwQ0FBMEM7Z0JBQzFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBRTFDLG1FQUFtRTtnQkFDbkUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFO29CQUN4QiwyQkFBMkI7b0JBQzNCLG9EQUFvRDtvQkFDcEQsc0NBQXNDO29CQUN0QyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDckUsQ0FBQyxDQUFDLENBQUE7Z0JBRUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBWSxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzNGLENBQUM7WUFDRCxPQUFNLEdBQUcsRUFBRSxDQUFDO2dCQUNSLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7WUFDdEIsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQzs4R0F2RVEsbUJBQW1CO2tHQUFuQixtQkFBbUIsd0dBSGxCLEVBQUU7OzJGQUdILG1CQUFtQjtrQkFML0IsU0FBUzttQkFBQztvQkFDUCxRQUFRLEVBQUUseUJBQXlCO29CQUNuQyxRQUFRLEVBQUUsRUFBRTtvQkFDWixVQUFVLEVBQUUsSUFBSTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBZnRlclZpZXdJbml0LCBBcHBsaWNhdGlvblJlZiwgQ29tcG9uZW50LCBDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIsIEVudmlyb25tZW50SW5qZWN0b3IsIEV2ZW50RW1pdHRlciwgSW5qZWN0b3IsIE5nWm9uZSwgT25DaGFuZ2VzLCBPbkRlc3Ryb3ksIFNpbXBsZUNoYW5nZXMsIFR5cGUsIFZpZXdDb250YWluZXJSZWYsIFZpZXdSZWYsIGNyZWF0ZUNvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgY3JlYXRlUm9vdCwgUm9vdCB9IGZyb20gJ3JlYWN0LWRvbS9jbGllbnQnO1xuXG5cbi8qKlxuICogRXh0ZW5kIHRoaXMgY29tcG9uZW50IHRvIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVcbiAqIGJpbmRpbmdzIHRvIGEgUmVhY3QgY29tcG9uZW50LlxuICpcbiAqICEgWW91IF9tdXN0XyBvdmVycmlkZSB0aGUgcHJvcGVydHkgYG5nUmVhY3RDb21wb25lbnRgXG4gKiBGYWlsdXJlIHRvIGRvIHNvIHdpbGwgcmVzdWx0IGluIGVycm9yc1xuICogYG92ZXJyaWRlIHJlYWRvbmx5IG5nUmVhY3RDb21wb25lbnQgPSBSZWFjdEZsb3dXcmFwcGFibGVDb21wb25lbnQ7YFxuICovXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ2FwcC1yZWFjdC1tYWdpYy13cmFwcGVyJyxcbiAgICB0ZW1wbGF0ZTogYGAsXG4gICAgc3RhbmRhbG9uZTogdHJ1ZVxufSlcbmV4cG9ydCBjbGFzcyBSZWFjdGlmeU5nQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkRlc3Ryb3ksIEFmdGVyVmlld0luaXQge1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJlYWN0IGNvbXBvbmVudCB0byBiZSB3cmFwcGVkLlxuICAgICAqICEgTXVzdCBiZSBvdmVycmlkZGVuIGZvciB0aGlzIHdyYXBwZXIgdG8gd29ya1xuICAgICAqL1xuICAgIG5nUmVhY3RDb21wb25lbnQ6IFJlYWN0LkZ1bmN0aW9uQ29tcG9uZW50PGFueT4gfCBSZWFjdC5Db21wb25lbnRDbGFzczxhbnk+O1xuXG4gICAgcHJpdmF0ZSBfcm9vdDogUm9vdDtcbiAgICBwdWJsaWMgdGhlbWU6IHN0cmluZztcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG5nQ29udGFpbmVyOiBWaWV3Q29udGFpbmVyUmVmLFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG5nWm9uZTogTmdab25lXG4gICAgKSB7XG4gICAgfVxuXG4gICAgbmdPbkluaXQoKSB7XG4gICAgICAgIGlmICghdGhpcy5uZ1JlYWN0Q29tcG9uZW50KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZWFjdE1hZ2ljV3JhcHBlckNvbXBvbmVudCBjYW5ub3Qgc3RhcnQgd2l0aG91dCBhIHByb3ZpZGVkIG5nUmVhY3RDb21wb25lbnQhXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlcz86IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fcmVuZGVyKCk7XG4gICAgfVxuXG4gICAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgICAgICB0aGlzLl9yZW5kZXIoKTtcbiAgICB9XG5cbiAgICBuZ09uRGVzdHJveSgpIHtcbiAgICAgICAgdGhpcy5fcm9vdD8udW5tb3VudCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3JlbmRlcigpIHtcbiAgICAgICAgaWYgKCF0aGlzLm5nUmVhY3RDb21wb25lbnQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUmVuZGVyIG5vIGNvbXBvbmVudC4gTWF5IGJlIGNvbnRleHQgaXNzdWVcIilcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcm9vdCA/Pz0gY3JlYXRlUm9vdCh0aGlzLm5nQ29udGFpbmVyLmVsZW1lbnQubmF0aXZlRWxlbWVudCk7XG5cbiAgICAgICAgICAgICAgICAvLyBMaXN0IGFsbCBrZXlzIHRoYXQgZG8gbm90IHN0YXJ0IHdpdGggYF9gIG5vciBgbmdgXG4gICAgICAgICAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHRoaXMpLmZpbHRlcihrID0+ICEvXig/Ol98bmcpLy50ZXN0KGspKTtcblxuICAgICAgICAgICAgICAgIC8vIEdldCBhbGwgcHJvcGVydHkga2V5cyBmcm9tIHRoZSBjbGFzc1xuICAgICAgICAgICAgICAgIGNvbnN0IHByb3BLZXlzID0ga2V5cy5maWx0ZXIoayA9PiAhay5zdGFydHNXaXRoKFwib25cIikpO1xuICAgICAgICAgICAgICAgIC8vIEdldCBhbGwgZXZlbnQgaGFuZGxlciBrZXlzIGZyb20gdGhlIGNsYXNzXG4gICAgICAgICAgICAgICAgY29uc3QgZXZ0S2V5cyA9IGtleXMuZmlsdGVyKGsgPT4gay5zdGFydHNXaXRoKFwib25cIikpO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgcHJvcHMgPSB7fTtcbiAgICAgICAgICAgICAgICAvLyBQcm9qZWN0IGFsbCBrZXkgcHJvcGVydGllcyBvbnRvIGBwcm9wc2BcbiAgICAgICAgICAgICAgICBwcm9wS2V5cy5mb3JFYWNoKGsgPT4gcHJvcHNba10gPSB0aGlzW2tdKTtcblxuICAgICAgICAgICAgICAgIC8vIEF0dGVtcHQgdG8gZW5zdXJlIG5vIHpvbmUgaXMgbG9zdCBkdXJpbmcgdGhlIGV2ZW50IGVtaXR0ZXIgZmlyZXNcbiAgICAgICAgICAgICAgICB0aGlzLm5nWm9uZS5ydW5HdWFyZGVkKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQmluZCBhbGwgZXZlbnQgaGFuZGxlcnMuXG4gICAgICAgICAgICAgICAgICAgIC8vICEgaW1wb3J0YW50IEFuZ3VsYXIgdXNlcyBFdmVudEVtaXR0ZXIsIFJlYWN0IHVzZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gYSBkaWZmZXJlbnQgbWV0aG9kIG9mIGV2ZW50IGJpbmRpbmdcbiAgICAgICAgICAgICAgICAgICAgZXZ0S2V5cy5mb3JFYWNoKGsgPT4gcHJvcHNba10gPSAoLi4uYXJncykgPT4gdGhpc1trXS5uZXh0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICB9KVxuXG4gICAgICAgICAgICAgICAgdGhpcy5fcm9vdC5yZW5kZXIoUmVhY3QuY3JlYXRlRWxlbWVudCh0aGlzLm5nUmVhY3RDb21wb25lbnQsIHsgcHJvcHM6IHByb3BzIGFzIGFueSB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycilcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { createComponent, EventEmitter, Component } from '@angular/core';
|
|
3
|
+
import { createApplication } from '@angular/platform-browser';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { firstValueFrom } from 'rxjs';
|
|
6
|
+
import { createRoot } from 'react-dom/client';
|
|
7
|
+
|
|
8
|
+
// declare const Zone;
|
|
9
|
+
// const zone = Zone ? new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} }) : null;
|
|
10
|
+
/**
|
|
11
|
+
* Wrap an angular component inside of a React memo object.
|
|
12
|
+
* Will attempt to bind @Input and @Output properties if provided,
|
|
13
|
+
* and will bind the react arguments directly as @Input properties.
|
|
14
|
+
*
|
|
15
|
+
* @experimental
|
|
16
|
+
* @param componentClass Angular component
|
|
17
|
+
* @param envInjector An `EnvironmentInjector` instance to be used for the component
|
|
18
|
+
* @param injector An `ElementInjector` instance
|
|
19
|
+
* @param _inputs
|
|
20
|
+
* @param _outputs
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
23
|
+
const ReactifyReactComponent = ({ component, appRef, injector, ngZone, staticInputs, staticOutputs, preSiblings, postSiblings, additionalChildren, rootElementName, containerElementName }) => React.memo((args) => {
|
|
24
|
+
const id = Math.random().toString();
|
|
25
|
+
React.useEffect(() => {
|
|
26
|
+
try {
|
|
27
|
+
const componentInstance = createComponent(component, {
|
|
28
|
+
environmentInjector: appRef.injector,
|
|
29
|
+
elementInjector: injector,
|
|
30
|
+
hostElement: document.getElementById(id)
|
|
31
|
+
});
|
|
32
|
+
appRef.attachView(componentInstance.hostView);
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
// component.hostView = hostView;
|
|
35
|
+
Object.assign(staticInputs, args);
|
|
36
|
+
const { inputs, outputs } = component['ɵcmp'];
|
|
37
|
+
// Returns a list of entries that need to be set
|
|
38
|
+
// This makes it so that unnecessary setters are not invoked.
|
|
39
|
+
const updated = Object.entries(inputs).filter(([parentKey, childKey]) => {
|
|
40
|
+
return componentInstance.instance[childKey] != staticInputs[parentKey];
|
|
41
|
+
});
|
|
42
|
+
updated.forEach(([parentKey, childKey]) => {
|
|
43
|
+
if (staticInputs.hasOwnProperty(parentKey))
|
|
44
|
+
componentInstance.instance[childKey] = staticInputs[parentKey];
|
|
45
|
+
});
|
|
46
|
+
const outputSubscriptions = {};
|
|
47
|
+
// Get a list of unregistered outputs
|
|
48
|
+
const newOutputs = Object.entries(outputs).filter(([parentKey, childKey]) => {
|
|
49
|
+
return !outputSubscriptions[parentKey];
|
|
50
|
+
});
|
|
51
|
+
// Reverse bind via subscription
|
|
52
|
+
newOutputs.forEach(([parentKey, childKey]) => {
|
|
53
|
+
if (!staticOutputs.hasOwnProperty(parentKey))
|
|
54
|
+
return;
|
|
55
|
+
const target = componentInstance.instance[childKey];
|
|
56
|
+
const outputs = staticOutputs;
|
|
57
|
+
const sub = target.subscribe((...args) => {
|
|
58
|
+
// Run the callback in the provided zone
|
|
59
|
+
ngZone.run(() => {
|
|
60
|
+
outputs[parentKey](...args);
|
|
61
|
+
});
|
|
62
|
+
}); // Subscription
|
|
63
|
+
outputSubscriptions[parentKey] = sub;
|
|
64
|
+
});
|
|
65
|
+
// Wrap the destroy method to safely release the subscriptions
|
|
66
|
+
const originalDestroy = componentInstance.onDestroy?.bind(componentInstance);
|
|
67
|
+
componentInstance.onDestroy = (cb) => {
|
|
68
|
+
Object.values(outputSubscriptions).forEach(s => s.unsubscribe());
|
|
69
|
+
originalDestroy?.(cb);
|
|
70
|
+
};
|
|
71
|
+
componentInstance.changeDetectorRef.detectChanges();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(err);
|
|
75
|
+
}
|
|
76
|
+
}, []);
|
|
77
|
+
const elements = [
|
|
78
|
+
...(preSiblings || []),
|
|
79
|
+
React.createElement(containerElementName || "div", { id }),
|
|
80
|
+
...(postSiblings || []),
|
|
81
|
+
...(additionalChildren || [])
|
|
82
|
+
].filter(e => e);
|
|
83
|
+
return React.createElement(rootElementName || "div", {}, ...elements);
|
|
84
|
+
});
|
|
85
|
+
const ReactifyAngularComponent2 = (component, props) => {
|
|
86
|
+
const inputRef = React.useRef(null);
|
|
87
|
+
const ctx = this;
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
// Is there a better way to do this?
|
|
90
|
+
let subscriptions;
|
|
91
|
+
let app;
|
|
92
|
+
(async () => {
|
|
93
|
+
// Code to run when the component mounts
|
|
94
|
+
app = await createApplication({ providers: [] });
|
|
95
|
+
const base = app.bootstrap(component, inputRef.current);
|
|
96
|
+
const { instance } = base;
|
|
97
|
+
await firstValueFrom(app.isStable);
|
|
98
|
+
// App has now bootstrapped fully.
|
|
99
|
+
subscriptions = [];
|
|
100
|
+
Object.entries(instance).filter(([k, v]) => {
|
|
101
|
+
// @Outputs are always Event Emitters (I think)
|
|
102
|
+
if (v instanceof EventEmitter) {
|
|
103
|
+
subscriptions.push(instance[k]?.subscribe(evt => props[k].call(ctx, evt)));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
instance[k] = props[k];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
})();
|
|
110
|
+
return () => {
|
|
111
|
+
// Code to run when the component unmounts
|
|
112
|
+
subscriptions?.forEach(s => s?.unsubscribe());
|
|
113
|
+
app?.destroy();
|
|
114
|
+
};
|
|
115
|
+
}, []); // Empty dependency array ensures this effect runs only once on mount and cleanup on unmount
|
|
116
|
+
const obj = {};
|
|
117
|
+
return React.createElement("div");
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extend this component to automatically generate
|
|
122
|
+
* bindings to a React component.
|
|
123
|
+
*
|
|
124
|
+
* ! You _must_ override the property `ngReactComponent`
|
|
125
|
+
* Failure to do so will result in errors
|
|
126
|
+
* `override readonly ngReactComponent = ReactFlowWrappableComponent;`
|
|
127
|
+
*/
|
|
128
|
+
class ReactifyNgComponent {
|
|
129
|
+
constructor(ngContainer, ngZone) {
|
|
130
|
+
this.ngContainer = ngContainer;
|
|
131
|
+
this.ngZone = ngZone;
|
|
132
|
+
}
|
|
133
|
+
ngOnInit() {
|
|
134
|
+
if (!this.ngReactComponent) {
|
|
135
|
+
throw new Error("ReactMagicWrapperComponent cannot start without a provided ngReactComponent!");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
ngOnChanges(changes) {
|
|
139
|
+
this._render();
|
|
140
|
+
}
|
|
141
|
+
ngAfterViewInit() {
|
|
142
|
+
this._render();
|
|
143
|
+
}
|
|
144
|
+
ngOnDestroy() {
|
|
145
|
+
this._root?.unmount();
|
|
146
|
+
}
|
|
147
|
+
_render() {
|
|
148
|
+
if (!this.ngReactComponent) {
|
|
149
|
+
console.log("Render no component. May be context issue");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
;
|
|
153
|
+
this.ngZone.runOutsideAngular(() => {
|
|
154
|
+
try {
|
|
155
|
+
this._root ??= createRoot(this.ngContainer.element.nativeElement);
|
|
156
|
+
// List all keys that do not start with `_` nor `ng`
|
|
157
|
+
const keys = Object.keys(this).filter(k => !/^(?:_|ng)/.test(k));
|
|
158
|
+
// Get all property keys from the class
|
|
159
|
+
const propKeys = keys.filter(k => !k.startsWith("on"));
|
|
160
|
+
// Get all event handler keys from the class
|
|
161
|
+
const evtKeys = keys.filter(k => k.startsWith("on"));
|
|
162
|
+
const props = {};
|
|
163
|
+
// Project all key properties onto `props`
|
|
164
|
+
propKeys.forEach(k => props[k] = this[k]);
|
|
165
|
+
// Attempt to ensure no zone is lost during the event emitter fires
|
|
166
|
+
this.ngZone.runGuarded(() => {
|
|
167
|
+
// Bind all event handlers.
|
|
168
|
+
// ! important Angular uses EventEmitter, React uses
|
|
169
|
+
// a different method of event binding
|
|
170
|
+
evtKeys.forEach(k => props[k] = (...args) => this[k].next(args));
|
|
171
|
+
});
|
|
172
|
+
this._root.render(React.createElement(this.ngReactComponent, { props: props }));
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
console.error(err);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ReactifyNgComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
180
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: ReactifyNgComponent, isStandalone: true, selector: "app-react-magic-wrapper", usesOnChanges: true, ngImport: i0, template: ``, isInline: true }); }
|
|
181
|
+
}
|
|
182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ReactifyNgComponent, decorators: [{
|
|
183
|
+
type: Component,
|
|
184
|
+
args: [{
|
|
185
|
+
selector: 'app-react-magic-wrapper',
|
|
186
|
+
template: ``,
|
|
187
|
+
standalone: true
|
|
188
|
+
}]
|
|
189
|
+
}], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.NgZone }] });
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Generated bundle index. Do not edit.
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
export { ReactifyAngularComponent2, ReactifyNgComponent, ReactifyReactComponent };
|
|
196
|
+
//# sourceMappingURL=ngx-reactify.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-reactify.mjs","sources":["../../../src/util/angular-to-react.ts","../../../src/util/react-to-angular.ts","../../../src/ngx-reactify.ts"],"sourcesContent":["import { Type, ApplicationRef, Injector, NgZone, createComponent, EventEmitter } from '@angular/core';\nimport { createApplication } from '@angular/platform-browser';\nimport * as React from 'react';\nimport { firstValueFrom, Subscription } from 'rxjs';\n\n\n// declare const Zone;\n// const zone = Zone ? new Zone(Zone.current, { name: \"@dotglitch_menu\", properties: {} }) : null;\n\n/**\n * Wrap an angular component inside of a React memo object.\n * Will attempt to bind @Input and @Output properties if provided,\n * and will bind the react arguments directly as @Input properties.\n *\n * @experimental\n * @param componentClass Angular component\n * @param envInjector An `EnvironmentInjector` instance to be used for the component\n * @param injector An `ElementInjector` instance\n * @param _inputs\n * @param _outputs\n * @returns\n */\nexport const ReactifyReactComponent = ({\n component,\n appRef,\n injector,\n ngZone,\n staticInputs,\n staticOutputs,\n preSiblings,\n postSiblings,\n additionalChildren,\n rootElementName,\n containerElementName\n}: {\n component: Type<any>,\n appRef: Omit<ApplicationRef, '_runningTick'>,\n injector: Injector,\n ngZone: NgZone,\n staticInputs?: { [key: string]: any; },\n staticOutputs?: { [key: string]: Function; },\n preSiblings?: React.ReactNode[],\n postSiblings?: React.ReactNode[],\n additionalChildren?: React.ReactNode[],\n rootElementName?: Parameters<typeof React.createElement>[0],\n containerElementName?: string;\n}) => React.memo((args) => {\n\n const id = Math.random().toString();\n React.useEffect(() => {\n try {\n\n const componentInstance = createComponent(component, {\n environmentInjector: appRef.injector,\n elementInjector: injector,\n hostElement: document.getElementById(id)\n });\n\n appRef.attachView(componentInstance.hostView);\n // @ts-ignore\n // component.hostView = hostView;\n\n Object.assign(staticInputs, args);\n\n const { inputs, outputs } = component['ɵcmp'];\n\n // Returns a list of entries that need to be set\n // This makes it so that unnecessary setters are not invoked.\n const updated = Object.entries(inputs).filter(([parentKey, childKey]: [string, string]) => {\n return componentInstance.instance[childKey] != staticInputs[parentKey];\n });\n\n updated.forEach(([parentKey, childKey]: [string, string]) => {\n if (staticInputs.hasOwnProperty(parentKey))\n componentInstance.instance[childKey] = staticInputs[parentKey];\n });\n\n const outputSubscriptions: { [key: string]: Subscription; } = {};\n // Get a list of unregistered outputs\n const newOutputs = Object.entries(outputs).filter(([parentKey, childKey]: [string, string]) => {\n return !outputSubscriptions[parentKey];\n });\n\n // Reverse bind via subscription\n newOutputs.forEach(([parentKey, childKey]: [string, string]) => {\n if (!staticOutputs.hasOwnProperty(parentKey)) return;\n\n const target: EventEmitter<unknown> = componentInstance.instance[childKey];\n const outputs = staticOutputs;\n\n const sub = target.subscribe((...args) => {\n // Run the callback in the provided zone\n ngZone.run(() => {\n outputs[parentKey](...args);\n });\n }); // Subscription\n\n outputSubscriptions[parentKey] = sub;\n });\n\n // Wrap the destroy method to safely release the subscriptions\n const originalDestroy = componentInstance.onDestroy?.bind(componentInstance);\n componentInstance.onDestroy = (cb) => {\n Object.values(outputSubscriptions).forEach(s => s.unsubscribe());\n originalDestroy?.(cb);\n };\n\n componentInstance.changeDetectorRef.detectChanges();\n }\n catch (err) {\n console.error(err);\n }\n }, []);\n\n const elements = [\n ...(preSiblings || []),\n React.createElement(containerElementName || \"div\", { id }),\n ...(postSiblings || []),\n ...(additionalChildren || [])\n ].filter(e => e);\n\n return React.createElement(rootElementName || \"div\", {}, ...elements);\n});\n\n\nexport const ReactifyAngularComponent2 = (\n component: Type<any>,\n props: any\n) => {\n const inputRef = React.useRef(null);\n const ctx = this;\n\n React.useEffect(() => {\n // Is there a better way to do this?\n let subscriptions: Subscription[];\n let app: ApplicationRef;\n (async () => {\n // Code to run when the component mounts\n app = await createApplication({ providers: [] });\n const base = app.bootstrap(component, inputRef.current);\n const { instance } = base;\n\n await firstValueFrom(app.isStable);\n\n // App has now bootstrapped fully.\n subscriptions = [];\n Object.entries(instance).filter(([k, v]) => {\n // @Outputs are always Event Emitters (I think)\n if (v instanceof EventEmitter) {\n subscriptions.push(\n instance[k]?.subscribe(evt => props[k].call(ctx, evt))\n );\n }\n else {\n instance[k] = props[k];\n }\n })\n })()\n\n return () => {\n // Code to run when the component unmounts\n subscriptions?.forEach(s => s?.unsubscribe());\n app?.destroy();\n };\n }, []); // Empty dependency array ensures this effect runs only once on mount and cleanup on unmount\n\n const obj = {};\n\n return React.createElement(\"div\")\n}\n","import { AfterViewInit, ApplicationRef, Component, ComponentFactoryResolver, EnvironmentInjector, EventEmitter, Injector, NgZone, OnChanges, OnDestroy, SimpleChanges, Type, ViewContainerRef, ViewRef, createComponent } from '@angular/core';\nimport * as React from 'react';\nimport { createRoot, Root } from 'react-dom/client';\n\n\n/**\n * Extend this component to automatically generate\n * bindings to a React component.\n *\n * ! You _must_ override the property `ngReactComponent`\n * Failure to do so will result in errors\n * `override readonly ngReactComponent = ReactFlowWrappableComponent;`\n */\n@Component({\n selector: 'app-react-magic-wrapper',\n template: ``,\n standalone: true\n})\nexport class ReactifyNgComponent implements OnChanges, OnDestroy, AfterViewInit {\n\n /**\n * The react component to be wrapped.\n * ! Must be overridden for this wrapper to work\n */\n ngReactComponent: React.FunctionComponent<any> | React.ComponentClass<any>;\n\n private _root: Root;\n public theme: string;\n\n constructor(\n private readonly ngContainer: ViewContainerRef,\n private readonly ngZone: NgZone\n ) {\n }\n\n ngOnInit() {\n if (!this.ngReactComponent) {\n throw new Error(\"ReactMagicWrapperComponent cannot start without a provided ngReactComponent!\");\n }\n }\n\n ngOnChanges(changes?: SimpleChanges): void {\n this._render();\n }\n\n ngAfterViewInit() {\n this._render();\n }\n\n ngOnDestroy() {\n this._root?.unmount();\n }\n\n private _render() {\n if (!this.ngReactComponent) {\n console.log(\"Render no component. May be context issue\")\n return\n };\n\n this.ngZone.runOutsideAngular(() => {\n try {\n this._root ??= createRoot(this.ngContainer.element.nativeElement);\n\n // List all keys that do not start with `_` nor `ng`\n const keys = Object.keys(this).filter(k => !/^(?:_|ng)/.test(k));\n\n // Get all property keys from the class\n const propKeys = keys.filter(k => !k.startsWith(\"on\"));\n // Get all event handler keys from the class\n const evtKeys = keys.filter(k => k.startsWith(\"on\"));\n\n const props = {};\n // Project all key properties onto `props`\n propKeys.forEach(k => props[k] = this[k]);\n\n // Attempt to ensure no zone is lost during the event emitter fires\n this.ngZone.runGuarded(() => {\n // Bind all event handlers.\n // ! important Angular uses EventEmitter, React uses\n // a different method of event binding\n evtKeys.forEach(k => props[k] = (...args) => this[k].next(args));\n })\n\n this._root.render(React.createElement(this.ngReactComponent, { props: props as any }));\n }\n catch(err) {\n console.error(err)\n }\n })\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["this"],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-reactify.d.ts","sourceRoot":"","sources":["../../src/ngx-reactify.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,cAAc,cAAc,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ngx-reactify",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"url": "https://github.com/knackstedt/ngx-reactify"
|
|
6
|
+
},
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": {
|
|
9
|
+
"email": "andrewk@vivaldi.net",
|
|
10
|
+
"name": "Andrew G. Knackstedt"
|
|
11
|
+
},
|
|
12
|
+
"private": false,
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"@angular/common": ">=17.0.0",
|
|
15
|
+
"@angular/core": ">=17.0.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"react": ">=18.0.0",
|
|
19
|
+
"react-dom": ">=18.0.0",
|
|
20
|
+
"tslib": ">=2.6.0"
|
|
21
|
+
},
|
|
22
|
+
"module": "fesm2022/ngx-reactify.mjs",
|
|
23
|
+
"typings": "index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
"./package.json": {
|
|
26
|
+
"default": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./index.d.ts",
|
|
30
|
+
"esm2022": "./esm2022/ngx-reactify.mjs",
|
|
31
|
+
"esm": "./esm2022/ngx-reactify.mjs",
|
|
32
|
+
"default": "./fesm2022/ngx-reactify.mjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"sideEffects": false
|
|
36
|
+
}
|
package/public-api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../../src/public-api.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Type, ApplicationRef, Injector, NgZone } from '@angular/core';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Wrap an angular component inside of a React memo object.
|
|
5
|
+
* Will attempt to bind @Input and @Output properties if provided,
|
|
6
|
+
* and will bind the react arguments directly as @Input properties.
|
|
7
|
+
*
|
|
8
|
+
* @experimental
|
|
9
|
+
* @param componentClass Angular component
|
|
10
|
+
* @param envInjector An `EnvironmentInjector` instance to be used for the component
|
|
11
|
+
* @param injector An `ElementInjector` instance
|
|
12
|
+
* @param _inputs
|
|
13
|
+
* @param _outputs
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
export declare const ReactifyReactComponent: ({ component, appRef, injector, ngZone, staticInputs, staticOutputs, preSiblings, postSiblings, additionalChildren, rootElementName, containerElementName }: {
|
|
17
|
+
component: Type<any>;
|
|
18
|
+
appRef: Omit<ApplicationRef, '_runningTick'>;
|
|
19
|
+
injector: Injector;
|
|
20
|
+
ngZone: NgZone;
|
|
21
|
+
staticInputs?: {
|
|
22
|
+
[key: string]: any;
|
|
23
|
+
};
|
|
24
|
+
staticOutputs?: {
|
|
25
|
+
[key: string]: Function;
|
|
26
|
+
};
|
|
27
|
+
preSiblings?: React.ReactNode[];
|
|
28
|
+
postSiblings?: React.ReactNode[];
|
|
29
|
+
additionalChildren?: React.ReactNode[];
|
|
30
|
+
rootElementName?: Parameters<typeof React.createElement>[0];
|
|
31
|
+
containerElementName?: string;
|
|
32
|
+
}) => React.NamedExoticComponent<object>;
|
|
33
|
+
export declare const ReactifyAngularComponent2: (component: Type<any>, props: any) => React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
34
|
+
//# sourceMappingURL=angular-to-react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular-to-react.d.ts","sourceRoot":"","sources":["../../../src/util/angular-to-react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAiC,MAAM,eAAe,CAAC;AAEtG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB;eAapB,KAAK,GAAG,CAAC;YACZ,KAAK,cAAc,EAAE,cAAc,CAAC;cAClC,QAAQ;YACV,MAAM;;;;;;;kBAGA,MAAM,SAAS,EAAE;mBAChB,MAAM,SAAS,EAAE;yBACX,MAAM,SAAS,EAAE;sBACpB,WAAW,OAAO,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC;2BACpC,MAAM;wCA6E/B,CAAC;AAGH,eAAO,MAAM,yBAAyB,cACvB,KAAK,GAAG,CAAC,SACb,GAAG,mFA0Cb,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AfterViewInit, NgZone, OnChanges, OnDestroy, SimpleChanges, ViewContainerRef } from '@angular/core';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Extend this component to automatically generate
|
|
6
|
+
* bindings to a React component.
|
|
7
|
+
*
|
|
8
|
+
* ! You _must_ override the property `ngReactComponent`
|
|
9
|
+
* Failure to do so will result in errors
|
|
10
|
+
* `override readonly ngReactComponent = ReactFlowWrappableComponent;`
|
|
11
|
+
*/
|
|
12
|
+
export declare class ReactifyNgComponent implements OnChanges, OnDestroy, AfterViewInit {
|
|
13
|
+
private readonly ngContainer;
|
|
14
|
+
private readonly ngZone;
|
|
15
|
+
/**
|
|
16
|
+
* The react component to be wrapped.
|
|
17
|
+
* ! Must be overridden for this wrapper to work
|
|
18
|
+
*/
|
|
19
|
+
ngReactComponent: React.FunctionComponent<any> | React.ComponentClass<any>;
|
|
20
|
+
private _root;
|
|
21
|
+
theme: string;
|
|
22
|
+
constructor(ngContainer: ViewContainerRef, ngZone: NgZone);
|
|
23
|
+
ngOnInit(): void;
|
|
24
|
+
ngOnChanges(changes?: SimpleChanges): void;
|
|
25
|
+
ngAfterViewInit(): void;
|
|
26
|
+
ngOnDestroy(): void;
|
|
27
|
+
private _render;
|
|
28
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ReactifyNgComponent, never>;
|
|
29
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ReactifyNgComponent, "app-react-magic-wrapper", never, {}, {}, never, never, true, never>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=react-to-angular.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-to-angular.d.ts","sourceRoot":"","sources":["../../../src/util/react-to-angular.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoG,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAQ,gBAAgB,EAA4B,MAAM,eAAe,CAAC;AAC/O,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;;AAI/B;;;;;;;GAOG;AACH,qBAKa,mBAAoB,YAAW,SAAS,EAAE,SAAS,EAAE,aAAa;IAYvE,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAX3B;;;OAGG;IACH,gBAAgB,EAAE,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAE3E,OAAO,CAAC,KAAK,CAAO;IACb,KAAK,EAAE,MAAM,CAAC;gBAGA,WAAW,EAAE,gBAAgB,EAC7B,MAAM,EAAE,MAAM;IAInC,QAAQ;IAMR,WAAW,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;IAI1C,eAAe;IAIf,WAAW;IAIX,OAAO,CAAC,OAAO;yCAnCN,mBAAmB;2CAAnB,mBAAmB;CAwE/B"}
|