├── .editorconfig
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .husky
├── .gitignore
├── commit-msg
└── pre-commit
├── .npmignore
├── .npmrc
├── .prettierignore
├── .yarnrc
├── AnimatableImage.js
├── AutoHeightImage.js
├── CHANGELOG.md
├── CITATION.cff
├── CONTRIBUTING.md
├── ErrorableImage.js
├── ExampleApp
├── .expo-shared
│ └── assets.json
├── .gitignore
├── .watchmanconfig
├── App.js
├── app.json
├── assets
│ ├── icon.png
│ ├── image.png
│ └── splash.png
├── babel.config.js
├── package.json
└── yarn.lock
├── ImagePolyfill.js
├── LICENSE
├── README.md
├── cache.js
├── helpers.js
├── index.d.ts
├── index.js
├── package.json
├── renovate.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | curly_bracket_next_line = false
11 | spaces_around_operators = true
12 | indent_brace_style = 1tbs
13 |
14 | [*.js]
15 | quote_type = single
16 |
17 | [*.{html,less,css,json}]
18 | quote_type = double
19 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: vivaxy
2 | open_collective: react-native-auto-height-image
3 | custom: ['https://gist.github.com/vivaxy/58eed1803a2eddda05c90aed99430de2']
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Codes:
13 | ```js
14 | ....
15 | ```
16 | 2. Click on '....'
17 | 3. See error
18 |
19 | **Expected behavior**
20 | A clear and concise description of what you expected to happen.
21 |
22 | **Screenshots**
23 | If applicable, add screenshots to help explain your problem.
24 |
25 | **Dependencies versions (please complete the following information):**
26 | - react:
27 | - react-native:
28 |
29 | **Additional context**
30 | Add any other context about the problem here.
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 | /build
4 | node_modules
5 | npm-debug.log
6 | yarn-error.log
7 |
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn lint-staged
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | .DS_Store
4 | npm-debug.log
5 | .editorconfig
6 | /ExampleApp
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org/
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | CHANGELOG.md
2 | README.md
3 | package.json
4 | ExampleApp/app.json
5 |
--------------------------------------------------------------------------------
/.yarnrc:
--------------------------------------------------------------------------------
1 | --registry "https://registry.npmjs.org/"
2 |
--------------------------------------------------------------------------------
/AnimatableImage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Animated, Image, ImageBackground } from 'react-native';
4 |
5 | function AnimatableImage(props) {
6 | const { animated, children, ...rest } = props;
7 |
8 | const ImageComponent = children
9 | ? ImageBackground
10 | : animated
11 | ? Animated.Image
12 | : Image;
13 |
14 | return {children};
15 | }
16 |
17 | AnimatableImage.propTypes = Image.propTypes | Animated.Image.propTypes;
18 |
19 | AnimatableImage.defaultProps = {
20 | animated: false
21 | };
22 |
23 | export default AnimatableImage;
24 |
--------------------------------------------------------------------------------
/AutoHeightImage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @since 2017-04-11 19:10:08
3 | * @author vivaxy
4 | */
5 | import React, { useEffect, useState, useRef } from 'react';
6 | import ImagePolyfill from './ImagePolyfill';
7 | import AnimatableImage from './AnimatableImage';
8 | import PropTypes from 'prop-types';
9 |
10 | import { getImageSizeFitWidth, getImageSizeFitWidthFromCache } from './cache';
11 | import { NOOP, DEFAULT_HEIGHT } from './helpers';
12 |
13 | // remove `resizeMode` props from `Image.propTypes`
14 | const { resizeMode, ...ImagePropTypes } = AnimatableImage.propTypes;
15 |
16 | function AutoHeightImage(props) {
17 | const {
18 | onHeightChange,
19 | source,
20 | width,
21 | style,
22 | maxHeight,
23 | onError,
24 | ...rest
25 | } = props;
26 | const [height, setHeight] = useState(
27 | getImageSizeFitWidthFromCache(source, width, maxHeight).height ||
28 | DEFAULT_HEIGHT
29 | );
30 | const mountedRef = useRef(false);
31 |
32 | useEffect(function () {
33 | mountedRef.current = true;
34 | return function () {
35 | mountedRef.current = false;
36 | };
37 | }, []);
38 |
39 | useEffect(
40 | function () {
41 | (async function () {
42 | try {
43 | const { height: newHeight } = await getImageSizeFitWidth(
44 | source,
45 | width,
46 | maxHeight
47 | );
48 | if (mountedRef.current) {
49 | // might trigger `onHeightChange` with same `height` value
50 | // dedupe maybe?
51 | setHeight(newHeight);
52 | onHeightChange(newHeight);
53 | }
54 | } catch (e) {
55 | onError(e);
56 | }
57 | })();
58 | },
59 | [source, onHeightChange, width, maxHeight]
60 | );
61 |
62 | // StyleSheet.create will cache styles, not what we want
63 | const imageStyles = { width, height };
64 |
65 | // Since it only makes sense to use polyfill with remote images
66 | const ImageComponent = source.uri ? ImagePolyfill : AnimatableImage;
67 | return (
68 |
74 | );
75 | }
76 |
77 | AutoHeightImage.propTypes = {
78 | ...ImagePropTypes,
79 | width: PropTypes.number.isRequired,
80 | maxHeight: PropTypes.number,
81 | onHeightChange: PropTypes.func,
82 | animated: PropTypes.bool
83 | };
84 |
85 | AutoHeightImage.defaultProps = {
86 | maxHeight: Infinity,
87 | onHeightChange: NOOP,
88 | animated: false
89 | };
90 |
91 | export default AutoHeightImage;
92 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### [3.2.4](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.2.3...v3.2.4) (2021-02-04)
6 |
7 |
8 | ### Features
9 |
10 | * supports `ImageBackground` [@SoniaComp](https://github.com/SoniaComp)
11 |
12 | ### [3.2.3](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.2.2...v3.2.3) (2020-10-17)
13 |
14 |
15 | ### Bug Fixes
16 |
17 | * **deps:** update dependency expo to v39 ([9cf60e4](https://github.com/vivaxy/react-native-auto-height-image/commit/9cf60e4798742a4ef648cc39cd96af6380b7180e))
18 | * **deps:** update dependency react to v16.14.0 ([ed45e7e](https://github.com/vivaxy/react-native-auto-height-image/commit/ed45e7ebf50b677ccdc501a01ae813258660cfc6))
19 | * **deps:** update dependency react-native-web to ^0.14.0 ([1ad617f](https://github.com/vivaxy/react-native-auto-height-image/commit/1ad617fa514cb307fc72a3c34e8254843e19d9d0))
20 |
21 | ### [3.2.2](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.2.1...v3.2.2) (2020-07-25)
22 |
23 |
24 | ### Bug Fixes
25 |
26 | * **deps:** update dependency expo to v38 ([6b24bd8](https://github.com/vivaxy/react-native-auto-height-image/commit/6b24bd8c1a2f1bf7fafcb0ba3c7b558318d7d152))
27 | * **deps:** update dependency react-native-web to ^0.13.0 ([82d6270](https://github.com/vivaxy/react-native-auto-height-image/commit/82d6270e7e45855864fcc4fcf1ec62ee97695300))
28 |
29 | ### [3.2.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.2.0...v3.2.1) (2020-06-08)
30 |
31 | ## [3.2.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.1.3...v3.2.0) (2020-05-27)
32 |
33 |
34 | ### Features
35 |
36 | * :sparkles: support `maxHeight` prop, reuse image cache on initial rendering to optimize the performance ([e5055c8](https://github.com/vivaxy/react-native-auto-height-image/commit/e5055c8e97a800581d7049140392cdedad035f48))
37 |
38 | ### [3.1.3](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.1.2...v3.1.3) (2020-05-07)
39 |
40 |
41 | ### Bug Fixes
42 |
43 | * :bug: fix `Can't perform a React state update on an unmounted component.` ([035e6a8](https://github.com/vivaxy/react-native-auto-height-image/commit/035e6a86ba39daf3c16d75d7467f925d94537023)), closes [#44](https://github.com/vivaxy/react-native-auto-height-image/issues/44)
44 |
45 | ### [3.1.2](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.1.1...v3.1.2) (2020-04-18)
46 |
47 |
48 | ### Bug Fixes
49 |
50 | * add missing symbol ([7498b82](https://github.com/vivaxy/react-native-auto-height-image/commit/7498b823bb8ac8a0f1f509fb0f083a61e57e192d))
51 |
52 | ### [3.1.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.1.0...v3.1.1) (2020-04-04)
53 |
54 |
55 | ### Bug Fixes
56 |
57 | * android crash at imagePolyfill ([21dc084](https://github.com/vivaxy/react-native-auto-height-image/commit/21dc0841c452a4178202db1beedfc7e2e72d7665))
58 |
59 | ## [3.1.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v3.0.0...v3.1.0) (2020-03-31)
60 |
61 |
62 | ### Features
63 |
64 | * animated image support ([97ff786](https://github.com/vivaxy/react-native-auto-height-image/commit/97ff786c40143599228524c1b12d4e29ba496e57))
65 |
66 | ## [3.0.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v2.0.0...v3.0.0) (2020-01-17)
67 |
68 |
69 | ### ⚠ BREAKING CHANGES
70 |
71 | * **changelog:** Drop support for react before 16.8 and react-native before 0.59
72 |
73 | * **changelog:** :memo: commit a breaking change ([03c9b81](https://github.com/vivaxy/react-native-auto-height-image/commit/03c9b81))
74 |
75 |
76 | ### Bug Fixes
77 |
78 | * fix for fallback images ([d825375](https://github.com/vivaxy/react-native-auto-height-image/commit/d825375))
79 |
80 |
81 | ### Features
82 |
83 | * **deps:** bumped React to ^16.8 & React Native to ^0.59.0 ([24edbc2](https://github.com/vivaxy/react-native-auto-height-image/commit/24edbc2))
84 |
85 | ## [2.0.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.1.3...v2.0.0) (2020-01-09)
86 |
87 |
88 | ### ⚠ BREAKING CHANGES
89 |
90 | * incorporated imagepolyfill in codebase, removed from deps
91 |
92 | ### Features
93 |
94 | * incorporated imagepolyfill in codebase, removed from deps ([bfdca6f](https://github.com/vivaxy/react-native-auto-height-image/commit/bfdca6f))
95 |
96 |
97 | ## [1.1.3](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.1.2...v1.1.3) (2019-10-16)
98 |
99 |
100 |
101 |
102 | ## [1.1.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.1.0...v1.1.1) (2019-08-13)
103 |
104 |
105 | ### Reverts
106 |
107 | * **open collective:** :rewind: revert changes to package.json ([37f3b17](https://github.com/vivaxy/react-native-auto-height-image/commit/37f3b17))
108 |
109 |
110 |
111 |
112 | # [1.1.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.5...v1.1.0) (2019-03-07)
113 |
114 |
115 | ### Features
116 |
117 | * :sparkles:updateImageHeight with safe check ([a2c9275](https://github.com/vivaxy/react-native-auto-height-image/commit/a2c9275))
118 |
119 |
120 |
121 |
122 | ## [1.0.5](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.4...v1.0.5) (2018-10-22)
123 |
124 |
125 | ### Bug Fixes
126 |
127 | * :bug:Fix updating the image size after change of the source ([cfe1566](https://github.com/vivaxy/react-native-auto-height-image/commit/cfe1566))
128 |
129 |
130 |
131 |
132 | ## [1.0.4](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.3...v1.0.4) (2018-10-09)
133 |
134 |
135 | ### Bug Fixes
136 |
137 | * :bug:Remove trailing comma ([89713a5](https://github.com/vivaxy/react-native-auto-height-image/commit/89713a5))
138 |
139 |
140 |
141 |
142 | ## [1.0.3](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.2...v1.0.3) (2018-10-09)
143 |
144 |
145 | ### Features
146 |
147 | * Allowing Image props.
148 |
149 |
150 |
151 |
152 | ## [1.0.2](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.1...v1.0.2) (2018-10-07)
153 |
154 |
155 | ### Features
156 |
157 | * Add type definitions.
158 |
159 |
160 |
161 |
162 | ## [1.0.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v1.0.0...v1.0.1) (2018-07-13)
163 |
164 |
165 | ### Features
166 |
167 | * Reformat codes.
168 |
169 |
170 |
171 |
172 | # [1.0.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.4.0...v1.0.0) (2018-01-18)
173 |
174 |
175 | ### Features
176 |
177 | * Support local images and fallback sources.
178 |
179 |
180 | ### Breaking changes.
181 |
182 | * Remove `imageURL`, use `source` instead.
183 |
184 |
185 |
186 |
187 | # [0.4.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.3.4...v0.4.0) (2018-01-16)
188 |
189 |
190 | ### Features
191 |
192 | * **onError:** :sparkles:Propagate errors to onError ([4d9a14d](https://github.com/vivaxy/react-native-auto-height-image/commit/4d9a14d))
193 |
194 |
195 |
196 |
197 | ## [0.3.4](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.3.3...v0.3.4) (2017-12-20)
198 |
199 |
200 | ### Features
201 |
202 | * Update image size on width change. ([7a09dc0](https://github.com/vivaxy/react-native-auto-height-image/commit/7a09dc0))
203 |
204 |
205 |
206 |
207 | ## [0.3.3](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.3.2...v0.3.3) (2017-08-22)
208 |
209 |
210 | ### Features
211 |
212 | * Optimize error handling from `Image.getSize`. ([80158e7](https://github.com/vivaxy/react-native-auto-height-image/commit/80158e7))
213 |
214 |
215 |
216 |
217 | ## [0.3.2](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.3.1...v0.3.2) (2017-08-22)
218 |
219 |
220 | ### Bug Fixes
221 |
222 | * **rejection:** :bug:Fix `Possible Unhandled Promise Rejection` warning. ([02441ba](https://github.com/vivaxy/react-native-auto-height-image/commit/02441ba)), closes [#4](https://github.com/vivaxy/react-native-auto-height-image/issues/4)
223 |
224 |
225 |
226 |
227 | ## [0.3.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.3.0...v0.3.1) (2017-08-08)
228 |
229 |
230 | ### Bug Fixes
231 |
232 | * :bug:Fixed syntax error in index.js. ([c384cd6](https://github.com/vivaxy/react-native-auto-height-image/commit/c384cd6))
233 |
234 |
235 |
236 |
237 | # [0.3.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.2.2...v0.3.0) (2017-07-31)
238 |
239 |
240 | ### Features
241 |
242 | * **onHeightChange:** :sparkles:Provides a new api to extract the calculated height. ([18c86e6](https://github.com/vivaxy/react-native-auto-height-image/commit/18c86e6))
243 |
244 |
245 |
246 |
247 | ## [0.2.2](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.2.1...v0.2.2) (2017-05-27)
248 |
249 |
250 | ### Documents
251 |
252 | * Update documents.
253 |
254 |
255 |
256 |
257 | ## [0.2.1](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.2.0...v0.2.1) (2017-04-24)
258 |
259 |
260 | ### Bug Fixes
261 |
262 | * :bug:Fix hasLoaded logic ([1b8264c](https://github.com/vivaxy/react-native-auto-height-image/commit/1b8264c))
263 |
264 |
265 |
266 |
267 | # [0.2.0](https://github.com/vivaxy/react-native-auto-height-image/compare/v0.1.0...v0.2.0) (2017-04-24)
268 |
269 |
270 | ### Features
271 |
272 | * :sparkles:Support all image props ([4088b73](https://github.com/vivaxy/react-native-auto-height-image/commit/4088b73))
273 |
274 |
275 |
276 |
277 | # 0.1.0 (2017-04-24)
278 |
279 |
280 | ### Features
281 |
282 | * :tada:First Commit ([243c394](https://github.com/vivaxy/react-native-auto-height-image/commit/243c394))
283 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.1.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: Xu
5 | given-names: Ye
6 | orcid: https://doi.org/10.5281/zenodo.7813210
7 | title: vivaxy/react-native-auto-height-image
8 | version: v3.2.4
9 | date-released: 2023-04-10
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to initialize project?
2 |
3 | * Clone this repository.
4 | * Run `yarn install`. (Install `yarn` globally.)
5 | * Make sure you have `watchman` installed. (If not, run `brew install watchman`.)
6 |
7 | # How to run ExampleApp?
8 |
9 | * Run `cd ExampleApp`.
10 | * Run `yarn install`.
11 | * Run `yarn start`.
12 |
13 | # How to make a change?
14 |
15 | * Supply a proper test case and test your changes in ExampleApp.
16 | * Git commit with [Conventional Commits](https://conventionalcommits.org/).
17 | * Bump version and publish with `npm run release`. This will update `CHANGELOG.md` automatically.
18 |
19 | # How to release a beta/test version?
20 |
21 | * Run `yarn release:beta`.
22 |
23 | # How to release a stable version?
24 |
25 | * Run `yarn release`.
26 |
--------------------------------------------------------------------------------
/ErrorableImage.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import AutoHeightImage from './AutoHeightImage';
4 |
5 | function ErrorableImage(props) {
6 | const { source, fallbackSource, onError, ...rest } = props;
7 |
8 | const [error, setError] = useState(false);
9 |
10 | const shouldUseFallbackSource = error && fallbackSource;
11 |
12 | return (
13 | {
16 | // if an error hasn't already been seen, try to load the error image
17 | // instead
18 | if (!error) {
19 | setError(true);
20 | }
21 |
22 | // also propagate to error handler if it is specified
23 | onError && onError(_e);
24 | }}
25 | {...rest}
26 | />
27 | );
28 | }
29 |
30 | export default ErrorableImage;
31 |
--------------------------------------------------------------------------------
/ExampleApp/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "f9155ac790fd02fadcdeca367b02581c04a353aa6d5aa84409a59f6804c87acd": true,
3 | "89ed26367cdb9b771858e026f2eb95bfdb90e5ae943e716575327ec325f39c44": true
4 | }
5 |
--------------------------------------------------------------------------------
/ExampleApp/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 | web-report/
12 |
--------------------------------------------------------------------------------
/ExampleApp/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/ExampleApp/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import AutoHeightImage from 'react-native-auto-height-image';
3 | import {
4 | StyleSheet,
5 | Text,
6 | ScrollView,
7 | TextInput,
8 | Animated
9 | } from 'react-native';
10 |
11 | import image from './assets/image.png';
12 |
13 | export default class App extends Component {
14 | state = {
15 | dynamicWidth: 200,
16 | fadeAnim: new Animated.Value(0)
17 | };
18 |
19 | handleTextInputChange = (text) => {
20 | const width = Number(text);
21 | if (!Number.isNaN(width)) {
22 | this.setState({ dynamicWidth: width });
23 | }
24 | };
25 |
26 | fadeIn = () => {
27 | Animated.timing(this.state.fadeAnim, {
28 | toValue: 1,
29 | duration: 5000,
30 | useNativeDriver: true
31 | }).start();
32 | };
33 |
34 | componentDidMount() {
35 | this.fadeIn();
36 | }
37 |
38 | render() {
39 | const { dynamicWidth } = this.state;
40 | return (
41 |
45 |
51 | Basic example
52 |
56 | Basic example with local image
57 |
58 | Basic example with dynamic width
59 |
64 | Basic example with dynamic width and local image
65 |
66 | Wrong image
67 | {
71 | console.log('----- onError', error);
72 | }}
73 | />
74 | Wrong image with fallback
75 | {
80 | console.log('----- onError', error);
81 | }}
82 | />
83 | Wrong image with local fallback
84 | {
89 | console.log('----- onError', error);
90 | }}
91 | />
92 | AnimatableImage
93 |
107 | ImageBackground
108 |
115 |
116 | You can make any Child Component!
117 |
118 |
119 |
120 | );
121 | }
122 | }
123 |
124 | const styles = StyleSheet.create({
125 | scrollViewContainer: {
126 | flex: 1,
127 | backgroundColor: '#fff',
128 | marginTop: 20
129 | },
130 | scrollViewContentContainer: {
131 | alignItems: 'center',
132 | paddingTop: 100
133 | },
134 | textInputStyle: {
135 | width: 300,
136 | height: 30,
137 | borderStyle: 'solid',
138 | borderColor: '#eee',
139 | borderWidth: 1
140 | },
141 | fadingContainer: {
142 | paddingVertical: 8,
143 | paddingHorizontal: 16,
144 | backgroundColor: 'powderblue'
145 | },
146 | textStyle: {
147 | color: 'white'
148 | }
149 | });
150 |
--------------------------------------------------------------------------------
/ExampleApp/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "ExampleApp for react-native-auto-height-image component",
4 | "slug": "example-app-for-react-native-auto-height-image-component",
5 | "privacy": "public",
6 | "version": "1.0.0",
7 | "orientation": "portrait",
8 | "icon": "./assets/icon.png",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "contain",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "updates": {
15 | "fallbackToCacheTimeout": 0
16 | },
17 | "assetBundlePatterns": [
18 | "**/*"
19 | ],
20 | "ios": {
21 | "supportsTablet": true
22 | },
23 | "description": "ExampleApp for react-native-auto-height-image component",
24 | "githubUrl": "https://github.com/vivaxy/react-native-auto-height-image/tree/master/ExampleApp"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ExampleApp/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vivaxy/react-native-auto-height-image/0bb6a33e5cf3ace67329e77a1dad75ae40e64c8d/ExampleApp/assets/icon.png
--------------------------------------------------------------------------------
/ExampleApp/assets/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vivaxy/react-native-auto-height-image/0bb6a33e5cf3ace67329e77a1dad75ae40e64c8d/ExampleApp/assets/image.png
--------------------------------------------------------------------------------
/ExampleApp/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vivaxy/react-native-auto-height-image/0bb6a33e5cf3ace67329e77a1dad75ae40e64c8d/ExampleApp/assets/splash.png
--------------------------------------------------------------------------------
/ExampleApp/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo']
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/ExampleApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject",
9 | "postinstall": "rm -rf ./node_modules/react-native-auto-height-image/node_modules && rm -rf ./node_modules/react-native-auto-height-image/ExampleApp"
10 | },
11 | "dependencies": {
12 | "expo": "~41.0.0",
13 | "react": "17.0.2",
14 | "react-dom": "17.0.2",
15 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.3.tar.gz",
16 | "react-native-auto-height-image": "file:..",
17 | "react-native-web": "~0.16.0"
18 | },
19 | "devDependencies": {
20 | "babel-preset-expo": "^8.0.0"
21 | },
22 | "private": true
23 | }
24 |
--------------------------------------------------------------------------------
/ImagePolyfill.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Platform, Image } from 'react-native';
3 | import AnimatableImage from './AnimatableImage';
4 |
5 | const isAndroid = () => Platform.OS === 'android';
6 |
7 | /**
8 | * An extension of the Image class which fixes an Android bug where remote images wouldn't fire the
9 | * Image#onError() callback when the image failed to load due to a 404 response.
10 | *
11 | * This component should only be used for loading remote images, not local resources.
12 | */
13 | function ImagePolyfill(props) {
14 | const { source, onError, ...rest } = props;
15 |
16 | const verifyImage = () => {
17 | const { uri } = source;
18 | Image.prefetch(uri).catch((e) => onError(e));
19 | };
20 |
21 | useEffect(() => {
22 | if (source && source.uri && onError && isAndroid()) {
23 | verifyImage();
24 | }
25 | }, [source, onError]);
26 |
27 | return ;
28 | }
29 |
30 | ImagePolyfill.propTypes = AnimatableImage.propTypes;
31 | ImagePolyfill.defaultProps = AnimatableImage.defaultProps;
32 |
33 | export default ImagePolyfill;
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 vivaxy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-auto-height-image
2 |
3 | Initialized by [vivaxy/gt-npm-package](https://github.com/vivaxy/gt-npm-package)
4 |
5 | [](https://www.npmjs.com/package/react-native-auto-height-image)
6 | [](https://www.npmjs.com/package/react-native-auto-height-image)
7 | [](./LICENSE)
8 | [](https://conventionalcommits.org)
9 | [](https://opencollective.com/react-native-auto-height-image)
10 | [](https://github.com/vivaxy/react-native-auto-height-image/issues/88)
11 | [](https://zenodo.org/badge/latestdoi/89235823)
12 |
13 | This component provides you a simple way to load a remote image and automatically set `Image` height to the image dimension which fits the provided width.
14 |
15 | React Native `Image` component needs users to set both `width` and `height` props.
16 |
17 | React Native version requirements: >=0.46.
18 |
19 | ## Installation
20 |
21 | `yarn add react-native-auto-height-image`
22 |
23 | `npm install react-native-auto-height-image`
24 |
25 | ## Usage
26 |
27 | Use local or remote files:
28 |
29 | ```js
30 | import React, { Component } from 'react';
31 | import AutoHeightImage from 'react-native-auto-height-image';
32 |
33 | import image from 'gallifrey-falls.png';
34 |
35 | export default class Demo extends Component {
36 | render() {
37 | return (
38 |
39 |
40 |
44 |
45 |
49 |
50 |
51 | );
52 | }
53 | }
54 | ```
55 |
56 | You can even specify fallback images for when the source fails to load:
57 |
58 | ```js
59 | import React, { Component } from 'react';
60 | import AutoHeightImage from 'react-native-auto-height-image';
61 |
62 | import image from 'gallifrey-falls.png';
63 |
64 | export default class Demo extends Component {
65 | render() {
66 | return (
67 |
72 | );
73 | }
74 | }
75 | ```
76 |
77 | ### Props
78 |
79 | | name | type | isRequired | default | description |
80 | | --- | --- | --- | --- | --- |
81 | | `width` | number | ✔ | N/A | image width to fit |
82 | | `maxHeight` | number | ✖ | `Infinity` | image max height |
83 | | `source` | number or object | ✔ | N/A | local (i.e. require/import) or remote image ({uri: '...'}) |
84 | | `fallbackSource` | number or object | ✖ | N/A | local (i.e. require/import) or remote image ({uri: '...'}) |
85 | | `onHeightChange` | func | ✖ | `(height) => {}` | called when updating image height, the argument `height` might be `0` |
86 | | `animated` | bool | ✖ | `false` | Use `Animated.Image` instead of `Image` |
87 |
88 | Other [image props](https://reactnative.dev/docs/image#props) except `resizeMode` are accepted.
89 |
90 | ## Change Log
91 |
92 | [Change log](./CHANGELOG.md)
93 |
94 | ## Contributing
95 |
96 | [Contributing](./CONTRIBUTING.md)
97 |
98 | ## Licence
99 |
100 | [MIT](./LICENSE)
101 |
102 | ## Contributors
103 |
104 | ### Code Contributors
105 |
106 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
107 |
108 |
109 | ### Financial Contributors
110 |
111 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/react-native-auto-height-image/contribute)]
112 |
113 | #### Individuals
114 |
115 |
116 |
117 | #### Organizations
118 |
119 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/react-native-auto-height-image/contribute)]
120 |
121 |
122 |
123 | ## Related Projects
124 |
125 | - [react-native-scalable-image](https://github.com/ihor/react-native-scalable-image)
126 | - [react-native-fit-image](https://github.com/huiseoul/react-native-fit-image)
127 | - [react-native-responsive-image-view](https://github.com/wKovacs64/react-native-responsive-image-view)
128 | - [react-native-auto-image](https://github.com/egorshulga/react-native-auto-image)
129 |
--------------------------------------------------------------------------------
/cache.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @since 2017-04-24 20:50:41
3 | * @author vivaxy
4 | */
5 |
6 | import { Image } from 'react-native';
7 | // undocumented but part of react-native; see
8 | // https://github.com/facebook/react-native/issues/5603#issuecomment-297959695
9 | import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
10 |
11 | /**
12 | * store with
13 | * key: image
14 | * value: {
15 | * width: 100,
16 | * height: 100,
17 | * }
18 | */
19 | const cache = new Map();
20 |
21 | const getImageSizeFromCache = (image) => {
22 | if (typeof image === 'number') {
23 | return cache.get(image);
24 | } else {
25 | return cache.get(image.uri);
26 | }
27 | };
28 |
29 | const loadImageSize = (image) => {
30 | return new Promise((resolve, reject) => {
31 | //number indicates import X or require(X) was used (i.e. local file)
32 | if (typeof image === 'number') {
33 | const { width, height } = resolveAssetSource(image);
34 | resolve({ width, height });
35 | } else {
36 | Image.getSize(
37 | image.uri,
38 | (width, height) => {
39 | // success
40 | resolve({ width, height });
41 | },
42 | reject
43 | );
44 | }
45 | });
46 | };
47 |
48 | export const getImageSizeFitWidthFromCache = (image, toWidth, maxHeight) => {
49 | const size = getImageSizeFromCache(image);
50 | if (size) {
51 | const { width, height } = size;
52 | if (!width || !height) return { width: 0, height: 0 };
53 | const scaledHeight = (toWidth * height) / width;
54 | return {
55 | width: toWidth,
56 | height: scaledHeight > maxHeight ? maxHeight : scaledHeight
57 | };
58 | }
59 | return {};
60 | };
61 |
62 | const getImageSizeMaybeFromCache = async (image) => {
63 | let size = getImageSizeFromCache(image);
64 | if (!size) {
65 | size = await loadImageSize(image);
66 | if (typeof image === 'number') {
67 | cache.set(image, size);
68 | } else {
69 | cache.set(image.uri, size);
70 | }
71 | }
72 | return size;
73 | };
74 |
75 | export const getImageSizeFitWidth = async (image, toWidth, maxHeight) => {
76 | const { width, height } = await getImageSizeMaybeFromCache(image);
77 | if (!width || !height) return { width: 0, height: 0 };
78 | const scaledHeight = (toWidth * height) / width;
79 | return {
80 | width: toWidth,
81 | height: scaledHeight > maxHeight ? maxHeight : scaledHeight
82 | };
83 | };
84 |
--------------------------------------------------------------------------------
/helpers.js:
--------------------------------------------------------------------------------
1 | export const NOOP = () => {};
2 | export const DEFAULT_HEIGHT = 0;
3 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ImageProps } from 'react-native';
3 |
4 | interface TSource {
5 | uri: string;
6 | }
7 |
8 | export interface AutoHeightImageProps extends ImageProps {
9 | source: number | TSource;
10 | width: number;
11 | maxHeight?: number;
12 | fallbackSource?: number | TSource;
13 | onHeightChange?: (height: number) => void;
14 | animated?: boolean;
15 | }
16 |
17 | declare class AutoHeightImage extends React.Component<
18 | AutoHeightImageProps,
19 | any
20 | > {}
21 |
22 | export default AutoHeightImage;
23 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import ErrorableImage from './ErrorableImage';
2 |
3 | export default ErrorableImage;
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-auto-height-image",
3 | "version": "3.2.4",
4 | "description": "react-native auto height image",
5 | "main": "./index.js",
6 | "typings": "./index.d.ts",
7 | "scripts": {
8 | "release": "standard-version && git push --follow-tags && npm publish",
9 | "release:beta": "standard-version --prerelease beta && git push --follow-tags && npm publish",
10 | "postinstall": "husky install",
11 | "prepublishOnly": "pinst --disable",
12 | "postpublish": "pinst --enable"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git@github.com:vivaxy/react-native-auto-height-image.git"
17 | },
18 | "keywords": [
19 | "react-native",
20 | "image",
21 | "auto-height",
22 | "react",
23 | "images"
24 | ],
25 | "author": "vivaxy",
26 | "license": "MIT",
27 | "dependencies": {
28 | "prop-types": "^15.7.2"
29 | },
30 | "devDependencies": {
31 | "@commitlint/cli": "^12.0.0",
32 | "@commitlint/config-conventional": "^12.0.0",
33 | "husky": "6",
34 | "lint-staged": "^11.0.0",
35 | "pinst": "^2.1.4",
36 | "prettier": "^2.0.0",
37 | "react": "^17.0.0",
38 | "react-native": "^0.64.0",
39 | "standard-version": "^9.0.0"
40 | },
41 | "peerDependencies": {
42 | "react": "^17.0.0",
43 | "react-native": "^0.64.0"
44 | },
45 | "lint-staged": {
46 | "**/**.{js,json,md,ts}": [
47 | "prettier --write",
48 | "git add"
49 | ]
50 | },
51 | "prettier": {
52 | "singleQuote": true,
53 | "trailingComma": "none",
54 | "arrowParens": "always"
55 | },
56 | "commitlint": {
57 | "extends": [
58 | "@commitlint/config-conventional"
59 | ],
60 | "rules": {
61 | "header-max-length": [
62 | 0,
63 | "never"
64 | ]
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base",
4 | ":preserveSemverRanges"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------