Skip to content

Commit

Permalink
feat: new prop "onTTreeChange"
Browse files Browse the repository at this point in the history
  • Loading branch information
jsamr committed Jun 4, 2021
1 parent 55f039e commit 5ecdcab
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 110 deletions.
2 changes: 1 addition & 1 deletion packages/render-html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@
]
},
"dependencies": {
"@native-html/transient-render-tree": "^1.1.3"
"@native-html/transient-render-tree": "^1.3.1"
}
}
67 changes: 13 additions & 54 deletions packages/render-html/src/RenderHTML.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useMemo } from 'react';
import { TTreeBuilder } from '@native-html/transient-render-tree';
import React from 'react';
import PropTypes from 'prop-types';
import { Dimensions } from 'react-native';
import { RenderHTMLProps } from './types';
import TNodeRenderer from './TNodeRenderer';
import defaultRenderers from './defaultRenderers';
import useTTree from './useTTree';

const propTypes: Record<keyof RenderHTMLProps, any> = {
type RenderHTMLPropTypes = Record<keyof RenderHTMLProps, any>;

const propTypes: RenderHTMLPropTypes = {
renderers: PropTypes.object.isRequired,
enableCSSInlineProcessing: PropTypes.bool,
enableUserAgentStyles: PropTypes.bool,
Expand Down Expand Up @@ -44,10 +46,11 @@ const propTypes: Record<keyof RenderHTMLProps, any> = {
baseStyle: PropTypes.object,
textSelectable: PropTypes.bool,
renderersProps: PropTypes.object,
allowFontScaling: PropTypes.bool
allowFontScaling: PropTypes.bool,
onTTreeChange: PropTypes.func
};

const defaultProps = {
const defaultProps: Partial<Record<keyof RenderHTMLProps, any>> = {
debug: false,
decodeEntities: true,
emSize: 14,
Expand All @@ -57,67 +60,23 @@ const defaultProps = {
enableExperimentalPercentWidth: false,
ignoredTags: [],
ignoredStyles: [],
baseStyles: { fontSize: 14 },
baseStyle: { fontSize: 14 },
tagsStyles: {},
classesStyles: {},
textSelectable: false,
allowFontScaling: true,
enableUserAgentStyles: true,
enableCSSInlineProcessing: true
enableCSSInlineProcessing: true,
renderers: {}
};

function useTTreeBuilder({
allowedStyles,
ignoredStyles,
decodeEntities,
baseStyle,
classesStyles,
tagsStyles,
idsStyles,
enableCSSInlineProcessing,
enableUserAgentStyles
}: RenderHTMLProps) {
return useMemo(
() =>
new TTreeBuilder({
cssProcessorConfig: {
inlinePropertiesBlacklist: ignoredStyles,
inlinePropertiesWhitelist: allowedStyles
},
htmlParserOptions: {
decodeEntities
},
stylesConfig: {
baseStyle,
enableCSSInlineProcessing,
enableUserAgentStyles,
classesStyles,
idsStyles,
tagsStyles
}
}),
[
allowedStyles,
baseStyle,
classesStyles,
decodeEntities,
enableCSSInlineProcessing,
enableUserAgentStyles,
idsStyles,
ignoredStyles,
tagsStyles
]
);
}

export default function RenderHTML(props: RenderHTMLProps) {
const ttreebuilder = useTTreeBuilder(props);
const troot = ttreebuilder.buildTTree(props.html);
const ttree = useTTree(props);
return (
<TNodeRenderer
defaultRenderers={defaultRenderers}
passedProps={props}
tnode={troot}
tnode={ttree}
/>
);
}
Expand Down
4 changes: 0 additions & 4 deletions packages/render-html/src/TNodeRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import TPhrasingRenderer from './TPhrasingRenderer';
import TTextRenderer from './TTextRenderer';
import defaultRenderers from './defaultRenderers';
import { RenderHTMLPassedProps } from './types';
import printTNode from './printTNode';
import extractAnchorOnLinkPress from './extractAnchorOnLinkPress';
import { GestureResponderEvent } from 'react-native';

Expand Down Expand Up @@ -69,9 +68,6 @@ function TNodeRenderer(props: TNodeRendererProps<TNode>) {
defaultRenderers,
syntheticAnchorOnLinkPress
};
if (tnode.tagName === 'body') {
printTNode(tnode);
}
if (tnode instanceof TBlock) {
return React.createElement(TBlockRenderer, childrenProps);
}
Expand Down
50 changes: 1 addition & 49 deletions packages/render-html/src/printTNode.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,4 @@
import { TNode, TText } from '@native-html/transient-render-tree';

function tnodePropertiesString(tnode: TNode) {
const tagPrint = tnode.tagName ? `tag=${tnode.tagName}` : 'anonymous';
const idPrint = tnode.id ? `id=${tnode.id}` : null;
const classesPrint = tnode.className ? `classes=${tnode.className}` : null;
const dataPrint =
tnode instanceof TText
? `data="${
tnode.data.length > 20
? tnode.data.substring(0, 17) + '…'
: tnode.data
}"`
: null;
// @ts-ignore
const anchorPrint = tnode.isAnchor ? `anchor[${tnode.href}]` : null;
const detailsPrint = [tagPrint, idPrint, classesPrint, dataPrint, anchorPrint]
.filter((p) => p !== null)
.join(',');
return `${tnode.constructor.name}(${detailsPrint})`;
}

function tnodeToString(
tnode: TNode,
paddingLeftParent = 0,
isChild = false,
isLast = false,
hasParentLine = false
) {
const paddingLeftChars = ''.padStart(1, '');
const prefix = isChild ? (isLast ? '└' : '├') : '';
const parentPrefix = !hasParentLine ? '' : '│';
const paddingPrefixChars = parentPrefix.padStart(paddingLeftParent - 1, ' ');
const childrenPrint: string = tnode.children
.map(
(c, i) =>
tnodeToString(
c,
paddingLeftParent + 1,
true,
i === tnode.children.length - 1
),
isChild && !isLast
)
.join('');
return `${paddingPrefixChars}${paddingLeftChars}${prefix}${tnodePropertiesString(
tnode
)}\n${childrenPrint}`;
}
import { TNode, tnodeToString } from '@native-html/transient-render-tree';

export default function printTNode(tnode: TNode) {
console.info(tnodeToString(tnode));
Expand Down
1 change: 1 addition & 0 deletions packages/render-html/src/renderers/imgRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const imgRenderer: DefaultRenderers['block'][string] = (props) => {
<ImgTag
alt={tnode.attributes.alt}
testID="img"
altColor={tnode.styles.nativeTextFlow.color as string}
contentWidth={contentWidth as number}
computeImagesMaxWidth={computeImagesMaxWidth}
enableExperimentalPercentWidth={enableExperimentalPercentWidth}
Expand Down
3 changes: 2 additions & 1 deletion packages/render-html/src/tags/ImgTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface ImgTagProps {
testID?: string;
computeImagesMaxWidth?: (containerWidth: number) => number;
onPress: PressableProps['onPress'];
altColor: string;
contentWidth: number;
enableExperimentalPercentWidth?: boolean;
imagesInitialDimensions: ImgDimensions;
Expand Down Expand Up @@ -411,7 +412,7 @@ export default class ImgTag extends PureComponent<ImgTagProps, any> {
return (
<View style={styles.errorBox} testID="image-error">
{this.props.alt ? (
<Text style={styles.errorText}>{this.props.alt}</Text>
<Text style={[styles.errorText, { color: this.props.altColor }]}>{this.props.alt}</Text>
) : (
false
)}
Expand Down
7 changes: 6 additions & 1 deletion packages/render-html/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
MixedStyleRecord,
DOMNode,
DOMText,
DOMElement
DOMElement,
TNode
} from '@native-html/transient-render-tree';
import { ReactNode } from 'react';
import {
Expand Down Expand Up @@ -206,4 +207,8 @@ export interface RenderHTMLProps<P = any> extends RenderHTMLPassedProps<P> {
* Return true in this custom function to ignore nodes very precisely, see [ignoring HTML content](https://github.com/archriss/react-native-render-html#ignoring-html-content)
*/
ignoreNodesFunction?: (node: DOMNode, parentTagName: string) => boolean;
/**
* Triggered when the transient render tree changes. Useful for debugging.
*/
onTTreeChange?: (ttree: TNode) => void;
}
25 changes: 25 additions & 0 deletions packages/render-html/src/useTTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { tnodeToString } from '@native-html/transient-render-tree';
import { useMemo, useEffect } from 'react';
import { RenderHTMLProps } from './types';
import useTTreeBuilder from './useTTreeBuilder';

export default function useTTree(props: RenderHTMLProps) {
const ttreebuilder = useTTreeBuilder(props);
const ttree = useMemo(() => ttreebuilder.buildTTree(props.html), [
props.html
]);
const { onTTreeChange, debug } = props;
useEffect(() => {
onTTreeChange?.call(null, ttree);
if (debug && __DEV__) {
console.info(
`Transient Render Tree update:\n${tnodeToString(ttree, {
isChild: false,
isLast: false,
parentLeftPrefix: ' '
})}`
);
}
}, [ttree, onTTreeChange, debug]);
return ttree;
}
47 changes: 47 additions & 0 deletions packages/render-html/src/useTTreeBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useMemo } from 'react';
import { TTreeBuilder } from '@native-html/transient-render-tree';
import { RenderHTMLProps } from './types';

export default function useTTreeBuilder({
allowedStyles,
ignoredStyles,
decodeEntities,
baseStyle,
classesStyles,
tagsStyles,
idsStyles,
enableCSSInlineProcessing,
enableUserAgentStyles
}: RenderHTMLProps) {
return useMemo(
() =>
new TTreeBuilder({
cssProcessorConfig: {
inlinePropertiesBlacklist: ignoredStyles,
inlinePropertiesWhitelist: allowedStyles
},
htmlParserOptions: {
decodeEntities
},
stylesConfig: {
baseStyle,
enableCSSInlineProcessing,
enableUserAgentStyles,
classesStyles,
idsStyles,
tagsStyles
}
}),
[
allowedStyles,
baseStyle,
classesStyles,
decodeEntities,
enableCSSInlineProcessing,
enableUserAgentStyles,
idsStyles,
ignoredStyles,
tagsStyles
]
);
}

0 comments on commit 5ecdcab

Please sign in to comment.