├── demo_0.jpg ├── demo_1.jpg ├── demo_2.jpg ├── screenshot.png ├── index.ts ├── .gitignore ├── tsconfig.json ├── package.json ├── lib ├── types.ts ├── patterns.ts └── react-svg-blob.tsx ├── LICENSE └── README.md /demo_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nghiepdev/react-svg-blob/HEAD/demo_0.jpg -------------------------------------------------------------------------------- /demo_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nghiepdev/react-svg-blob/HEAD/demo_1.jpg -------------------------------------------------------------------------------- /demo_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nghiepdev/react-svg-blob/HEAD/demo_2.jpg -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nghiepdev/react-svg-blob/HEAD/screenshot.png -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export { SvgBlob } from './lib/react-svg-blob'; 2 | export * from './lib/patterns'; 3 | export * from './lib/types'; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # misc 5 | .DS_Store 6 | 7 | # logs 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # build 13 | /dist -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": ["esnext", "dom"], 6 | "esModuleInterop": true, 7 | "jsx": "react", 8 | "declaration": true, 9 | "outDir": "./dist", 10 | "strict": true, 11 | "noImplicitAny": false 12 | }, 13 | "include": ["index.ts"], 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-svg-blob", 3 | "version": "0.3.1", 4 | "description": "React SVG Blob Generator", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "build": "tsc", 12 | "prepublishOnly": "npm run build" 13 | }, 14 | "dependencies": { 15 | "blobshape": "^1.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^17.0.3", 19 | "typescript": "^4.2.3" 20 | }, 21 | "peerDependencies": { 22 | "react": ">=16.8" 23 | }, 24 | "homepage": "https://github.com/nghiepit/react-svg-blob", 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/nghiepit/react-svg-blob.git" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/nghiepit/react-svg-blob/issues" 31 | }, 32 | "keywords": [ 33 | "react svg", 34 | "svg blob", 35 | "svg shape" 36 | ], 37 | "author": "Nghiep ", 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | export interface ShapeProps { 2 | size?: number; 3 | growth?: number; 4 | edges?: number; 5 | seed?: number; 6 | } 7 | 8 | export type PatternProps = Pick< 9 | React.SVGAttributes, 10 | 'width' | 'height' | 'path' 11 | >; 12 | 13 | interface BaseProps 14 | extends Omit< 15 | React.SVGAttributes, 16 | 'viewBox' | 'xmlns' | 'xmlnsXlink' 17 | > { 18 | variant: unknown; 19 | isOutline?: boolean; 20 | shapeProps?: ShapeProps; 21 | } 22 | 23 | interface SvgSolidProps extends BaseProps { 24 | variant: 'solid'; 25 | } 26 | 27 | interface SvgGradientProps extends BaseProps { 28 | variant: 'gradient'; 29 | colors: [string, string]; 30 | } 31 | 32 | interface SvgPatternProps extends BaseProps { 33 | variant: 'pattern'; 34 | pattern: PatternProps; 35 | } 36 | 37 | interface SvgImageProps extends BaseProps { 38 | variant: 'image'; 39 | image: string; 40 | } 41 | 42 | export type SvgBlobProps = 43 | | SvgSolidProps 44 | | SvgGradientProps 45 | | SvgPatternProps 46 | | SvgImageProps; 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-present Nghiep 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. -------------------------------------------------------------------------------- /lib/patterns.ts: -------------------------------------------------------------------------------- 1 | export const cross = { 2 | width: 40, 3 | height: 40, 4 | path: 'M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z', 5 | }; 6 | 7 | export const hexagons = { 8 | width: 28, 9 | height: 49, 10 | path: 'M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z', 11 | }; 12 | 13 | export const checker = { 14 | width: 8, 15 | height: 8, 16 | path: 'M0 0h4v4H0V0zm4 4h4v4H4V4z', 17 | }; 18 | 19 | export const stripes = { 20 | width: 40, 21 | height: 40, 22 | path: 'M0 40L40 0H20L0 20M40 40V20L20 40', 23 | }; 24 | 25 | export const lines = { 26 | width: 6, 27 | height: 6, 28 | path: 'M5 0h1L0 6V5zM6 5v1H5z', 29 | }; 30 | 31 | export const brown = { 32 | width: 20, 33 | height: 12, 34 | path: 'M9.8 12L0 2.2V.8l10 10 10-10v1.4L10.2 12h-.4zm-4 0L0 6.2V4.8L7.2 12H5.8zm8.4 0L20 6.2V4.8L12.8 12h1.4zM9.8 0l.2.2.2-.2h-.4zm-4 0L10 4.2 14.2 0h-1.4L10 2.8 7.2 0H5.8z', 35 | }; 36 | 37 | export const wave = { 38 | width: 100, 39 | height: 20, 40 | path: 'M21.184 20c.357-.13.72-.264 1.088-.402l1.768-.661C33.64 15.347 39.647 14 50 14c10.271 0 15.362 1.222 24.629 4.928.955.383 1.869.74 2.75 1.072h6.225c-2.51-.73-5.139-1.691-8.233-2.928C65.888 13.278 60.562 12 50 12c-10.626 0-16.855 1.397-26.66 5.063l-1.767.662c-2.475.923-4.66 1.674-6.724 2.275h6.335zm0-20C13.258 2.892 8.077 4 0 4V2c5.744 0 9.951-.574 14.85-2h6.334zM77.38 0C85.239 2.966 90.502 4 100 4V2c-6.842 0-11.386-.542-16.396-2h-6.225zM0 14c8.44 0 13.718-1.21 22.272-4.402l1.768-.661C33.64 5.347 39.647 4 50 4c10.271 0 15.362 1.222 24.629 4.928C84.112 12.722 89.438 14 100 14v-2c-10.271 0-15.362-1.222-24.629-4.928C65.888 3.278 60.562 2 50 2 39.374 2 33.145 3.397 23.34 7.063l-1.767.662C13.223 10.84 8.163 12 0 12v2z', 41 | }; 42 | 43 | export const floor = { 44 | width: 80, 45 | height: 80, 46 | path: 'M0 0h40v40H0V0zm40 40h40v40H40V40zm0-40h2l-2 2V0zm0 4l4-4h2l-6 6V4zm0 4l8-8h2L40 10V8zm0 4L52 0h2L40 14v-2zm0 4L56 0h2L40 18v-2zm0 4L60 0h2L40 22v-2zm0 4L64 0h2L40 26v-2zm0 4L68 0h2L40 30v-2zm0 4L72 0h2L40 34v-2zm0 4L76 0h2L40 38v-2zm0 4L80 0v2L42 40h-2zm4 0L80 4v2L46 40h-2zm4 0L80 8v2L50 40h-2zm4 0l28-28v2L54 40h-2zm4 0l24-24v2L58 40h-2zm4 0l20-20v2L62 40h-2zm4 0l16-16v2L66 40h-2zm4 0l12-12v2L70 40h-2zm4 0l8-8v2l-6 6h-2zm4 0l4-4v2l-2 2h-2z', 47 | }; 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REACT-SVG-BLOB 2 | 3 | React SVG Blob Generator. Inspired by [blob shapes app](https://github.com/lokesh-coder/blobs.app) original 4 | 5 | [![NPM version](https://img.shields.io/npm/v/react-svg-blob.svg)](https://www.npmjs.com/package/react-svg-blob) 6 | [![NPM monthly download](https://img.shields.io/npm/dm/react-svg-blob.svg)](https://www.npmjs.com/package/react-svg-blob) 7 | 8 | [![react-svg-blob](screenshot.png)](https://codesandbox.io/s/react-svg-blob-kuzpc) 9 | 10 | ## Demo 11 | 12 | https://codesandbox.io/s/react-svg-blob-kuzpc 13 | 14 | ## Installation 15 | 16 | ```sh 17 | $ yarn add react-svg-blob 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```jsx 23 | import {SvgBlob} from 'react-svg-blob'; 24 | import {cross as crossPattern} from 'react-svg-blob/dist/lib/patterns'; 25 | 26 | ; 27 | 28 | 29 | 30 | 31 | 32 | 36 | ``` 37 | 38 | ### Options 39 | 40 | | parameter | type | default | description | 41 | | :--------------: | :-------------------------------: | :---------: | :------------------------------------------------------------------------------------ | 42 | | variant | `solid\|gradient\|pattern\|image` | `undefined` | The variant type of shape. Required `true` | 43 | | isOutline | `boolean` | `false` | | 44 | | shapeProps.size | `number` | `200` | SVG blob path size | 45 | | shapeProps.grow | `number` | `6` | Minimum size of the blob in percentage. More the smaller more the randomness | 46 | | shapeProps.edges | `number` | `6` | Total nodes to create a shape. Increasing this value will add complexity to the shape | 47 | | shapeProps.seed | `number` | `undefined` | It can be used to get same shape | 48 | 49 | > We provide some patterns ready to use. You can find more of the pattern at [Hero Patterns](https://www.heropatterns.com/) 50 | 51 | ## Screenshot examples 52 | 53 | demo_0demo_1demo_2 54 | 55 | ## License 56 | 57 | MIT 58 | -------------------------------------------------------------------------------- /lib/react-svg-blob.tsx: -------------------------------------------------------------------------------- 1 | import React, {useMemo, forwardRef} from 'react'; 2 | import blobshape from 'blobshape'; 3 | 4 | import {SvgBlobProps} from './types'; 5 | 6 | export const SvgBlob = forwardRef(function SvgBlob( 7 | props, 8 | ref 9 | ) { 10 | const { 11 | variant, 12 | isOutline = false, 13 | color = 'currentColor', 14 | shapeProps, 15 | ...restProps 16 | } = props; 17 | 18 | const size = shapeProps?.size ?? 200; 19 | const growth = shapeProps?.growth ?? 6; 20 | const edges = shapeProps?.edges ?? 6; 21 | const seed = shapeProps?.seed ?? 6; 22 | 23 | const {path: svgPath} = useMemo( 24 | () => 25 | blobshape({ 26 | size, 27 | growth, 28 | edges, 29 | seed, 30 | }), 31 | [size, growth, edges, seed] 32 | ); 33 | 34 | const pathProps: React.SVGProps = { 35 | fill: color, 36 | }; 37 | 38 | if (variant === 'gradient') { 39 | pathProps.fill = 'url(#gradient)'; 40 | } 41 | 42 | if (isOutline) { 43 | pathProps.strokeWidth = '7px'; 44 | pathProps.fill = 'none'; 45 | pathProps.stroke = color; 46 | } 47 | 48 | if (variant === 'gradient' && isOutline) { 49 | pathProps.stroke = 'url(#gradient)'; 50 | } 51 | 52 | const {colors, pattern, image, ...svgProps} = restProps as any; 53 | 54 | return ( 55 | 61 | {props.variant === 'solid' && } 62 | 63 | {props.variant === 'gradient' && ( 64 | <> 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | )} 74 | 75 | {props.variant === 'pattern' && ( 76 | <> 77 | 78 | 86 | 87 | 88 | 89 | 90 | 91 | )} 92 | 93 | {props.variant === 'image' && ( 94 | <> 95 | 96 | 97 | 98 | 99 | 100 | 109 | 110 | )} 111 | 112 | ); 113 | }); 114 | --------------------------------------------------------------------------------