Skip to content

Commit

Permalink
feat: support for loading HTML from URI
Browse files Browse the repository at this point in the history
  • Loading branch information
jsamr committed Jun 4, 2021
1 parent b888fe0 commit 6c07b8d
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/render-html/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@
]
},
"dependencies": {
"@native-html/transient-render-engine": "^2.0.0"
"@native-html/transient-render-engine": "^2.0.1"
}
}
93 changes: 93 additions & 0 deletions packages/render-html/src/LoadHTML.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { ReactElement, useEffect, useState } from 'react';
import { ActivityIndicator, Text, View } from 'react-native';
import { RenderHTMLProps } from './shared-types';

interface HTMLLoaderProps extends RenderHTMLProps {
children: (resolvedHTML: string) => ReactElement;
}

interface LoaderInternalState {
loading: boolean;
error: boolean;
resolvedHTML: string | null;
}

const ERROR_STATE = {
error: true,
loading: false,
resolvedHTML: null
};

async function loadHTMLResource(uri: string): Promise<LoaderInternalState> {
const response = await fetch(uri);
if (response.ok) {
const html = await response.text();
return {
resolvedHTML: html,
error: false,
loading: false
};
}
return ERROR_STATE;
}

function useLoader(props: HTMLLoaderProps) {
const { uri, html } = props;
const [loadState, setState] = useState<LoaderInternalState>({
error: false,
loading: false,
resolvedHTML: html || null
});
const { error } = loadState;
useEffect(() => {
let cancelled = false;
if (!error && uri) {
setState({ loading: true, error: false, resolvedHTML: null });
loadHTMLResource(uri)
.then((state) => {
!cancelled && setState(state);
})
.catch(() => {
!cancelled && setState(ERROR_STATE);
});
}
return () => {
cancelled = true;
};
}, [error, uri]);
return loadState;
}

function defaultRenderError(props: RenderHTMLProps) {
return (
<View style={{ flex: 1, alignItems: 'center' }}>
<Text style={{ fontStyle: 'italic', fontSize: 16 }}>
Failed to load {props.uri}
</Text>
</View>
);
}

function defaultRenderLoading() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
);
}
export default function LoadHTML(props: HTMLLoaderProps): ReactElement | null {
const { remoteErrorView, remoteLoadingView, children } = props;
const { resolvedHTML, error, loading } = useLoader(props);
if (error) {
return remoteErrorView!.call(null, props);
}
if (loading) {
return remoteLoadingView!.call(null, props);
}
return children?.call(null, resolvedHTML!) || null;
}

