1
- const NO_RENDER = { render : false } ;
1
+
2
+ const SHALLOW = { shallow : true } ;
2
3
3
4
const ESC = {
4
5
'<' : '<' ,
@@ -9,10 +10,45 @@ const ESC = {
9
10
10
11
const HOP = Object . prototype . hasOwnProperty ;
11
12
12
- let escape = s => String ( s ) . replace ( / [ < > " & ] / , a => ESC [ a ] || a ) ;
13
+ let escape = s => String ( s ) . replace ( / [ < > " & ] / , escapeChar ) ;
14
+
15
+ let escapeChar = a => ESC [ a ] || a ;
16
+
17
+
18
+ /** Render Preact JSX + Components to an HTML string.
19
+ * @name render
20
+ * @function
21
+ * @param {VNode } vnode JSX VNode to render.
22
+ * @param {Object } [options={}] Rendering options
23
+ * @param {Boolean } [options.shallow=false] If `true`, renders nested Components as HTML elements (`<Foo a="b" />`).
24
+ * @param {Boolean } [options.xml=false] If `true`, uses self-closing tags for elements without children.
25
+ * @param {Object } [context={}] Optionally pass an initial context object through the render path.
26
+ */
27
+ renderToString . render = renderToString ;
28
+
29
+
30
+ /** Only render elements, leaving Components inline as `<ComponentName ... />`.
31
+ * This method is just a convenience alias for `render(vnode, context, { shallow:true })`
32
+ * @name shallow
33
+ * @function
34
+ * @param {VNode } vnode JSX VNode to render.
35
+ * @param {Object } [context={}] Optionally pass an initial context object through the render path.
36
+ */
37
+ renderToString . shallowRender = ( vnode , context ) => renderToString ( vnode , context , SHALLOW ) ;
13
38
14
- export default function renderToString ( vnode ) {
39
+
40
+ /** You can actually skip preact entirely and import this empty Component base class (or not use a base class at all).
41
+ * preact-render-to-string doesn't use any of Preact's functionality to do its job.
42
+ * @name Component
43
+ * @class
44
+ */
45
+ // renderToString.Component = function Component(){};
46
+
47
+
48
+ /** The default export is an alias of `render()`. */
49
+ export default function renderToString ( vnode , context , opts , inner ) {
15
50
let { nodeName, attributes, children } = vnode || EMPTY ;
51
+ context = context || { } ;
16
52
17
53
// #text nodes
18
54
if ( ! nodeName ) {
@@ -21,40 +57,70 @@ export default function renderToString(vnode) {
21
57
22
58
// components
23
59
if ( typeof nodeName === 'function' ) {
24
- let props = { children, ...attributes } ,
25
- rendered ;
26
-
27
- if ( typeof nodeName . prototype . render !== 'function' ) {
28
- // stateless functional components
29
- rendered = nodeName ( props ) ;
60
+ if ( opts && opts . shallow && inner ) {
61
+ nodeName = nodeName . prototype . displayName || nodeName . name ;
30
62
}
31
63
else {
32
- // class-based components
33
- let c = new nodeName ( ) ;
34
- c . setProps ( props , NO_RENDER ) ;
35
- rendered = c . render ( c . props = props , c . state ) ;
64
+ let props = { children, ...attributes } ,
65
+ rendered ;
66
+
67
+ if ( typeof nodeName . prototype . render !== 'function' ) {
68
+ // stateless functional components
69
+ rendered = nodeName ( props , context ) ;
70
+ }
71
+ else {
72
+ // class-based components
73
+ let c = new nodeName ( props , context ) ;
74
+ c . props = props ;
75
+ c . context = context ;
76
+ rendered = c . render ( c . props , c . state , c . context ) ;
77
+
78
+ if ( c . getChildContext ) {
79
+ context = c . getChildContext ( ) ;
80
+ }
81
+ }
82
+
83
+ return renderToString ( rendered , context , opts , true ) ;
36
84
}
37
- return renderToString ( rendered ) ;
38
85
}
39
86
40
87
// render JSX to HTML
41
- let s = `<${ nodeName } ` ;
88
+ let s = `<${ nodeName } ` ,
89
+ html ;
90
+
42
91
for ( let name in attributes ) {
43
92
if ( HOP . call ( attributes , name ) ) {
44
- let v = attributes [ name ] ;
93
+ let v = attributes [ name ] ,
94
+ type = typeof v ;
45
95
if ( name === 'className' ) {
46
96
if ( attributes [ 'class' ] ) continue ;
47
97
name = 'class' ;
48
98
}
49
- if ( v !== null && v !== undefined ) {
99
+ if ( name === 'dangerouslySetInnerHTML' ) {
100
+ html = v && v . __html ;
101
+ }
102
+ else if ( v !== null && v !== undefined && type !== 'function' ) {
50
103
s += ` ${ name } ="${ escape ( v ) } "` ;
51
104
}
52
105
}
53
106
}
54
107
s += '>' ;
55
- if ( children && children . length ) {
56
- s += children . map ( renderToString ) . join ( '' ) ;
108
+
109
+ if ( html ) {
110
+ s += html ;
57
111
}
112
+ else {
113
+ let len = children && children . length ;
114
+ if ( len ) {
115
+ for ( let i = 0 ; i < len ; i ++ ) {
116
+ s += renderToString ( children [ i ] , context , opts , true ) ;
117
+ }
118
+ }
119
+ else if ( opts && opts . xml ) {
120
+ return s . substring ( 0 , s . length - 1 ) + ' />' ;
121
+ }
122
+ }
123
+
58
124
s += `</${ nodeName } >`
59
125
return s ;
60
126
} ;
0 commit comments