Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8f5c030

Browse files
committed
feat(iframe-plugin): new autoscale config
When this config is enabled (default), the WebView will be scaled down to fit the contentWidth.
1 parent 1de3df0 commit 8f5c030

File tree

7 files changed

+181
-67
lines changed

7 files changed

+181
-67
lines changed

packages/iframe-plugin/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ yarn add @native-html/iframe-plugin react-native-webview
4848
- Supports `onLinkPress`;
4949
- Supports `defaultWebViewProps`;
5050
- Compliance with [RFC001](https://github.com/archriss/react-native-render-html/blob/master/rfc/001-A-deterministic-approach-to-embedded-content-scaling.adoc#L13): scales to available width;
51+
- Autoscale feature (adapt zoom level to available width! Enabled by default.);
5152
- A single renderer function exported as default, super easy to plug-in!
5253
- Compatible with `react-native-web` via [`@formidable-webview/web`](https://github.com/formidable-webview/ubiquitous/tree/master/packages/web#readme)
5354

@@ -81,6 +82,7 @@ const renderers = {
8182
WebView={WebView}
8283
source={{ html: '<iframe ...></iframe>' }}
8384
defaultWebViewProps={{ /* Any prop you want to pass to WebView */ }}
85+
renderersProps={{ iframe: { autoscale: true /* enabled by default */ }}}
8486
/>
8587

8688
```

packages/iframe-plugin/etc/iframe-plugin.api.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,44 @@
44
55
```ts
66

7+
import { ComponentType } from 'react';
8+
import { ContainerProps } from 'react-native-render-html';
9+
import { HtmlAttributesDictionary } from 'react-native-render-html';
10+
import { PassProps } from 'react-native-render-html';
11+
import { default as React_2 } from 'react';
712
import { RendererFunction } from 'react-native-render-html';
13+
import { StyleProp } from 'react-native';
14+
import { ViewStyle } from 'react-native';
15+
16+
// @public
17+
export function extractHtmlIframeProps(htmlAttribs: HtmlAttributesDictionary, convertedCSSStyles: StyleProp<any>, passProps: PassProps<any>): HTMLIframeProps;
18+
19+
// @public
20+
export function HTMLIframe({ WebView, webViewProps: userWebViewProps, source, style, onLinkPress, htmlAttribs, scaleFactor, autoscale }: HTMLIframeProps): React_2.ReactElement<any, string | ((props: any) => React_2.ReactElement<any, string | any | (new (props: any) => React_2.Component<any, any, any>)> | null) | (new (props: any) => React_2.Component<any, any, any>)>;
21+
22+
// @public
23+
export interface HTMLIframeConfig {
24+
autoscale: boolean;
25+
}
26+
27+
// @public
28+
export interface HTMLIframeProps<WebViewProps = any> extends HTMLIframeConfig {
29+
// (undocumented)
30+
htmlAttribs: HtmlAttributesDictionary;
31+
// (undocumented)
32+
onLinkPress?: ContainerProps['onLinkPress'];
33+
scaleFactor: number;
34+
// (undocumented)
35+
source: {
36+
uri?: string;
37+
html?: string;
38+
};
39+
// (undocumented)
40+
style: StyleProp<ViewStyle>;
41+
WebView: ComponentType<WebViewProps>;
42+
// (undocumented)
43+
webViewProps?: WebViewProps;
44+
}
845

946
// @public
1047
const iframe: RendererFunction<any>;

packages/iframe-plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"typescript": "~3.9.7"
6060
},
6161
"dependencies": {
62-
"@formidable-webview/webshell": "^2.1.0",
62+
"@formidable-webview/webshell": "^2.2.0",
6363
"@types/prop-types": "^15.7.3",
6464
"prop-types": "^15.7.2"
6565
},
Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,98 @@
11
import React, { ComponentType, useCallback, useMemo } from 'react';
2-
import makeWebshell, {
2+
import {
33
HandleLinkPressFeature,
4-
LinkPressTarget
4+
ForceResponsiveViewportFeature,
5+
LinkPressTarget,
6+
useWebshell
57
} from '@formidable-webview/webshell';
68
import { StyleProp, ViewStyle } from 'react-native';
79
import {
810
ContainerProps,
911
HtmlAttributesDictionary
1012
} from 'react-native-render-html';
1113

12-
export interface HTMLIframeProps<WebViewProps = any> {
14+
/**
15+
* Configuration options for the HTMLIframe component.
16+
* You can pass those options through `renderersProps.iframe`
17+
* HTML prop.
18+
*
19+
* @public
20+
*/
21+
export interface HTMLIframeConfig {
1322
/**
14-
* The `WebView` Component you wish to use.
23+
* When the iframe attribute width is wider than the contentWidth, scales
24+
* down the viewport so that it doesn't overflows horizontally.
25+
*
26+
* @defaultvalue true
1527
*/
16-
WebView: ComponentType<WebViewProps>;
28+
autoscale: boolean;
29+
}
30+
31+
/**
32+
* Props for the HTMLIframe component.
33+
*
34+
* @public
35+
*/
36+
export interface HTMLIframeProps<WebViewProps = any> extends HTMLIframeConfig {
1737
/**
18-
* Any props you'd like to pass to {@link TableConfig.WebView}.
19-
*
20-
* @remarks
21-
* `source` and `javascriptEnabled` will be ignored and overriden. Also, you
22-
* should pass a stable or memoized object to avoid extraneous renderings.
23-
* See `React.useMemo`.
38+
* The `WebView` Component you wish to use.
2439
*/
40+
WebView: ComponentType<WebViewProps>;
2541
webViewProps?: WebViewProps;
2642
source: { uri?: string; html?: string };
27-
key: string;
2843
style: StyleProp<ViewStyle>;
2944
onLinkPress?: ContainerProps['onLinkPress'];
3045
htmlAttribs: HtmlAttributesDictionary;
46+
/**
47+
* When autoscale is enabled, scales the WebView zoom level to make sure the
48+
* viewport fits contentWidth.
49+
*/
50+
scaleFactor: number;
3151
}
3252

53+
const features = [new HandleLinkPressFeature({ preventDefault: true })];
54+
55+
/**
56+
* A component to render iframes in react-native-render-html.
57+
*
58+
* @public
59+
*/
3360
export default function HTMLIframe({
3461
WebView,
35-
webViewProps,
62+
webViewProps: userWebViewProps,
3663
source,
3764
style,
38-
key,
3965
onLinkPress,
40-
htmlAttribs
66+
htmlAttribs,
67+
scaleFactor,
68+
autoscale = true
4169
}: HTMLIframeProps) {
42-
const Webshell = useMemo(
70+
const scaleFeature = useMemo(
4371
() =>
44-
makeWebshell(
45-
WebView,
46-
new HandleLinkPressFeature({ preventDefault: true })
47-
),
48-
[WebView]
72+
autoscale
73+
? new ForceResponsiveViewportFeature({
74+
initScale: scaleFactor,
75+
maxScale: scaleFactor,
76+
minScale: scaleFactor
77+
})
78+
: null,
79+
[scaleFactor, autoscale]
4980
);
5081
const onDOMLinkPress = useCallback(
5182
({ uri }: LinkPressTarget) =>
5283
onLinkPress?.call(null, { nativeEvent: {} } as any, uri, htmlAttribs),
5384
[onLinkPress, htmlAttribs]
5485
);
55-
return (
56-
<Webshell
57-
testID="iframe"
58-
key={key}
59-
source={source}
60-
style={style}
61-
onDOMLinkPress={onDOMLinkPress}
62-
{...webViewProps}
63-
/>
64-
);
86+
const webViewProps = useWebshell({
87+
features: [...features, scaleFeature as any],
88+
props: {
89+
...userWebViewProps,
90+
onDOMLinkPress,
91+
style,
92+
source,
93+
testID: 'iframe',
94+
allowsFullscreenVideo: true
95+
}
96+
});
97+
return React.createElement(WebView, webViewProps);
6598
}
Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
1-
import React from 'react';
2-
import { Dimensions, StyleSheet } from 'react-native';
3-
import { RendererFunction, constructStyles } from 'react-native-render-html';
1+
import { Dimensions, StyleProp, StyleSheet } from 'react-native';
2+
import {
3+
constructStyles,
4+
HtmlAttributesDictionary,
5+
PassProps
6+
} from 'react-native-render-html';
47
import extractPrintDimensions from './extractPrintDimensions';
5-
import HTMLIframe from './HTMLIframe';
8+
import { HTMLIframeProps } from './HTMLIframe';
69

710
function normalizeUri(uri: string): string {
811
return uri.startsWith('//') ? `https:${uri}` : uri;
912
}
1013

1114
/**
12-
* The renderer function for the iframe element. This renderer is fully
13-
* scalable, and will adjust to `contentWidth` and `computeEmbeddedMaxWidth`.
14-
* It also features `onLinkPress`.
15+
* Extract props for the HTMLIframe component from renderer function arguments.
16+
* This function is especially usefull for custom iframe renderers.
1517
*
16-
* @param htmlAttribs - HTML attributes of the element.
17-
* @param children - The children (ignored)
18-
* @param convertedCSSStyles - Inline styles
19-
* @param passProps - Passed props from the root component.
18+
* @param htmlAttribs - The HTML node attributes.
19+
* @param convertedCSSStyles - Converted inline styles.
20+
* @param passProps - Passed props.
2021
*
2122
* @public
2223
*/
23-
const iframe: RendererFunction<any> = function iframe(
24-
htmlAttribs,
25-
children,
26-
convertedCSSStyles,
27-
passProps
28-
) {
24+
export default function extractHtmlIframeProps(
25+
htmlAttribs: HtmlAttributesDictionary,
26+
convertedCSSStyles: StyleProp<any>,
27+
passProps: PassProps<any>
28+
): HTMLIframeProps {
2929
const {
3030
WebView,
3131
contentWidth,
3232
onLinkPress,
3333
computeEmbeddedMaxWidth,
34-
defaultWebViewProps
34+
defaultWebViewProps,
35+
key,
36+
renderersProps: { iframe: iframeConfig }
3537
} = passProps;
3638
const resolvedContentWidth =
3739
typeof contentWidth === 'number'
@@ -53,13 +55,19 @@ const iframe: RendererFunction<any> = function iframe(
5355

5456
const attrWidth = Number(htmlAttribs.width);
5557
const attrHeight = Number(htmlAttribs.height);
56-
const { printWidth, printHeight } = extractPrintDimensions({
58+
const printConfig = {
5759
attrWidth: Number.isNaN(attrWidth) ? null : attrWidth,
5860
attrHeight: Number.isNaN(attrHeight) ? null : attrHeight,
5961
styleWidth: width,
6062
styleHeight: height,
6163
contentWidth: availableWidth
62-
});
64+
};
65+
const { printWidth, printHeight } = extractPrintDimensions(printConfig);
66+
const scaleFactor =
67+
typeof printConfig.attrWidth === 'number' &&
68+
printConfig.attrWidth > printWidth
69+
? printWidth / attrWidth
70+
: 1;
6371

6472
const source = htmlAttribs.srcdoc
6573
? { html: htmlAttribs.srcdoc as string }
@@ -70,18 +78,15 @@ const iframe: RendererFunction<any> = function iframe(
7078
"@native-html/iframe-plugin: You must pass a WebView component from react-native-webview as a prop to the HTML component. The iframe won't be rendered."
7179
);
7280
}
73-
74-
return WebView ? (
75-
<HTMLIframe
76-
key={passProps.key}
77-
source={source}
78-
style={[restStyle, { width: printWidth, height: printHeight }]}
79-
WebView={WebView}
80-
htmlAttribs={htmlAttribs}
81-
onLinkPress={onLinkPress}
82-
webViewProps={defaultWebViewProps}
83-
/>
84-
) : null;
85-
};
86-
87-
export default iframe;
81+
return {
82+
...iframeConfig,
83+
key,
84+
source,
85+
onLinkPress,
86+
htmlAttribs,
87+
scaleFactor,
88+
style: [restStyle, { width: printWidth, height: printHeight }],
89+
webViewProps: defaultWebViewProps,
90+
WebView
91+
};
92+
}

packages/iframe-plugin/src/iframe.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import { RendererFunction } from 'react-native-render-html';
3+
import extractHtmlIframeProps from './extractHtmlIframeProps';
4+
import HTMLIframe from './HTMLIframe';
5+
6+
/**
7+
* The renderer function for the iframe element. This renderer is fully
8+
* scalable, and will adjust to `contentWidth` and `computeEmbeddedMaxWidth`.
9+
* It also features `onLinkPress`.
10+
*
11+
* @param htmlAttribs - HTML attributes of the element.
12+
* @param children - The children (ignored)
13+
* @param convertedCSSStyles - Inline styles
14+
* @param passProps - Passed props from the root component.
15+
*
16+
* @public
17+
*/
18+
const iframe: RendererFunction<any> = function iframe(
19+
htmlAttribs,
20+
children,
21+
convertedCSSStyles,
22+
passProps
23+
) {
24+
const props = extractHtmlIframeProps(
25+
htmlAttribs,
26+
convertedCSSStyles,
27+
passProps
28+
);
29+
30+
return props.WebView ? React.createElement(HTMLIframe, props) : null;
31+
};
32+
33+
export default iframe;

packages/iframe-plugin/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { default } from './iframe';
2+
export { default as extractHtmlIframeProps } from './extractHtmlIframeProps';
3+
export { default as HTMLIframe } from './HTMLIframe';
4+
export type { HTMLIframeProps, HTMLIframeConfig } from './HTMLIframe';

0 commit comments

Comments
 (0)