public/react/react2angular.tsx (28 lines of code) (raw):
// Originally taken from https://github.com/coatue-oss/react2angular
// We have copied this into the project directly rather than as a
// dependency in order to support our migration to React 18
import { IAugmentedJQuery, IComponentOptions } from 'angular'
import NgComponent from 'ngcomponent'
import * as React from 'react'
import { render, unmountComponentAtNode } from 'react-dom'
/**
* Wraps a React component in Angular. Returns a new Angular component.
*
* Usage:
*
* ```ts
* type Props = { foo: number }
* class ReactComponent extends React.Component<Props, S> {}
* const AngularComponent = react2angular(ReactComponent, ['foo'])
* ```
*/
export function react2angular<Props extends Map<string, any>>(
Class: React.ComponentType<Props>,
bindingNames: (keyof Props)[],
injectNames: string[] = []
): IComponentOptions {
return {
bindings: Object.fromEntries(bindingNames.map(_ => [_, "<"])),
controller: ['$element', ...injectNames, class extends NgComponent<Props> {
static get $$ngIsClass() {
return true
}
isDestroyed = false
injectedProps: { [name: string]: any }
constructor(private $element: IAugmentedJQuery, ...injectedProps: any[]) {
super()
this.injectedProps = {}
injectNames.forEach((name, i) => {
this.injectedProps[name] = injectedProps[i]
})
}
render() {
if (!this.isDestroyed) {
render(
<Class {...this.props} {...this.injectedProps as any} />,
this.$element[0]
)
}
}
componentWillUnmount() {
this.isDestroyed = true
unmountComponentAtNode(this.$element[0])
}
}]
}
}