Skip to content

Commit

Permalink
feat: auto-generate blurDataURL property when placeholder=blur
Browse files Browse the repository at this point in the history
  • Loading branch information
nd0ut committed Jun 7, 2022
1 parent 87d85a1 commit bda8cf1
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 16 deletions.
47 changes: 37 additions & 10 deletions example/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import { FC } from 'react';
import styles from '../styles/Home.module.css';

type CodeProps = {
[key: string]: any
}
const Code: FC<CodeProps> = (p) =>
[key: string]: any;
};
const Code: FC<CodeProps> = (p) => (
<code className={styles.inlineCode} {...p} />
);

const Home: NextPage = () => (
<div className={styles.container}>
<div className={styles.card}>
<h1>Uploadcare custom loader for Image Component <a href="https://github.com/uploadcare/nextjs-loader">@uploadcare/nextjs-loader</a></h1>
<h1>
Uploadcare custom loader for Image Component{' '}
<a href="https://github.com/uploadcare/nextjs-loader">
@uploadcare/nextjs-loader
</a>
</h1>
<p>
The following is an example of a reference to an image from the{' '}
Uploadcare CDN at <Code>ucarecdn.com</Code>
Expand All @@ -31,7 +37,8 @@ const Home: NextPage = () => (
/>
<hr className={styles.hr} />
<p>
The following is an example of use of the <Code>UploadcareImage</Code> helper component.
The following is an example of use of the <Code>UploadcareImage</Code>{' '}
helper component.
</p>
<UploadcareImage
alt="Vercel logo"
Expand All @@ -40,6 +47,19 @@ const Home: NextPage = () => (
height={500}
/>
<hr className={styles.hr} />
<p>
The following is an example of use of the <Code>UploadcareImage</Code>{' '}
helper component with <Code>placeholder=blur</Code> property. It&apos;s
better to enable network throttling in dev tools to see the blurred placeholder.
</p>
<UploadcareImage
alt="Vercel logo"
src="https://ucarecdn.com/c768f1c2-891a-4f54-8e1e-7242df218b51/pinewatt2Hzmz15wGikunsplash.jpg"
width={500}
height={500}
placeholder="blur"
/>
<hr className={styles.hr} />
<p>
The following is an example of a reference to an external image at{' '}
<Code>assets.vercel.com</Code>.
Expand Down Expand Up @@ -68,8 +88,11 @@ const Home: NextPage = () => (
height={64}
loader={uploadcareLoader}
/>
<hr className={styles.hr} />
<p>Local image will be served AS IS in Development, and converted to the absolute URL and passed to the proxy in Production</p>
<hr className={styles.hr} />
<p>
Local image will be served AS IS in Development, and converted to the
absolute URL and passed to the proxy in Production
</p>
<Image
alt="A local image"
src="/local_image.png"
Expand All @@ -78,9 +101,13 @@ const Home: NextPage = () => (
loader={uploadcareLoader}
/>
<hr className={styles.hr} />
Checkout the project documentation on Github <a href="https://github.com/uploadcare/nextjs-loader">@uploadcare/nextjs-loader</a>.
Checkout the project documentation on Github{' '}
<a href="https://github.com/uploadcare/nextjs-loader">
@uploadcare/nextjs-loader
</a>
.
</div>
</div>
)
);

export default Home
export default Home;
1 change: 1 addition & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom'
3 changes: 2 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
testPathIgnorePatterns: ["<rootDir>/build/", "<rootDir>/src/__tests__/utils"],
collectCoverageFrom: ["src/**/*.{ts,js,tsx}"]
collectCoverageFrom: ["src/**/*.{ts,js,tsx}"],
setupFilesAfterEnv: ['<rootDir>/jest-setup.js']
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@babel/preset-env": "^7.15.6",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.2",
"@testing-library/react-hooks": "^7.0.2",
"@types/jest": "^27.0.2",
Expand Down
43 changes: 41 additions & 2 deletions src/__tests__/uploadcare-image.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('UploadcareImage', () => {
removeEnvVar('NEXT_PUBLIC_UPLOADCARE_PUBLIC_KEY');
});

test('The UploadcareImage component renders passed image with default settings properly', () => {
it('should render passed image with default settings properly', () => {
const src =
'https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/vercel.png';

Expand All @@ -38,7 +38,7 @@ describe('UploadcareImage', () => {
);
});

test('The UploadcareImage component should accept src without filename', () => {
it('should accept src without filename', () => {
const src = 'https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/';

render(
Expand All @@ -56,4 +56,43 @@ describe('UploadcareImage', () => {
'https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/-/format/auto/-/stretch/off/-/progressive/yes/-/resize/1080x/-/quality/normal/'
);
});

it('should generate blurDataURL when placeholder=blur passed', () => {
const src =
'https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/image.png';

render(
<UploadcareImage
src={src}
width={500}
height={500}
quality={80}
placeholder="blur"
/>
);

expect(screen.getByRole('img')).toHaveStyle(
'background-image: url(https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/-/format/auto/-/stretch/off/-/progressive/yes/-/resize/10x/-/quality/lightest/image.png)'
);
});

it('should not override passed blurDataURL', () => {
const src =
'https://ucarecdn.com/a6f8abc8-f92e-460a-b7a1-c5cd70a18cdb/image.png';

render(
<UploadcareImage
src={src}
width={500}
height={500}
quality={80}
placeholder="blur"
blurDataURL={src}
/>
);

expect(screen.getByRole('img')).toHaveStyle(
`background-image: url(${src})`
);
});
});
23 changes: 21 additions & 2 deletions src/components/UploadcareImage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
import Image, { ImageProps } from 'next/image';
import React from 'react';
import { getInt } from '../utils/helpers';
import { uploadcareLoader } from '../utils/loader';

export function UploadcareImage(props: ImageProps): JSX.Element {
return <Image loader={uploadcareLoader} {...props} />;
export function UploadcareImage({
blurDataURL,
...props
}: ImageProps): JSX.Element {
if (
props.placeholder === 'blur' &&
!blurDataURL &&
typeof props.src === 'string'
) {
const imageWidth = getInt(props.width);
const blurImageWidth = imageWidth ? Math.ceil(imageWidth * 0.01) : 10;
blurDataURL = uploadcareLoader({
src: props.src,
width: blurImageWidth,
quality: 0
});
}
return (
<Image loader={uploadcareLoader} blurDataURL={blurDataURL} {...props} />
);
}
10 changes: 10 additions & 0 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ export function isJpegExtension(extension: string): boolean {
return ['jpg', 'jpeg'].includes(extension.toLowerCase());
}

export function getInt(x: unknown): number | undefined {
if (typeof x === 'number') {
return x;
}
if (typeof x === 'string') {
return parseInt(x, 10);
}
return undefined;
}

function _parseUploadcareTransformationParam(param: string): string[] {
return param.split('/');
}
Loading

0 comments on commit bda8cf1

Please sign in to comment.