LoadHTML.defaultProps = {
remoteErrorView: defaultRenderError,
remoteLoadingView: defaultRenderLoading
};
20 changes: 14 additions & 6 deletions packages/render-html/src/RenderHTML.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Platform } from 'react-native';
import { RenderHTMLProps } from './shared-types';
Expand All @@ -10,6 +10,7 @@ import SharedPropsContext, {
import TNodeRenderersContext from './context/TNodeRenderersContext';
import TChildrenRenderer from './TChildrenRenderer';
import RenderHTMLDebug from './RenderHTMLDebug';
import LoadHTML from './LoadHTML';

export type RenderHTMLPropTypes = Record<keyof RenderHTMLProps, any>;

Expand Down Expand Up @@ -138,18 +139,25 @@ const defaultProps: {
debug: __DEV__
};

export default function RenderHTML(props: RenderHTMLProps) {
function RenderResolvedHTML(props: RenderHTMLProps) {
const ttree = useTTree(props);
const Wrapper = props.debug ? RenderHTMLDebug : Fragment;
return <TNodeRenderer tnode={ttree} collapsedMarginTop={null} />;
}

export default function RenderHTML(props: RenderHTMLProps) {
return (
<Wrapper {...props}>
<RenderHTMLDebug {...props}>
<SharedPropsContext.Provider value={props}>
<TNodeRenderersContext.Provider
value={{ TNodeRenderer, TChildrenRenderer }}>
<TNodeRenderer tnode={ttree} collapsedMarginTop={null} />
<LoadHTML {...props}>
{(resolvedHTML) => (
<RenderResolvedHTML {...props} html={resolvedHTML} />
)}
</LoadHTML>
</TNodeRenderersContext.Provider>
</SharedPropsContext.Provider>
</Wrapper>
</RenderHTMLDebug>
);
}

Expand Down
21 changes: 17 additions & 4 deletions packages/render-html/src/RenderHTMLDebug.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react';
import React, { Fragment } from 'react';
import { PropsWithChildren } from 'react';
import { useEffect } from 'react';
import RenderHTML from './RenderHTML';
import { RenderHTMLProps } from './shared-types';

export default function RenderHTMLDebug(props: RenderHTMLProps) {
function RenderHTMLProd(props: PropsWithChildren<RenderHTMLProps>) {
return <Fragment>{props.children}</Fragment>;
}

function RenderHTMLDev(props: PropsWithChildren<RenderHTMLProps>) {
useEffect(() => {
if (typeof props.contentWidth !== 'number') {
console.warn(
Expand All @@ -16,5 +20,14 @@ export default function RenderHTMLDebug(props: RenderHTMLProps) {
);
}
}, [props.contentWidth]);
return React.createElement(RenderHTML, props);
return <Fragment>{props.children}</Fragment>;
}

export default function RenderHTMLDebug(
props: PropsWithChildren<RenderHTMLProps>
) {
if (props.debug && __DEV__) {
return React.createElement(RenderHTMLDev, props);
}
return React.createElement(RenderHTMLProd, props);
}
2 changes: 1 addition & 1 deletion packages/render-html/src/TBlockRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function mergeCollapsedMargins(
return [nativeStyle, additionalStyles];
}

const TDefaultBlockRenderer: TDefaultRenderer<TBlock> = ({
export const TDefaultBlockRenderer: TDefaultRenderer<TBlock> = ({
tnode,
key,
children: overridingChildren,
Expand Down
8 changes: 8 additions & 0 deletions packages/render-html/src/TDocumentRenderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TBlock } from '@native-html/transient-render-engine';
import { TNodeGenericRendererProps } from './shared-types';

const TDocumentRenderer = ({}: TNodeGenericRendererProps<TBlock>) => {
return null;
};

export default TDocumentRenderer;
1 change: 1 addition & 0 deletions packages/render-html/src/defaultRenderers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TBlock } from '@native-html/transient-render-engine';
import React from 'react';
import ImgRenderer from './renderers/ImgRenderer';
import ListRenderer from './renderers/ListRenderer';
import type { RendererProps } from './shared-types';
Expand Down
3 changes: 3 additions & 0 deletions packages/render-html/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import RenderHTML from './RenderHTML';
export * from './shared-types';
export default RenderHTML;

export { default as useTRenderEngine } from './useTRenderEngine';
export { default as useTTree } from './useTTree';
8 changes: 4 additions & 4 deletions packages/render-html/src/shared-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
TNode,
TBlock
} from '@native-html/transient-render-engine';
import { ReactNode } from 'react';
import { ReactElement, ReactNode } from 'react';
import {
CSSPropertyNameList,
MixedStyleDeclaration
Expand Down Expand Up @@ -204,15 +204,15 @@ export interface RenderHTMLProps<P = any>
/**
* Replace the default wrapper with a function that takes your content as the first parameter.
*/
customWrapper?: (innerNodes: ReactNode) => ReactNode;
customWrapper?: (innerNodes: ReactNode) => ReactElement;
/**
* Replace the default loader while fetching a remote website's content.
*/
remoteLoadingView?: (props: RenderHTMLProps<P>, state: any) => ReactNode;
remoteLoadingView?: (props: RenderHTMLProps<P>) => ReactElement;
/**
* Replace the default error if a remote website's content could not be fetched.
*/
remoteErrorView?: (props: RenderHTMLProps<P>, state: any) => ReactNode;
remoteErrorView?: (props: RenderHTMLProps<P>) => ReactElement;
/**
* The default value in pixels for 1em
*/
Expand Down
20 changes: 10 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2910,28 +2910,28 @@ __metadata:
languageName: node
linkType: hard

"@native-html/css-processor@npm:1.5.0":
version: 1.5.0
resolution: "@native-html/css-processor@npm:1.5.0"
"@native-html/css-processor@npm:1.5.1":
version: 1.5.1
resolution: "@native-html/css-processor@npm:1.5.1"
dependencies:
css-to-react-native: ^3.0.0
peerDependencies:
"@types/react-native": "*"
csstype: ^3.0.4
checksum: 7263eb07cd677080bd2b7958d8eb304858df3c0aeba7a415537dea0e01d31dd64fad068f96071cfd131a240a96bb9c66e11a3b0bda2bbdbfb2b80d7a5785e3d0
checksum: 6c4e253314ff5e438964b1d6621f40cb41ab02cee2aa4ccfaf2f2e8adeeaa1576fc0469ceea297c40569ec6d496fff53f7037bb2c35f593d615feef78dcc5a20
languageName: node
linkType: hard

"@native-html/transient-render-engine@npm:^2.0.0":
version: 2.0.0
resolution: "@native-html/transient-render-engine@npm:2.0.0"
"@native-html/transient-render-engine@npm:^2.0.1":
version: 2.0.1
resolution: "@native-html/transient-render-engine@npm:2.0.1"
dependencies:
"@native-html/css-processor": 1.5.0
"@native-html/css-processor": 1.5.1
htmlparser2: ^5.0.1
peerDependencies:
"@types/react-native": "*"
react-native: ^0.63.0
checksum: 6d7d520f91b8b19685676026931cda0852a46262585fa706005f4db01c5454814d4a319eaecaf5650991076587e9e1dfbcad619993716532a1920d5359124c6b
checksum: 8bee3f1c032972ebbc1d108745c5052e9fc35e5c39087a9d64a29db5c324cc3cc148089a841ce41cf02d8ca9f61b0619a962053af7788ec5a9b2426ec26fc060
languageName: node
linkType: hard

Expand Down Expand Up @@ -14216,7 +14216,7 @@ fsevents@^1.2.7:
"@babel/preset-react": ^7.12.7
"@babel/preset-typescript": ^7.12.1
"@babel/runtime": ^7.12.5
"@native-html/transient-render-engine": ^2.0.0
"@native-html/transient-render-engine": ^2.0.1
"@react-native-community/bob": ^0.16.2
"@release-it/conventional-changelog": ^2.0.0
"@types/jest": ^26.0.14
Expand Down

0 comments on commit 6c07b8d

Please sign in to comment.