11import React , { memo , ReactElement } from 'react' ;
2- import TBlockRenderer from './TBlockRenderer' ;
3- import TPhrasingRenderer from './TPhrasingRenderer' ;
4- import TTextRenderer from './TTextRenderer' ;
5- import { TNodeRendererProps } from './shared-types' ;
2+ import { TDefaultRenderer , TNodeRendererProps } from './shared-types' ;
63import { useSharedProps } from './context/SharedPropsProvider' ;
4+ import {
5+ TText ,
6+ TBlock ,
7+ TNode ,
8+ TPhrasing
9+ } from '@native-html/transient-render-engine' ;
10+ import useAssembledCommonProps from './hooks/useAssembledCommonProps' ;
11+ import { useTNodeChildrenRenderer } from './context/TChildrenRendererContext' ;
12+ import renderTextualContent from './renderTextualContent' ;
13+ import { useRendererRegistry } from './context/RenderRegistryProvider' ;
14+ import renderBlockContent from './renderBlockContent' ;
15+ import renderEmptyContent from './renderEmptyContent' ;
716
817export type { TNodeRendererProps } from './shared-types' ;
918
19+ const TDefaultBlockRenderer : TDefaultRenderer < TBlock > =
20+ renderBlockContent . bind ( null ) ;
21+
22+ TDefaultBlockRenderer . displayName = 'TDefaultBlockRenderer' ;
23+
24+ const TDefaultPhrasingRenderer : TDefaultRenderer < TPhrasing > =
25+ renderTextualContent . bind ( null ) ;
26+
27+ TDefaultPhrasingRenderer . displayName = 'TDefaultPhrasingRenderer' ;
28+
29+ const TDefaultTextRenderer : TDefaultRenderer < TText > =
30+ renderTextualContent . bind ( null ) ;
31+
32+ TDefaultTextRenderer . displayName = 'TDefaultTextRenderer' ;
33+
34+ function isGhostTNode ( tnode : TNode ) {
35+ return (
36+ ( tnode . type === 'text' && ( tnode . data === '' || tnode . data === ' ' ) ) ||
37+ tnode . type === 'empty'
38+ ) ;
39+ }
40+
1041/**
1142 * A component to render any {@link TNode}.
1243 */
@@ -15,33 +46,78 @@ const TNodeRenderer = memo(function MemoizedTNodeRenderer(
1546) : ReactElement | null {
1647 const { tnode } = props ;
1748 const sharedProps = useSharedProps ( ) ;
49+ const renderRegistry = useRendererRegistry ( ) ;
50+ const TNodeChildrenRenderer = useTNodeChildrenRenderer ( ) ;
1851 const tnodeProps = {
1952 ...props ,
53+ TNodeChildrenRenderer,
2054 sharedProps
2155 } ;
22- if ( tnode . type === 'block' || tnode . type === 'document' ) {
23- return React . createElement ( TBlockRenderer , tnodeProps ) ;
24- }
25- if ( tnode . type === 'phrasing' ) {
26- return React . createElement ( TPhrasingRenderer , tnodeProps ) ;
27- }
28- if ( tnode . type === 'text' ) {
29- return React . createElement ( TTextRenderer , tnodeProps ) ;
30- }
31- if ( typeof __DEV__ === 'boolean' && __DEV__ && tnode . type === 'empty' ) {
32- if ( tnode . isUnregistered ) {
33- console . warn (
34- `There is no custom renderer registered for tag " ${ tnode . tagName } " which is not part of the HTML5 standard. The tag will not be rendered.` +
35- ' If you don\'t want this tag to be rendered, add it to "ignoredTags" prop array. If you do, register an HTMLElementModel for this tag with "customHTMLElementModels" prop.'
36- ) ;
37- } else if ( tnode . tagName !== 'head' ) {
38- console . warn (
39- `The " ${ tnode . tagName } " tag is a valid HTML element but is not handled by this library. You must extend the default HTMLElementModel for this tag with "customHTMLElementModels" prop and make sure its content model is not set to "none".` +
40- ' If you don\'t want this tag to be rendered, add it to "ignoredTags" prop array.'
56+ const renderer =
57+ tnode . type === 'block' || tnode . type === 'document'
58+ ? TDefaultBlockRenderer
59+ : tnode . type === 'text'
60+ ? TDefaultTextRenderer
61+ : tnode . type === 'phrasing'
62+ ? TDefaultPhrasingRenderer
63+ : renderEmptyContent ;
64+
65+ const { assembledProps , Renderer } = useAssembledCommonProps (
66+ tnodeProps ,
67+ renderer as any
68+ ) ;
69+ switch ( tnode . type ) {
70+ case 'empty' :
71+ return renderEmptyContent ( assembledProps ) ;
72+ case 'text' :
73+ const InternalTextRenderer = renderRegistry . getInternalTextRenderer (
74+ props . tnode . tagName
4175 ) ;
42- }
76+
77+ if ( InternalTextRenderer ) {
78+ return React . createElement ( InternalTextRenderer , tnodeProps ) ;
79+ }
80+ // If ghost line prevention is enabled and the text data is empty, render
81+ // nothing to avoid React Native painting a 20px height line.
82+ // See also https://git.io/JErwX
83+ if (
84+ tnodeProps . tnode . data === '' &&
85+ tnodeProps . sharedProps . enableExperimentalGhostLinesPrevention
86+ ) {
87+ return null ;
88+ }
89+ break ;
90+ case 'phrasing' :
91+ // When a TPhrasing node is anonymous and has only one child, its
92+ // rendering amounts to rendering its only child.
93+ if (
94+ tnodeProps . sharedProps . bypassAnonymousTPhrasingNodes &&
95+ tnodeProps . tnode . tagName == null &&
96+ tnodeProps . tnode . children . length <= 1
97+ ) {
98+ return React . createElement ( TNodeChildrenRenderer , {
99+ tnode : props . tnode
100+ } ) ;
101+ }
102+ // If ghost line prevention is enabled and the tnode is an anonymous empty
103+ // phrasing node, render nothing to avoid React Native painting a 20px
104+ // height line. See also https://git.io/JErwX
105+ if (
106+ tnodeProps . sharedProps . enableExperimentalGhostLinesPrevention &&
107+ tnodeProps . tnode . tagName == null &&
108+ tnodeProps . tnode . children . every ( isGhostTNode )
109+ ) {
110+ return null ;
111+ }
112+ break ;
43113 }
44- return null ;
114+ const renderFn =
115+ tnode . type === 'block' || tnode . type === 'document'
116+ ? renderBlockContent
117+ : renderTextualContent ;
118+ return Renderer === null
119+ ? renderFn ( assembledProps )
120+ : React . createElement ( Renderer as any , assembledProps ) ;
45121} ) ;
46122
47123const defaultProps : Required < Pick < TNodeRendererProps < any > , 'propsFromParent' > > =
@@ -54,4 +130,10 @@ const defaultProps: Required<Pick<TNodeRendererProps<any>, 'propsFromParent'>> =
54130// @ts -expect-error default props must be defined
55131TNodeRenderer . defaultProps = defaultProps ;
56132
133+ export {
134+ TDefaultBlockRenderer ,
135+ TDefaultPhrasingRenderer ,
136+ TDefaultTextRenderer
137+ } ;
138+
57139export default TNodeRenderer ;
0 commit comments