Skip to content

Commit

Permalink
feat: a revamped scalable HTMLImage component
Browse files Browse the repository at this point in the history
BREAKING: imagesMaxWidth prop is discontinued in favor of contentWidth and
computeImagesMaxWidth. See RFC001 for an exhaustive description.

This patch offers a rewrite of the HTMLImage component to get a close
match with RFC001, “a deterministic approach to images scaling”. The only
part of this RFC which is unsupported is the unitConverter behavior, which
is planned for a later major release.

In addition to the capabilities defined in the RFC, this patch provides
the following features and behaviors:

- new property enableExperimentalPercentWidth. It allows percent width
  for <img> tags, computed relatively to contentWidth.
- take margins into account when scaling down images;
- support for overriding image styles, including resizeMode;
- support for minWidth, minHeight, maxWidth, maxHeight styles.

This patch also fixes #141, #172 and provides the features offered in
PR #242 and #315.

OPTIMIZATIONS: The imageBoxDimensions are computed when required. In
addition, requirements are also recomputed when necessary, preventing
expensive operations from happening too often. Also, because we need to
flatten the style prop to infer requirements, this flatten value is now
cached and re-evaluated when appropriate. Finally, styles have been
moved to a stylesheet when that is possible, to avoid commiting updates
to the native side. Note that these performance optimizations are made
possible by the high coverage rate of the HTMLImage component.

fixes #141
fixes #172
closes #315
closes #242
  • Loading branch information
jsamr committed Sep 26, 2020
1 parent 4ca0312 commit 0d3cfcf
Show file tree
Hide file tree
Showing 10 changed files with 999 additions and 305 deletions.
93 changes: 45 additions & 48 deletions README.md

Large diffs are not rendered by default.

32 changes: 23 additions & 9 deletions src/HTML.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ export default class HTML extends PureComponent {
customWrapper: PropTypes.func,
onLinkPress: PropTypes.func,
onParsed: PropTypes.func,
imagesMaxWidth: PropTypes.number,
computeImagesMaxWidth: PropTypes.func,
staticContentMaxWidth: PropTypes.number,
contentWidth: PropTypes.number,
enableExperimentalPercentWidth: PropTypes.bool,
imagesInitialDimensions: PropTypes.shape({
width: PropTypes.number,
height: PropTypes.number
Expand All @@ -57,8 +59,9 @@ export default class HTML extends PureComponent {
decodeEntities: true,
emSize: 14,
ptSize: 1.3,
contentWidth: Dimensions.get('window').width,
staticContentMaxWidth: Dimensions.get('window').width,
imagesMaxWidth: Dimensions.get('window').width,
enableExperimentalPercentWidth: false,
ignoredTags: IGNORED_TAGS,
ignoredStyles: [],
baseFontStyle: { fontSize: 14 },
Expand Down Expand Up @@ -86,15 +89,30 @@ export default class HTML extends PureComponent {
componentDidMount () {
this.mounted = true;
this.registerDOM();
if (__DEV__ && typeof this.props.contentWidth !== 'number') {
console.warn(
"You should always pass contentWidth prop to properly handle screen rotations " +
"and have a seemless support for images scaling. " +
"In the meantime, HTML will fallback to Dimensions.window().width, but its " +
"layout will become inconsistent after screen rotations. " +
"You are encouraged to use useWindowDimensions hook, see: " +
"https://reactnative.dev/docs/usewindowdimensions"
);
}
}

componentWillUnmount() {
this.mounted = false;
}

componentDidUpdate(prevProps, prevState) {
const { html, uri, renderers, tagsStyles, classesStyles } = prevProps;
let doParseDOM = false;
const { html, uri, renderers, tagsStyles, classesStyles, contentWidth, staticContentMaxWidth, computeImagesMaxWidth } = prevProps;
let shouldParseDOM = tagsStyles !== this.props.tagsStyles ||
classesStyles !== this.props.classesStyles ||
contentWidth !== this.props.contentWidth ||
staticContentMaxWidth !== this.props.staticContentMaxWidth ||
computeImagesMaxWidth !== this.props.computeImagesMaxWidth ||
this.state.dom !== prevState.dom;

this.generateDefaultStyles(this.props.baseFontStyle);
if (renderers !== this.props.renderers) {
Expand All @@ -104,11 +122,7 @@ export default class HTML extends PureComponent {
// If the source changed, register the new HTML and parse it
this.registerDOM(this.props);
}
if (tagsStyles !== this.props.tagsStyles || classesStyles !== this.props.classesStyles) {
// If the tagsStyles changed, render again
this.parseDOM(this.state.dom, this.props);
}
if (this.state.dom !== prevState.dom) {
if (shouldParseDOM) {
this.parseDOM(this.state.dom, this.props);
}
}
Expand Down
Loading

0 comments on commit 0d3cfcf

Please sign in to comment.