diff --git a/packages/render-html/src/RenderHTMLConfigProvider.tsx b/packages/render-html/src/RenderHTMLConfigProvider.tsx index 7d2e53b10..97bfde1d4 100644 --- a/packages/render-html/src/RenderHTMLConfigProvider.tsx +++ b/packages/render-html/src/RenderHTMLConfigProvider.tsx @@ -26,6 +26,7 @@ export const renderHTMLConfigPropTypes: RenderHTMLConfigPropTypes = { bypassAnonymousTPhrasingNodes: PropTypes.bool, defaultTextProps: PropTypes.object, defaultViewProps: PropTypes.object, + enableExperimentalGhostLinesPrevention: PropTypes.bool, enableExperimentalMarginCollapsing: PropTypes.bool, remoteErrorView: PropTypes.func, remoteLoadingView: PropTypes.func, diff --git a/packages/render-html/src/TTextRenderer.ts b/packages/render-html/src/TTextRenderer.ts index 27c3508c2..b222b2ca4 100644 --- a/packages/render-html/src/TTextRenderer.ts +++ b/packages/render-html/src/TTextRenderer.ts @@ -29,7 +29,16 @@ function TStandardTextRenderer(props: TNodeSubRendererProps) { export default function TTextRenderer(props: TNodeSubRendererProps) { const InternalTextRenderer = useInternalTextRenderer(props.tnode); if (InternalTextRenderer) { - return React.createElement(InternalTextRenderer); + return React.createElement(InternalTextRenderer, props); + } + // If ghost line prevention is enabled and the text data is empty, render + // nothing to avoid React Native painting a 20px height line. + // See also https://git.io/JErwX + if ( + props.tnode.data === '' && + props.sharedProps.enableExperimentalGhostLinesPrevention + ) { + return null; } return React.createElement(TStandardTextRenderer, props); } diff --git a/packages/render-html/src/context/defaultSharedProps.ts b/packages/render-html/src/context/defaultSharedProps.ts index f9a30118c..ef8f2deb0 100644 --- a/packages/render-html/src/context/defaultSharedProps.ts +++ b/packages/render-html/src/context/defaultSharedProps.ts @@ -20,6 +20,7 @@ const defaultSharedProps: Required = { allowFontScaling: true }, defaultViewProps: {}, + enableExperimentalGhostLinesPrevention: false, enableExperimentalMarginCollapsing: false, computeEmbeddedMaxWidth: (contentWidth) => contentWidth, provideEmbeddedHeaders: () => null, diff --git a/packages/render-html/src/render/render-types.tsx b/packages/render-html/src/render/render-types.tsx index 8ef29f085..294f0532b 100644 --- a/packages/render-html/src/render/render-types.tsx +++ b/packages/render-html/src/render/render-types.tsx @@ -1,13 +1,14 @@ import { TBlock, TPhrasing, TText } from '@native-html/transient-render-engine'; import { ComponentType } from 'react'; +import { TNodeSubRendererProps } from '../internal-types'; import { CustomRenderer, InternalRenderer } from '../shared-types'; /** * Special internal renderers for non-printable text (wbr, br). */ -export type InternalTextContentRenderer = ComponentType<{ - key?: string | number; -}> & { +export type InternalTextContentRenderer = ComponentType< + TNodeSubRendererProps +> & { isNativeInternalTextRenderer: true; }; diff --git a/packages/render-html/src/shared-types.ts b/packages/render-html/src/shared-types.ts index ecf278ef6..107db63fc 100644 --- a/packages/render-html/src/shared-types.ts +++ b/packages/render-html/src/shared-types.ts @@ -363,6 +363,26 @@ export interface RenderHTMLSharedProps { */ defaultWebViewProps?: any; + /** + * React Native doesn't handle lines like we would expect on a web browser. + * For example: + * ```jsx + * + * + * + * ``` + * will span 20 dpi in height. Setting this prop to `true` will make + * the renderer take those React Native oddities into account. + * See also this ticket: https://git.io/JErwX + * + * @remarks It might not work when `bypassAnonymousTPhrasingNodes` is set to + * `false`. Also note that this is an experimental feature, thus subject to + * behavioral instability. + * + * @defaultValue false + */ + enableExperimentalGhostLinesPrevention?: boolean; + /** * Enable or disable margin collapsing CSS behavior (experimental!). * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing | MDN docs}. @@ -374,6 +394,8 @@ export interface RenderHTMLSharedProps { * flex), which is not standard. * - Might not work well with {@link TPhrasing} nodes having only one child. * + * This is an experimental feature, thus subject to behavioral instability. + * * @defaultValue false */ enableExperimentalMarginCollapsing?: boolean;