diff --git a/packages/render-html/src/RenderHTML.tsx b/packages/render-html/src/RenderHTML.tsx
index beffc370c..41c95818b 100644
--- a/packages/render-html/src/RenderHTML.tsx
+++ b/packages/render-html/src/RenderHTML.tsx
@@ -1,202 +1,25 @@
-import React, { useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { Dimensions, Platform } from 'react-native';
-import { RenderResolvedHTMLProps, RenderHTMLProps } from './shared-types';
-import useTTree from './hooks/useTTree';
-import SharedPropsContext, {
- defaultSharedPropsContext
-} from './context/SharedPropsContext';
-import TChildrenRenderersContext from './context/TChildrenRendererContext';
-import TNodeChildrenRenderer from './TNodeChildrenRenderer';
-import RenderHTMLDebug from './RenderHTMLDebug';
-import SourceLoader from './SourceLoader';
-import RenderRegistryProvider from './context/RenderRegistryProvider';
-import TChildrenRenderer from './TChildrenRenderer';
-import TDocumentRenderer from './TDocumentRenderer';
+import React from 'react';
-export type RenderHTMLPropTypes = Record;
+import { RenderHTMLProps } from './shared-types';
-const propTypes: RenderHTMLPropTypes = {
- renderers: PropTypes.object.isRequired,
- defaultTextProps: PropTypes.object,
- defaultViewProps: PropTypes.object,
- source: PropTypes.oneOfType([
- PropTypes.shape({
- html: PropTypes.string.isRequired,
- baseUrl: PropTypes.string
- }),
- PropTypes.shape({
- uri: PropTypes.string.isRequired,
- method: PropTypes.string,
- body: PropTypes.any,
- headers: PropTypes.object
- })
- ]),
- enableCSSInlineProcessing: PropTypes.bool,
- enableUserAgentStyles: PropTypes.bool,
- enableExperimentalMarginCollapsing: PropTypes.bool,
- idsStyles: PropTypes.object,
- remoteErrorView: PropTypes.func,
- remoteLoadingView: PropTypes.func,
- ignoredTags: PropTypes.array.isRequired,
- ignoredStyles: PropTypes.array.isRequired,
- allowedStyles: PropTypes.array,
- htmlParserOptions: PropTypes.object,
- debug: PropTypes.bool.isRequired,
- listsPrefixesRenderers: PropTypes.object,
- ignoreDOMNode: PropTypes.func,
- alterDOMData: PropTypes.func,
- alterDOMChildren: PropTypes.func,
- alterDOMElement: PropTypes.func,
- tagsStyles: PropTypes.object,
- classesStyles: PropTypes.object,
- onLinkPress: PropTypes.func,
- computeEmbeddedMaxWidth: PropTypes.func,
- contentWidth: PropTypes.number,
- enableExperimentalPercentWidth: PropTypes.bool,
- imagesInitialDimensions: PropTypes.shape({
- width: PropTypes.number,
- height: PropTypes.number
- }),
- emSize: PropTypes.number.isRequired,
- baseStyle: PropTypes.object,
- renderersProps: PropTypes.object,
- onTTreeChange: PropTypes.func,
- onHTMLLoaded: PropTypes.func,
- systemFonts: PropTypes.arrayOf(PropTypes.string),
- fallbackFonts: PropTypes.shape({
- serif: PropTypes.string,
- 'sans-serif': PropTypes.string,
- monospace: PropTypes.string
- }),
- triggerTREInvalidationPropNames: PropTypes.arrayOf(PropTypes.string),
- WebView: PropTypes.any,
- defaultWebViewProps: PropTypes.object,
- onDocumentMetadataLoaded: PropTypes.func
-};
+import TRenderEngineProvider from './TRenderEngineProvider';
+import RenderHTMLFragment from './RenderHTMLFragment';
-const defaultProps: {
- [k in keyof RenderHTMLProps]?: RenderHTMLProps[k];
-} = {
- ...defaultSharedPropsContext,
- htmlParserOptions: {
- decodeEntities: true
- },
- emSize: 14,
- ignoredTags: [],
- ignoredStyles: [],
- baseStyle: { fontSize: 14 },
- tagsStyles: {},
- classesStyles: {},
- enableUserAgentStyles: true,
- enableCSSInlineProcessing: true,
- renderers: {},
- fallbackFonts: {
- 'sans-serif': Platform.select({ ios: 'system', default: 'sans-serif' }),
- monospace: Platform.select({ ios: 'Menlo', default: 'monospace' }),
- serif: Platform.select({ ios: 'Times New Roman', default: 'serif' })
- },
- systemFonts: Platform.select({
- default: [],
- ios: [
- 'San Francisco',
- 'Arial',
- 'ArialHebrew',
- 'Avenir',
- 'Baskerville',
- 'Bodoni 72',
- 'Bradley Hand',
- 'Chalkboard SE',
- 'Cochin',
- 'Copperplate',
- 'Courier',
- 'Courier New',
- 'Damascus',
- 'Didot',
- 'Futura',
- 'Geeza Pro',
- 'Georgia',
- 'Gill Sans',
- 'Helvetica',
- 'Helvetica Neue',
- 'Hiragino Sans',
- 'Hoefler Text',
- 'Iowan Old Style',
- 'Kailasa',
- 'Khmer Sangam MN',
- 'Marker Felt',
- 'Menlo',
- 'Mishafi',
- 'Noteworthy',
- 'Optima',
- 'Palatino',
- 'Papyrus',
- 'Savoye LET',
- 'Symbol',
- 'Thonburi',
- 'Times New Roman',
- 'Trebuchet MS',
- 'Verdana',
- 'Zapf Dingbats',
- 'Zapfino'
- ],
- android: [
- 'Roboto',
- 'notoserif',
- 'sans-serif-light',
- 'sans-serif-thin',
- 'sans-serif-medium'
- ]
- }),
- triggerTREInvalidationPropNames: [],
- debug: __DEV__,
- contentWidth: undefined
-};
-
-function RenderResolvedHTML(props: RenderResolvedHTMLProps) {
- const ttree = useTTree(props);
- return (
-
- );
-}
-
-export default function RenderHTML({
- defaultTextProps,
- ...props
-}: RenderHTMLProps) {
- const normalizedProps = {
- contentWidth: Dimensions.get('window').width,
- ...props,
- defaultTextProps: { ...defaultProps.defaultTextProps, ...defaultTextProps }
- };
+/**
+ * Render HTML text in native views!
+ *
+ * @remarks - If your application uses many instances of this component, you
+ * should share the render engine across those instances via the
+ * `TRenderEngineProvier` component, and render the HTML with
+ * `RenderHTMLFragment` instead. That should significantly increase
+ * performance.
+ *
+ * @param props - Props for this component.
+ */
+export default function RenderHTML(props: RenderHTMLProps) {
return (
-
-
- }>
- ({
- TChildrenRenderer,
- TNodeChildrenRenderer
- }),
- []
- )}>
-
- {(resolvedProps) => (
-
- )}
-
-
-
-
-
+
+ {React.createElement(RenderHTMLFragment, props)}
+
);
}
-
-RenderHTML.defaultProps = defaultProps;
-RenderHTML.propTypes = propTypes;
diff --git a/packages/render-html/src/RenderHTMLFragment.tsx b/packages/render-html/src/RenderHTMLFragment.tsx
new file mode 100644
index 000000000..ed477cf64
--- /dev/null
+++ b/packages/render-html/src/RenderHTMLFragment.tsx
@@ -0,0 +1,123 @@
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+
+import {
+ RenderResolvedHTMLProps,
+ ResolvedResourceProps,
+ RenderHTMLFragmentProps
+} from './shared-types';
+import useTTree from './hooks/useTTree';
+import SharedPropsContext, {
+ defaultSharedPropsContext
+} from './context/SharedPropsContext';
+import TChildrenRenderersContext from './context/TChildrenRendererContext';
+import TNodeChildrenRenderer from './TNodeChildrenRenderer';
+import RenderHTMLFragmentDebug from './RenderHTMLFragmentDebug';
+import SourceLoader from './SourceLoader';
+import TChildrenRenderer from './TChildrenRenderer';
+import TDocumentRenderer from './TDocumentRenderer';
+import selectSharedProps from './helpers/selectSharedProps';
+
+export type RenderHTMLFragmentPropTypes = Record<
+ keyof RenderHTMLFragmentProps,
+ any
+>;
+
+export const renderHtmlFragmentPropTypes: RenderHTMLFragmentPropTypes = {
+ defaultTextProps: PropTypes.object,
+ defaultViewProps: PropTypes.object,
+ source: PropTypes.oneOfType([
+ PropTypes.shape({
+ html: PropTypes.string.isRequired,
+ baseUrl: PropTypes.string
+ }),
+ PropTypes.shape({
+ uri: PropTypes.string.isRequired,
+ method: PropTypes.string,
+ body: PropTypes.any,
+ headers: PropTypes.object
+ })
+ ]),
+ enableExperimentalMarginCollapsing: PropTypes.bool,
+ remoteErrorView: PropTypes.func,
+ remoteLoadingView: PropTypes.func,
+ debug: PropTypes.bool.isRequired,
+ listsPrefixesRenderers: PropTypes.object,
+ onLinkPress: PropTypes.func,
+ computeEmbeddedMaxWidth: PropTypes.func,
+ contentWidth: PropTypes.number,
+ enableExperimentalPercentWidth: PropTypes.bool,
+ imagesInitialDimensions: PropTypes.shape({
+ width: PropTypes.number,
+ height: PropTypes.number
+ }),
+ renderersProps: PropTypes.object,
+ onTTreeChange: PropTypes.func,
+ onHTMLLoaded: PropTypes.func,
+ WebView: PropTypes.any,
+ defaultWebViewProps: PropTypes.object
+};
+
+export const renderHTMLFragmentDefaultProps: {
+ [k in keyof RenderHTMLFragmentProps]?: RenderHTMLFragmentProps[k];
+} = {
+ ...defaultSharedPropsContext,
+ contentWidth: undefined
+};
+
+function RenderResolvedHTML(props: RenderResolvedHTMLProps) {
+ const ttree = useTTree(props);
+ return (
+
+ );
+}
+
+const renderResolved = (resolvedProps: ResolvedResourceProps) => (
+
+);
+
+/**
+ * Render a HTML snippet, given that there is a `TRenderEngineProvider` up in
+ * the render tree.
+ *
+ * @param props - Props for this component.
+ */
+export default function RenderHTMLFragment(props: RenderHTMLFragmentProps) {
+ const {
+ source,
+ onHTMLLoaded,
+ remoteErrorView,
+ remoteLoadingView,
+ ...remainingProps
+ } = props;
+ const sourceLoaderProps = {
+ source,
+ onHTMLLoaded,
+ remoteErrorView,
+ remoteLoadingView,
+ children: renderResolved
+ };
+ return (
+
+
+ ({
+ TChildrenRenderer,
+ TNodeChildrenRenderer
+ }),
+ []
+ )}>
+ {React.createElement(SourceLoader, sourceLoaderProps)}
+
+
+
+ );
+}
+
+RenderHTMLFragment.defaultProps = renderHTMLFragmentDefaultProps;
+RenderHTMLFragment.propTypes = renderHtmlFragmentPropTypes;
diff --git a/packages/render-html/src/RenderHTMLDebug.tsx b/packages/render-html/src/RenderHTMLFragmentDebug.tsx
similarity index 82%
rename from packages/render-html/src/RenderHTMLDebug.tsx
rename to packages/render-html/src/RenderHTMLFragmentDebug.tsx
index aa8479a94..7bfbfba58 100644
--- a/packages/render-html/src/RenderHTMLDebug.tsx
+++ b/packages/render-html/src/RenderHTMLFragmentDebug.tsx
@@ -1,11 +1,7 @@
import React, { Fragment } from 'react';
import { PropsWithChildren } from 'react';
import lookupRecord from './helpers/lookupRecord';
-import { RenderHTMLProps } from './shared-types';
-
-export function RenderHTMLProd(props: PropsWithChildren) {
- return {props.children};
-}
+import { RenderHTMLFragmentProps } from './shared-types';
export const messages = {
outdatedUriProp:
@@ -25,8 +21,8 @@ export const messages = {
'https://reactnative.dev/docs/usewindowdimensions'
};
-const RenderHTMLDebug = function RenderHTMLDebug(
- props: PropsWithChildren
+const RenderHTMLFragmentDebug = function RenderHTMLDebug(
+ props: PropsWithChildren
) {
if (__DEV__) {
if (typeof props.contentWidth !== 'number') {
@@ -45,4 +41,4 @@ const RenderHTMLDebug = function RenderHTMLDebug(
return {props.children};
};
-export default RenderHTMLDebug;
+export default RenderHTMLFragmentDebug;
diff --git a/packages/render-html/src/TRenderEngineProvider.tsx b/packages/render-html/src/TRenderEngineProvider.tsx
new file mode 100644
index 000000000..9a0daa7d3
--- /dev/null
+++ b/packages/render-html/src/TRenderEngineProvider.tsx
@@ -0,0 +1,149 @@
+import TRenderEngine from '@native-html/transient-render-engine';
+import React, { PropsWithChildren } from 'react';
+import { Platform } from 'react-native';
+import PropTypes from 'prop-types';
+import useTRenderEngine from './hooks/useTRenderEngine';
+import { TransientRenderEngineConfig } from './shared-types';
+import RenderRegistryProvider from './context/RenderRegistryProvider';
+
+const defaultTRenderEngine = {} as any;
+
+const TRenderEngineContext = React.createContext(
+ defaultTRenderEngine
+);
+
+export const tRenderEngineProviderPropTypes: Record<
+ keyof TransientRenderEngineConfig,
+ any
+> = {
+ renderers: PropTypes.object.isRequired,
+ enableCSSInlineProcessing: PropTypes.bool,
+ enableUserAgentStyles: PropTypes.bool,
+ idsStyles: PropTypes.object,
+ ignoredTags: PropTypes.array.isRequired,
+ ignoredStyles: PropTypes.array.isRequired,
+ allowedStyles: PropTypes.array,
+ htmlParserOptions: PropTypes.object,
+ ignoreDOMNode: PropTypes.func,
+ alterDOMData: PropTypes.func,
+ alterDOMChildren: PropTypes.func,
+ alterDOMElement: PropTypes.func,
+ tagsStyles: PropTypes.object,
+ classesStyles: PropTypes.object,
+ emSize: PropTypes.number.isRequired,
+ baseStyle: PropTypes.object,
+ systemFonts: PropTypes.arrayOf(PropTypes.string),
+ fallbackFonts: PropTypes.shape({
+ serif: PropTypes.string,
+ 'sans-serif': PropTypes.string,
+ monospace: PropTypes.string
+ }),
+ triggerTREInvalidationPropNames: PropTypes.arrayOf(PropTypes.string),
+ onDocumentMetadataLoaded: PropTypes.func
+};
+
+export const defaultTRenderEngineProviderProps: TransientRenderEngineConfig = {
+ htmlParserOptions: {
+ decodeEntities: true
+ },
+ emSize: 14,
+ ignoredTags: [],
+ ignoredStyles: [],
+ baseStyle: { fontSize: 14 },
+ tagsStyles: {},
+ classesStyles: {},
+ enableUserAgentStyles: true,
+ enableCSSInlineProcessing: true,
+ renderers: {},
+ fallbackFonts: {
+ 'sans-serif': Platform.select({ ios: 'system', default: 'sans-serif' }),
+ monospace: Platform.select({ ios: 'Menlo', default: 'monospace' }),
+ serif: Platform.select({ ios: 'Times New Roman', default: 'serif' })
+ },
+ systemFonts: Platform.select({
+ default: [],
+ ios: [
+ 'San Francisco',
+ 'Arial',
+ 'ArialHebrew',
+ 'Avenir',
+ 'Baskerville',
+ 'Bodoni 72',
+ 'Bradley Hand',
+ 'Chalkboard SE',
+ 'Cochin',
+ 'Copperplate',
+ 'Courier',
+ 'Courier New',
+ 'Damascus',
+ 'Didot',
+ 'Futura',
+ 'Geeza Pro',
+ 'Georgia',
+ 'Gill Sans',
+ 'Helvetica',
+ 'Helvetica Neue',
+ 'Hiragino Sans',
+ 'Hoefler Text',
+ 'Iowan Old Style',
+ 'Kailasa',
+ 'Khmer Sangam MN',
+ 'Marker Felt',
+ 'Menlo',
+ 'Mishafi',
+ 'Noteworthy',
+ 'Optima',
+ 'Palatino',
+ 'Papyrus',
+ 'Savoye LET',
+ 'Symbol',
+ 'Thonburi',
+ 'Times New Roman',
+ 'Trebuchet MS',
+ 'Verdana',
+ 'Zapf Dingbats',
+ 'Zapfino'
+ ],
+ android: [
+ 'Roboto',
+ 'notoserif',
+ 'sans-serif-light',
+ 'sans-serif-thin',
+ 'sans-serif-medium'
+ ]
+ }),
+ triggerTREInvalidationPropNames: []
+};
+
+export function useAmbiantTRenderEngine() {
+ const engine = React.useContext(TRenderEngineContext);
+ if (__DEV__ && engine === defaultTRenderEngine) {
+ console.error('TRenderEngineProvider is missing in the render tree.');
+ }
+ return engine;
+}
+
+/**
+ * A react component to share a transient web engine instance across different
+ * rendered contents via `RenderHTMLFragment`. This can seriously enhance
+ * performance in applications with potentially dozens or hundreds of distinct
+ * rendered snippets such as chat apps.
+ *
+ * @param props - Pass engine config here.
+ */
+export default function TRenderEngineProvider({
+ children,
+ ...config
+}: PropsWithChildren) {
+ const engine = useTRenderEngine(config);
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+TRenderEngineProvider.defaultProps = defaultTRenderEngineProviderProps;
+TRenderEngineProvider.propTypes = tRenderEngineProviderPropTypes;
diff --git a/packages/render-html/src/__tests__/component.render-html-dev.test.tsx b/packages/render-html/src/__tests__/component.render-html-fragment-debug.test.tsx
similarity index 75%
rename from packages/render-html/src/__tests__/component.render-html-dev.test.tsx
rename to packages/render-html/src/__tests__/component.render-html-fragment-debug.test.tsx
index 034f136fb..91d733c78 100644
--- a/packages/render-html/src/__tests__/component.render-html-dev.test.tsx
+++ b/packages/render-html/src/__tests__/component.render-html-fragment-debug.test.tsx
@@ -1,30 +1,33 @@
import React from 'react';
import { render } from 'react-native-testing-library';
-import RenderHTMLDebug, { messages } from '../RenderHTMLDebug';
+import RenderHTMLFragmentDebug, { messages } from '../RenderHTMLFragmentDebug';
beforeAll(function () {
//@ts-expect-error
global.__DEV__ = true;
});
-describe('RenderHTMLDebug', () => {
+describe('RenderHTMLFragmentDebug', () => {
it('should warn when contentWidth has not been provided', () => {
console.warn = jest.fn();
render(
- Hello world
' }} debug={false} />
+ Hello world' }}
+ debug={false}
+ />
);
expect(console.warn).toHaveBeenNthCalledWith(1, messages.contentWidth);
});
it('should warn when source has not been provided', () => {
console.warn = jest.fn();
//@ts-expect-error
- render();
+ render();
expect(console.warn).toHaveBeenNthCalledWith(1, messages.noSource);
});
it('should warn when outdated html prop has been provided', () => {
console.warn = jest.fn();
render(
- React.createElement(RenderHTMLDebug, {
+ React.createElement(RenderHTMLFragmentDebug, {
contentWidth: 0,
source: { html: 'hello world' },
//@ts-expect-error
@@ -37,7 +40,7 @@ describe('RenderHTMLDebug', () => {
it('should warn when outdated uri prop has been provided', () => {
console.warn = jest.fn();
render(
- React.createElement(RenderHTMLDebug, {
+ React.createElement(RenderHTMLFragmentDebug, {
contentWidth: 0,
source: { html: 'hello world' },
//@ts-expect-error
diff --git a/packages/render-html/src/__tests__/component.render-html.test.tsx b/packages/render-html/src/__tests__/component.render-html.test.tsx
index e81e3bde6..8b8d6c61d 100644
--- a/packages/render-html/src/__tests__/component.render-html.test.tsx
+++ b/packages/render-html/src/__tests__/component.render-html.test.tsx
@@ -12,6 +12,7 @@ describe('RenderHTML', () => {
).not.toThrow();
});
it('should render without error when missing a source', () => {
+ //@ts-expect-error
expect(() => render()).not.toThrow();
});
it('should update ImgTag contentWidth when contentWidth prop changes', () => {
diff --git a/packages/render-html/src/context/SharedPropsContext.ts b/packages/render-html/src/context/SharedPropsContext.ts
index 5cd20e45c..4f426ce5b 100644
--- a/packages/render-html/src/context/SharedPropsContext.ts
+++ b/packages/render-html/src/context/SharedPropsContext.ts
@@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
-import { Dimensions, Linking, TextProps } from 'react-native';
+import { Dimensions, Linking, TextProps, ViewProps } from 'react-native';
import { RenderHTMLPassedProps } from '../shared-types';
export const defaultSharedPropsContext: Required = {
@@ -19,7 +19,15 @@ export const defaultSharedPropsContext: Required = {
},
listsPrefixesRenderers: {},
onLinkPress: (_e, href) => Linking.canOpenURL(href) && Linking.openURL(href),
- WebView: () => null,
+ WebView: () => {
+ if (__DEV__) {
+ console.warn(
+ 'One of your renderer is attempting to use WebView component, which has not been ' +
+ "provided as a prop to the RenderHtml component. As a consequence, the element won't be rendered."
+ );
+ }
+ return null;
+ },
defaultWebViewProps: {},
renderersProps: {}
};
@@ -41,11 +49,17 @@ export function useRendererProps<
}
export function useDefaultTextProps(): TextProps {
- return useSharedProps().defaultTextProps;
+ return {
+ ...defaultSharedPropsContext.defaultTextProps,
+ ...useSharedProps().defaultTextProps
+ };
}
-export function useDefaultViewProps(): TextProps {
- return useSharedProps().defaultViewProps;
+export function useDefaultViewProps(): ViewProps {
+ return {
+ ...defaultSharedPropsContext.defaultViewProps,
+ ...useSharedProps().defaultViewProps
+ };
}
export function useComputeMaxWidthForTag(tagName: string) {
diff --git a/packages/render-html/src/helpers/__tests__/selectSharedProps.test.ts b/packages/render-html/src/helpers/__tests__/selectSharedProps.test.ts
new file mode 100644
index 000000000..0b0a28fa5
--- /dev/null
+++ b/packages/render-html/src/helpers/__tests__/selectSharedProps.test.ts
@@ -0,0 +1,12 @@
+import selectSharedProps from '../selectSharedProps';
+
+describe('selectSharedProps', () => {
+ it('should default to default values', () => {
+ expect(selectSharedProps({ contentWidth: undefined }).contentWidth).toEqual(
+ expect.any(Number)
+ );
+ });
+ it('should retain non-nil values', () => {
+ expect(selectSharedProps({ contentWidth: 300 }).contentWidth).toEqual(300);
+ });
+});
diff --git a/packages/render-html/src/helpers/selectSharedProps.ts b/packages/render-html/src/helpers/selectSharedProps.ts
new file mode 100644
index 000000000..64eb7a3e2
--- /dev/null
+++ b/packages/render-html/src/helpers/selectSharedProps.ts
@@ -0,0 +1,16 @@
+import pickBy from 'ramda/src/pickBy';
+import pick from 'ramda/src/pick';
+import pipe from 'ramda/src/pipe';
+import mergeRight from 'ramda/src/mergeRight';
+import { RenderHTMLPassedProps, RenderHTMLProps } from '../shared-types';
+import { defaultSharedPropsContext } from '../context/SharedPropsContext';
+
+const selectSharedProps: (
+ props: Partial
+) => Required = pipe(
+ pick(Object.keys(defaultSharedPropsContext)),
+ pickBy((val) => val != null),
+ mergeRight(defaultSharedPropsContext) as any
+);
+
+export default selectSharedProps;
diff --git a/packages/render-html/src/hooks/useTRenderEngine.ts b/packages/render-html/src/hooks/useTRenderEngine.ts
index 5e4c2d019..c391b5c01 100644
--- a/packages/render-html/src/hooks/useTRenderEngine.ts
+++ b/packages/render-html/src/hooks/useTRenderEngine.ts
@@ -6,11 +6,11 @@ import TRenderEngine, {
TagName,
DOMElement
} from '@native-html/transient-render-engine';
-import { RenderResolvedHTMLProps } from '../shared-types';
+import { TransientRenderEngineConfig } from '../shared-types';
import { CustomRendererSpecs } from '../render/render-types';
import lookupRecord from '../helpers/lookupRecord';
-export default function useTRenderEngine(props: RenderResolvedHTMLProps) {
+export default function useTRenderEngine(props: TransientRenderEngineConfig) {
const {
allowedStyles,
ignoredStyles,
diff --git a/packages/render-html/src/hooks/useTTree.ts b/packages/render-html/src/hooks/useTTree.ts
index 8bbcf1830..172594812 100644
--- a/packages/render-html/src/hooks/useTTree.ts
+++ b/packages/render-html/src/hooks/useTTree.ts
@@ -1,10 +1,10 @@
import { tnodeToString } from '@native-html/transient-render-engine';
import { useMemo, useEffect } from 'react';
import { RenderResolvedHTMLProps } from '../shared-types';
-import useTRenderEngine from './useTRenderEngine';
+import { useAmbiantTRenderEngine } from '../TRenderEngineProvider';
export default function useTTree(props: RenderResolvedHTMLProps) {
- const trenderEngine = useTRenderEngine(props);
+ const trenderEngine = useAmbiantTRenderEngine();
const ttree = useMemo(() => trenderEngine.buildTTree(props.html), [
props.html,
trenderEngine
diff --git a/packages/render-html/src/index.ts b/packages/render-html/src/index.ts
index e70057fc0..0040c824a 100644
--- a/packages/render-html/src/index.ts
+++ b/packages/render-html/src/index.ts
@@ -50,6 +50,8 @@ export {
} from './TNodeChildrenRenderer';
export type { TNodeChildrenRendererProps } from './TNodeChildrenRenderer';
export { default as TNodeRenderer } from './TNodeRenderer';
+export { default as TRenderEngineProvider } from './TRenderEngineProvider';
+export { default as RenderHTMLFragment } from './RenderHTMLFragment';
export { default as useInternalRenderer } from './hooks/useInternalRenderer';
export { default as useNormalizedUrl } from './hooks/useNormalizedUrl';
export { default as useTRenderEngine } from './hooks/useTRenderEngine';
diff --git a/packages/render-html/src/shared-types.ts b/packages/render-html/src/shared-types.ts
index 4cdab6e53..353822613 100644
--- a/packages/render-html/src/shared-types.ts
+++ b/packages/render-html/src/shared-types.ts
@@ -250,6 +250,29 @@ export interface TransientRenderEngineConfig {
* The default value in pixels for 1em
*/
emSize?: number;
+ /**
+ * Name of props which should trigger a rebuild of the Transient Render
+ * Engine (TRE).
+ *
+ * @remarks For performance sake, this component will not recreate an
+ * instance of the engine on each prop change. If you need some props to
+ * trigger a new instantiation, such as `tagsStyles`, pass a list of their
+ * names in this array.
+ *
+ * Please note that only props involved in the building of the transient render
+ * tree are concerned by this mechanism.
+ *
+ * @example
+ * ```ts
+ * triggerTREInvalidationPropNames = ['tagsStyles', 'allowedStyles']
+ * ```
+ */
+ triggerTREInvalidationPropNames?: Array<
+ Exclude<
+ keyof TransientRenderEngineConfig,
+ 'triggerTREInvalidationPropNames'
+ >
+ >;
}
export interface RenderHTMLSourceUri {
@@ -286,9 +309,8 @@ export interface RenderHTMLSourceInline {
export type RenderHTMLSource = RenderHTMLSourceInline | RenderHTMLSourceUri;
-export interface RenderHTMLProps
- extends RenderHTMLPassedProps
,
- TransientRenderEngineConfig {
+export interface RenderHTMLFragmentProps
+ extends RenderHTMLPassedProps
{
/**
* The object source to render (either `{ uri }` or `{ html }`).
*/
@@ -309,27 +331,16 @@ export interface RenderHTMLProps
* Triggered when HTML is available to the RenderHTML component.
*/
onHTMLLoaded?: (html: string) => void;
- /**
- * Name of props which should trigger a rebuild of the Transient Render
- * Engine (TRE).
- *
- * @remarks For performance sake, this component will not recreate an
- * instance of the engine on each prop change. If you need some props to
- * trigger a new instantiation, such as `tagsStyles`, pass a list of their
- * names in this array.
- *
- * Please note that only props involved in the building of the transient render
- * tree are concerned by this mechanism.
- *
- * @example
- * ```ts
- * triggerTREInvalidationPropNames = ['tagsStyles', 'allowedStyles']
- * ```
- */
- triggerTREInvalidationPropNames?: Array;
}
-export type RenderResolvedHTMLProps = Omit & {
+export interface RenderHTMLProps
+ extends RenderHTMLFragmentProps
,
+ TransientRenderEngineConfig {}
+
+export type RenderResolvedHTMLProps = Pick<
+ RenderHTMLProps,
+ 'onTTreeChange' | 'debug'
+> & {
html: string;
baseUrl?: string;
onDocumentMetadataLoaded?: TransientRenderEngineConfig['onDocumentMetadataLoaded'];
@@ -340,7 +351,11 @@ export interface ResolvedResourceProps {
baseUrl?: string;
}
-export interface SourceLoaderProps extends RenderHTMLProps {
+export interface SourceLoaderProps
+ extends Pick<
+ RenderHTMLProps,
+ 'source' | 'remoteLoadingView' | 'remoteErrorView' | 'onHTMLLoaded'
+ > {
children: (resource: ResolvedResourceProps) => ReactElement;
}