Skip to content

Commit fe7be8a

Browse files
committed
feat: add support for children transclude
Fixes coatue-oss#12
1 parent 791681b commit fe7be8a

9 files changed

+875
-1563
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ node_modules
33
*.d.ts
44
*.js
55
*.map
6-
!karma.conf.js
6+
!karma.conf.js
7+
!html-react-parser.d.ts

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
8.1.2

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ If `propTypes` are defined and you passed in a 2nd argument, the argument will o
5555
></my-component>
5656
```
5757

58+
You can also transclude HTML content which will be rendered as children of the React component.
59+
60+
```html
61+
<my-component
62+
foo="3"
63+
baz="'baz'">
64+
<span>This is transcluded</span>
65+
<p>And this!</p>
66+
<my-other-component
67+
bar="'bar'">
68+
</my-other-component>
69+
</my-component>
70+
```
71+
5872
## Tests
5973

6074
```sh

html-react-parser.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module 'html-react-parser'

index.tsx

+47-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1-
import { IAugmentedJQuery, IComponentOptions } from 'angular'
1+
import {
2+
IAugmentedJQuery,
3+
ICompileService,
4+
IComponentOptions,
5+
IScope,
6+
ITranscludeFunction
7+
} from 'angular'
28
import fromPairs = require('lodash.frompairs')
9+
import HTMLtoJSX = require('htmltojsx')
10+
import Parser = require('html-react-parser')
311
import NgComponent from 'ngcomponent'
412
import * as React from 'react'
513
import { render, unmountComponentAtNode } from 'react-dom'
614

15+
const converter = new HTMLtoJSX({
16+
createClass: false
17+
})
18+
719
/**
820
* Wraps a React component in Angular. Returns a new Angular component.
921
*
@@ -25,17 +37,47 @@ export function react2angular<Props>(
2537

2638
return {
2739
bindings: fromPairs(names.map(_ => [_, '<'])),
28-
controller: ['$element', class extends NgComponent<Props, void> {
29-
constructor(private $element: IAugmentedJQuery) {
40+
controller: ['$element', '$transclude', '$compile', class extends NgComponent<Props, void> {
41+
private transcludedContent: JQuery
42+
private transclusionScope: IScope
43+
44+
constructor(private $element: IAugmentedJQuery, private $transclude: ITranscludeFunction, private $compile: ICompileService) {
3045
super()
3146
}
47+
3248
render() {
49+
let children
50+
this.$transclude((clone: JQuery, scope: IScope) => {
51+
children = Array.prototype.slice.call(clone).map((element: HTMLElement) => {
52+
this.$compile(element)(scope)
53+
const phase = scope.$root.$$phase
54+
if (phase !== '$apply' && phase !== '$digest') {
55+
scope.$apply()
56+
}
57+
return converter.convert(element.outerHTML)
58+
})
59+
this.transcludedContent = clone
60+
this.transclusionScope = scope
61+
})
3362
// TODO: rm any when https://github.com/Microsoft/TypeScript/pull/13288 is merged
34-
render(<Class {...(this.props as any)} />, this.$element[0])
63+
render(
64+
<Class {...(this.props as any)}>
65+
{Parser(children && (children as string[]).join(''))}
66+
</Class>,
67+
this.$element[0]
68+
)
3569
}
70+
3671
componentWillUnmount() {
3772
unmountComponentAtNode(this.$element[0])
3873
}
39-
}]
74+
75+
$onDestroy() {
76+
super.$onDestroy()
77+
this.transcludedContent.remove()
78+
this.transclusionScope.$destroy()
79+
}
80+
}],
81+
transclude: true
4082
}
4183
}

0 commit comments

Comments
 (0)