Skip to content
This repository was archived by the owner on Aug 19, 2022. It is now read-only.

Commit b3eb7a6

Browse files
authored
Merge pull request #25 from brybrophy/feature/delay-prop
#15 Feature/delay prop
2 parents 6485a92 + 6c00d82 commit b3eb7a6

File tree

8 files changed

+152
-84
lines changed

8 files changed

+152
-84
lines changed

README.md

+43-27
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55

66
[`react-progressive-image`](https://www.npmjs.com/package/react-progressive-image) React component for progressive image loading
77

8-
## Installation
9-
10-
Using [npm](https://www.npmjs.com/):
11-
12-
$ npm install --save react-progressive-image
8+
### Install
139

10+
```bash
11+
$ yarn add react-progressive-image
12+
```
1413

1514
The UMD build is also available on [unpkg](https://unpkg.com):
1615

@@ -20,50 +19,67 @@ The UMD build is also available on [unpkg](https://unpkg.com):
2019

2120
If you use the UMD build you can find the library on `window.ReactProgressiveImage`.
2221

23-
## Usage
22+
### Examples
2423

25-
`react-progressive-image` exports a single React component, `ProgressiveImage`, which takes a `src` and `placeholder` prop, as well as optional props `srcSetData`, and `onError` function.
24+
#### Simple
2625

27-
`src` should be the final image you want to load, and `placeholder` is the image you want to display until `src` is loaded. `placeholder` can be anything you want. A typical use case might involve using a smaller version of the image, an inlined version (data URI), or a loading graphic.
28-
29-
If you would like to supply a srcSet for the image, you can use the `srcSetData` prop. The prop should be and object containing two properties, `srcSet`, and `sizes`.
26+
```jsx
27+
<ProgressiveImage src="large-image.jpg" placeholder="tiny-image.jpg">
28+
{src => <img src={src} alt="an image" />}
29+
</ProgressiveImage>
30+
```
3031

31-
`ProgressiveImage` accepts a render callback as a child, which will be called with the `placeholder` first, and then `src` once the image has been loaded.
32+
#### With Delay
3233

3334
```jsx
34-
<ProgressiveImage src='large-image.jpg' placeholder='tiny-image.jpg'>
35-
{(src) => <img src={src} alt='an image'/>}
35+
<ProgressiveImage
36+
delay={3000}
37+
src="large-image.jpg"
38+
placeholder="tiny-image.jpg"
39+
>
40+
{src => <img src={src} alt="an image" />}
3641
</ProgressiveImage>
3742
```
3843

39-
It will also call the render callback with a second argument, `loading`, which you can use to quickly determine what image is being rendered. `loading` will be `true` when the placeholder is rendered, and `false` when the full image is rendered.
44+
#### With loading argment
4045

4146
```jsx
42-
<ProgressiveImage src='large-image.jpg' placeholder='tiny-image.jpg'>
47+
<ProgressiveImage src="large-image.jpg" placeholder="tiny-image.jpg">
4348
{(src, loading) => (
44-
<img style={{ opacity: loading ? 0.5 : 1 }} src={src} alt='an image'/>
49+
<img style={{ opacity: loading ? 0.5 : 1 }} src={src} alt="an image" />
4550
)}
4651
</ProgressiveImage>
4752
```
4853

49-
If the `srcSetData` prop is supplied, it will be returned as the third argument to the render callback. This is helpful if you are sharing a render function between multiple different `ProgressiveImage` components.
54+
#### With srcSet
5055

5156
```jsx
52-
<ProgressiveImage
53-
src='medium.jpg'
57+
<ProgressiveImage
58+
src="medium.jpg"
5459
srcSetData={{
5560
srcSet: 'small.jpg 320w, medium.jpg 700w, large.jpg 2000w',
56-
sizes: "(max-width: 2000px) 100vw, 2000px"
61+
sizes: '(max-width: 2000px) 100vw, 2000px'
5762
}}
58-
placeholder='tiny-image.jpg'
63+
placeholder="tiny-image.jpg"
5964
>
6065
{(src, _loading, srcSetData) => (
61-
<img
62-
src={src}
63-
srcSet={srcSetData.srcSet}
64-
sizes={srcSetData.sizes}
65-
alt='an image'
66+
<img
67+
src={src}
68+
srcSet={srcSetData.srcSet}
69+
sizes={srcSetData.sizes}
70+
alt="an image"
6671
/>
6772
)}
6873
</ProgressiveImage>
69-
```
74+
```
75+
76+
### Props
77+
78+
| Name | Type | Required | Description |
79+
| ----------- | -------------------------------------- | -------- | ----------------------------------------------- |
80+
| children | `function` | `true` | returns `src`, `loading`, and `srcSetData` |
81+
| delay | `number` | `false` | time in milliseconds before src image is loaded |
82+
| onError | `function` | `false` | returns error event |
83+
| placeholder | `string` | `true` | the src of the placeholder image |
84+
| src | `string` | `true` | the src of the main image |
85+
| srcSetData | `{srcSet: "string", sizes: "string" }` | `false` | srcset and sizes to be applied to the image |

__tests__/index.js

+42-23
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
import "raf/polyfill";
2-
import React from "react";
3-
import { configure, mount } from "enzyme";
4-
import Adapter from "enzyme-adapter-react-16";
5-
import ProgressiveImage from "../src";
1+
import 'raf/polyfill';
2+
import React from 'react';
3+
import { configure, mount } from 'enzyme';
4+
import Adapter from 'enzyme-adapter-react-16';
5+
import ProgressiveImage from '../src';
66

77
configure({ adapter: new Adapter() });
88

9-
const src = "https://image.xyz/source";
10-
const placeholder = "https://image.xyz/placeholder";
9+
const src = 'https://image.xyz/source';
10+
const placeholder = 'https://image.xyz/placeholder';
1111
const srcSetData = {
12-
srcSet: "srcSet",
13-
sizes: "sizes"
12+
srcSet: 'srcSet',
13+
sizes: 'sizes'
1414
};
1515

16-
const mountProgressiveImage = renderFn => {
16+
const mountProgressiveImage = (renderFn, delay) => {
1717
const defaultRender = image => {
1818
return <img src={image} />;
1919
};
2020
const render = renderFn || defaultRender;
2121
return mount(
2222
<ProgressiveImage
23+
delay={delay}
2324
src={src}
2425
placeholder={placeholder}
2526
srcSetData={srcSetData}
@@ -29,14 +30,14 @@ const mountProgressiveImage = renderFn => {
2930
);
3031
};
3132

32-
describe("react-progressive-image", () => {
33+
describe('react-progressive-image', () => {
3334
beforeEach(() => {
3435
global.Image = Image;
3536
});
36-
it("exports a React component", () => {
37-
expect(typeof ProgressiveImage).toBe("function");
37+
it('exports a React component', () => {
38+
expect(typeof ProgressiveImage).toBe('function');
3839
});
39-
it("throws if not provided a function as a child", () => {
40+
it('throws if not provided a function as a child', () => {
4041
/* eslint-disable no-console */
4142
const _error = console.error;
4243
console.error = jest.fn(() => {});
@@ -53,54 +54,72 @@ describe("react-progressive-image", () => {
5354
}
5455
/* eslint-enable no-console */
5556
});
56-
it("creates an instance of Image when mounted", () => {
57+
it('creates an instance of Image when mounted', () => {
5758
const wrapper = mountProgressiveImage();
5859
const instance = wrapper.instance();
5960
expect(instance.image.constructor).toBe(HTMLImageElement);
6061
});
61-
it("sets the onload property on the Image instance", () => {
62+
it('sets the onload property on the Image instance', () => {
6263
const wrapper = mountProgressiveImage();
6364
const instance = wrapper.instance();
6465
expect(instance.image.onload).toEqual(instance.onLoad);
6566
});
66-
it("sets the onerror property on the Image instance", () => {
67+
it('sets the onerror property on the Image instance', () => {
6768
const wrapper = mountProgressiveImage();
6869
const instance = wrapper.instance();
6970
expect(instance.image.onerror).toEqual(instance.onError);
7071
});
71-
it("sets the src property on the Image instance", () => {
72+
it('sets the src property on the Image instance', () => {
7273
const wrapper = mountProgressiveImage();
7374
const instance = wrapper.instance();
7475
expect(instance.image.src).toEqual(src);
7576
});
76-
it("sets the srcSet property on the Image instance", () => {
77+
it('sets the srcSet property on the Image instance', () => {
7778
const wrapper = mountProgressiveImage();
7879
const instance = wrapper.instance();
7980
expect(instance.image.srcset).toEqual(srcSetData.srcSet);
8081
});
81-
it("sets the sizes property on the Image instance", () => {
82+
it('sets the sizes property on the Image instance', () => {
8283
const wrapper = mountProgressiveImage();
8384
const instance = wrapper.instance();
8485
expect(instance.image.sizes).toEqual(srcSetData.sizes);
8586
});
86-
it("renders placeholder image on initial render", () => {
87+
it('renders placeholder image on initial render', () => {
8788
const render = jest.fn(src => <img src={src} alt="an image" />);
8889
const wrapper = mountProgressiveImage(render);
8990
expect(render.mock.calls[0][0]).toEqual(placeholder);
9091
});
91-
it("renders src image on second render", () => {
92+
it('renders src image on second render', () => {
9293
const render = jest.fn(src => <img src={src} alt="an image" />);
9394
const wrapper = mountProgressiveImage(render);
9495
wrapper.instance().loadImage(src);
9596
wrapper.instance().onLoad();
9697
expect(render.mock.calls[1][0]).toEqual(src);
9798
});
98-
it("sets loading to false after src image is loaded", () => {
99+
it('sets loading to false after src image is loaded', () => {
99100
const render = jest.fn(src => <img src={src} alt="an image" />);
100101
const wrapper = mountProgressiveImage(render);
101102
expect(render.mock.calls[0][1]).toEqual(true);
102103
wrapper.instance().loadImage(src);
103104
wrapper.instance().onLoad();
104105
expect(render.mock.calls[1][1]).toEqual(false);
105106
});
107+
it('does not immediately set image if delay prop exists', () => {
108+
const delay = 3000;
109+
const render = jest.fn(src => <img src={src} alt="an image" />);
110+
const wrapper = mountProgressiveImage(render, delay);
111+
wrapper.instance().loadImage(src);
112+
wrapper.instance().onLoad();
113+
expect(wrapper.instance().state.image).toEqual(placeholder);
114+
});
115+
it('sets image after delay passes if delay prop exists', () => {
116+
const delay = 3000;
117+
const render = jest.fn(src => <img src={src} alt="an image" />);
118+
const wrapper = mountProgressiveImage(render, delay);
119+
wrapper.instance().loadImage(src);
120+
wrapper.instance().onLoad();
121+
setTimeout(() => {
122+
expect(wrapper.instance().state.image).toEqual(src);
123+
}, delay + 1);
124+
});
106125
});

demo/app.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ const textContainerStyle = {
3131
position: 'absolute',
3232
right: 0,
3333
top: 0
34-
}
34+
};
3535

3636
const textStyle = {
3737
color: '#fff',
3838
fontFamily: 'sans-serif',
3939
fontSize: '2.5em',
40-
textTransform: 'uppercase',
40+
textTransform: 'uppercase'
4141
};
4242

4343
class App extends React.Component {
@@ -51,20 +51,20 @@ class App extends React.Component {
5151
Image
5252
</h1>
5353
</div>
54-
<ProgressiveImage
55-
src={MD}
56-
placeholder={inline}
54+
<ProgressiveImage
55+
src={MD}
56+
placeholder={inline}
5757
srcSetData={{
5858
srcSet: `${SM} 320w, ${MD} 700w, ${LG} 2000w`,
59-
sizes: "(max-width: 2000px) 100vw, 2000px"
59+
sizes: '(max-width: 2000px) 100vw, 2000px'
6060
}}
6161
>
6262
{(image, loading, srcSetData) => {
6363
return (
64-
<img
65-
style={imageStyle}
66-
src={image}
67-
srcSet={srcSetData.srcSet}
64+
<img
65+
style={imageStyle}
66+
src={image}
67+
srcSet={srcSetData.srcSet}
6868
sizes={srcSetData.sizes}
6969
/>
7070
);

demo/inline.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/webpack.config.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
module.exports = {
22
mode: 'development',
33
context: __dirname,
4-
entry: [
5-
'./app.js'
6-
],
4+
entry: ['./app.js'],
75
output: {
86
path: __dirname,
97
filename: 'bundle.js'
108
},
119
module: {
12-
rules: [{
13-
test: /\.js$/,
14-
exclude: /node_modules/,
15-
loader: 'babel-loader'
16-
}]
10+
rules: [
11+
{
12+
test: /\.js$/,
13+
exclude: /node_modules/,
14+
loader: 'babel-loader'
15+
}
16+
]
1717
}
1818
};

prettier.config.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
singleQuote: true,
3+
trailingComma: "none"
4+
};

src/index.d.ts

+23-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
declare module "react-progressive-image" {
2-
export interface ProgressiveImageProps {
3-
onError?: (errorEvent: Event) => void;
4-
placeholder: string;
5-
src: string;
6-
}
1+
declare module 'react-progressive-image' {
2+
export interface ProgressiveImageProps {
3+
delay?: number;
4+
onError?: (errorEvent: Event) => void;
5+
placeholder: string;
6+
src: string;
7+
srcSetData?: {
8+
srcSet: string;
9+
sizes: string;
10+
};
11+
}
712

8-
export interface ProgressiveImageState {
9-
image: string;
10-
}
13+
export interface ProgressiveImageState {
14+
image: string;
15+
loading: boolean;
16+
srcSetData?: {
17+
srcSet: string;
18+
sizes: string;
19+
};
20+
}
1121

12-
export default class ProgressiveImage extends React.Component<ProgressiveImageProps, ProgressiveImageState>{}
22+
export default class ProgressiveImage extends React.Component<
23+
ProgressiveImageProps,
24+
ProgressiveImageState
25+
> {}
1326
}

0 commit comments

Comments
 (0)