Repository: MoOx/react-svg-inline Branch: master Commit: 9635b7d86385 Files: 10 Total size: 16.7 KB Directory structure: gitextract_xh4e8jrc/ ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json └── src/ ├── __tests__/ │ └── index.js ├── index.css └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # editorconfig.org root = true [*] end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 2 [*.md] # Allow
from Markdown trim_trailing_whitespace = false ================================================ FILE: .gitignore ================================================ node_modules # build lib ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 4 - 5 ================================================ FILE: CHANGELOG.md ================================================ # 2.1.1 - 2018-06-07 - Fix accessibility\* for svgs with newlines by @cmrigney in [#26](https://github.com/MoOx/react-svg-inline/pull/26) # 2.1.0 - 2018-01-22 - Add `accessibilityLabel` and `accessibilityDesc` props for a11y by @filoxo in [#23](https://github.com/MoOx/react-svg-inline/pull/23) # 2.0.1 - 2017-10-12 - Add React 16 support, by @smashercosmo in [#18](https://github.com/MoOx/react-svg-inline/pull/18) # 2.0.0 - 2017-04-18 - Fixed: Use `prop-types` package instead of react export to avoid warning with `react@^15.5.0`. Released as a major version since react (specified as in “peerDependencies”) needs a stricter range. # 1.2.0 - 2016-07-06 - Added: React ^15.2.0 support (no more warnings) ([#4](https://github.com/MoOx/react-svg-inline/pull/4) - @nason) # 1.1.0 - 2016-03-14 - Added: compat with react@15 # 1.0.1 - 2015-12-08 - Fixed: `main` prop in package.json # 1.0.0 - 2015-12-03 💥 ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Maxime Thirouin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # DEPRECATED, I recommend you the tool [SVGR](https://github.com/smooth-code/svgr) --- # react-svg-inline [![Travis (Unix) Build Badge](https://img.shields.io/travis/MoOx/react-svg-inline/master.svg?label=unix+build)](https://travis-ci.org/MoOx/react-svg-inline) > A react component to clean and display raw SVGs. ## Install ```console $ npm install react-svg-inline ``` You might also need to `npm install raw-loader` if you want to use this with webpack. ## Usage Here is an example of a usage in a React stateless component: ```js import React from "react" import SVGInline from "react-svg-inline" export default () => (
"} />
) ``` # Webpack to `require()` SVGs Use the raw-loader to require() raw SVGs files and pass them to `react-svg-inline`. ```js module.exports = { loaders: [ { test: /\.svg$/, loader: 'raw-loader' } ] } ``` ```js import React from "react" import SVGInline from "react-svg-inline" import iconSVG from "./myicon.svg" export default () => (
) ``` ## Options (props) ### className ``PropTypes.string`` Class name used for the component that will wrap the SVG. ### classSuffix ``PropTypes.string`` The class suffix that will be added to the svg className (default: "-svg"). ### component ``PropTypes.oneOfType([ PropTypes.string, PropTypes.func, ]),`` The component that will wrap the svg (default: `span`). ### svg ``PropTypes.string.isRequired`` ### fill ``PropTypes.string`` Color to use ### cleanup ``PropTypes.oneOfType([ PropTypes.bool, PropTypes.array, ])`` This allow you to cleanup (remove) some svg attributes. Here are the supported value that can be removed: - title - desc - comment - defs - width - height - fill - sketchMSShapeGroup - sketchMSPage - sketchMSLayerGroup If cleanup === true, it will remove all the attributes above. ### cleanupExceptions ``PropTypes.array`` This allow you to whitelist some svg attributes to keep while cleaning some others. ### width ``PropTypes.string`` ### height ``PropTypes.string`` ### accessibilityLabel ``PropTypes.string`` This value is added as an svg `` element that is accessible to screen readers. (Note: when this option is used, an SVG `id` attribute will be automatically injected). ### accessibilityDesc ``PropTypes.string`` This value is added as an svg `<desc>` element that is accessible to screen readers. --- ## CONTRIBUTING * ⇄ Pull requests and ★ Stars are always welcome. * For bugs and feature requests, please create an issue. * Pull requests must be accompanied by passing automated tests (`$ npm test`). ## [CHANGELOG](CHANGELOG.md) ## [LICENSE](LICENSE) ================================================ FILE: package.json ================================================ { "name": "react-svg-inline", "version": "2.1.1", "description": "A React component to inline your SVGs.", "keywords": [ "react", "svg", "icon", "inline" ], "author": "Maxime Thirouin", "license": "MIT", "repository": "https://github.com/MoOx/react-svg-inline.git", "main": "lib/index.js", "files": [ "lib", "src", "!**/__tests__" ], "dependencies": { "classnames": "^2.2.1", "prop-types": "^15.5.8" }, "devDependencies": { "ava": "^0.15.0", "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-eslint": "^7.2.2", "babel-preset-env": "^1.4.0", "babel-preset-react": "^6.24.1", "babel-preset-stage-3": "^6.24.1", "eslint": "^4.19.1", "eslint-config-i-am-meticulous": "^9.0.1", "eslint-plugin-react": "^7.9.1", "husky": "^0.14.3", "npmpub": "^4.0.0", "prettier": "^1.13.4", "pretty-quick": "^1.6.0", "react": "^16.0.0", "react-dom": "^16.0.0", "rimraf": "^2.4.4" }, "peerDependencies": { "react": "^0.14.9 || ^15.3.0 || ^16.0.0" }, "scripts": { "precommit": "pretty-quick --staged", "prebabelify": "rimraf lib", "babelify": "babel --copy-files src --out-dir lib", "prepublish": "npm run babelify", "lint": "eslint --fix src", "ava": "ava", "test": "npm run lint && npm run ava", "release": "npmpub" }, "babel": { "presets": [ "babel-preset-env", "babel-preset-stage-3", "babel-preset-react" ] }, "eslintConfig": { "extends": "eslint-config-i-am-meticulous/react" }, "ava": { "files": [ "src/**/__tests__/*.js" ], "failFast": true, "verbose": true, "require": [ "babel-core/register" ], "babel": "inherit" } } ================================================ FILE: src/__tests__/index.js ================================================ /* eslint-disable react/no-multi-comp, react/prop-types, react/jsx-no-bind */ import test from "ava"; import React from "react"; import ReactDOMServer from "react-dom/server"; import SVGInline from ".."; // const result = ? // => https://github.com/sindresorhus/ava/issues/274 test("SVGInline: passes & merges className", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline className="TestSVG" svg="<svg><g></g></svg>" /> ); t.is( result, '<span class="SVGInline TestSVG"><svg class="SVGInline-svg ' + 'TestSVG-svg"' + "><g></g></svg></span>" ); }); test("SVGInline: parent component can be chosen by tagName", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline component="div" className="TestSVG" svg="<svg><g></g></svg>" /> ); t.is( result, '<div class="SVGInline TestSVG"><svg class="SVGInline-svg TestSVG-svg"' + "><g></g></svg></div>" ); }); test("SVGInline: parent composite component can be chosen", t => { const TestComponent = props => { return <div {...props} className="foo" />; }; const result = ReactDOMServer.renderToStaticMarkup( <SVGInline component={TestComponent} className="TestSVG" svg="<svg><g></g></svg>" /> ); t.is( result, '<div class="foo"><svg class="SVGInline-svg TestSVG-svg"><g></g></svg>' + "</div>" ); }); const svgPiece = 'width="24" height="16px"><g fill="none"><path ' + 'fill="#ab234f"></path></g></svg>'; const SVGInlineStart = '<span class="SVGInline"><svg class="SVGInline-svg"'; const SVGInlineCleanedStart = '<span class="SVGInline SVGInline--cleaned">' + '<svg class="SVGInline-svg SVGInline--cleaned-svg"'; test("SVGInline: doesn't cleanup the svg by default", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline svg={`<svg ${svgPiece}`} /> ); t.is(result, `${SVGInlineStart} ${svgPiece}</span>`); }); test("SVGInline: can cleanup the svg", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline cleanup svg={`<svg ${svgPiece}`} /> ); t.is(result, `${SVGInlineCleanedStart}><g><path></path></g></svg></span>`); }); test("SVGInline: cleanup the svg with exceptions", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline cleanupExceptions={["fill"]} svg={`<svg ${svgPiece}`} /> ); t.is( result, `${SVGInlineCleanedStart}><g fill="none"><path fill="#ab234f"></path>` + "</g></svg></span>" ); }); test("SVGInline: should add width (and height automatically)", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline svg={"<svg><g></g></svg>"} width="1rem" /> ); t.is( result, `${SVGInlineStart} style="width: 1rem;height: 1rem;"><g></g></svg></span>` ); }); test("SVGInline: should add width & height", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline svg={"<svg><g></g></svg>"} width="1rem" height="auto" /> ); t.is( result, `${SVGInlineStart} style="width: 1rem;height: auto;"><g></g></svg></span>` ); }); test("SVGInline: should add height", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline svg={"<svg><g></g></svg>"} height="1rem" /> ); t.is(result, `${SVGInlineStart} style="height: 1rem;"><g></g></svg></span>`); }); test("SVGInline: does not pass internal props to component", t => { const TestComponent = props => { t.not(props.className, undefined); t.is(props.component, undefined); t.is(props.classSuffix, undefined); t.is(props.fill, undefined); t.is(props.cleanup, undefined); t.is(props.cleanupExceptions, undefined); return <div className="foo" />; }; ReactDOMServer.renderToStaticMarkup( <SVGInline component={TestComponent} className="TestSVG" classSuffix="-test" fill="#000000" svg="<svg><g></g></svg>" cleanupExceptions={["fake"]} cleanup /> ); }); test("SVGInline: includes title element if accessibilityLabel is provided", t => { const result = ReactDOMServer.renderToStaticMarkup( <SVGInline svg={"<svg><g></g></svg>"} accessibilityLabel="My test title" /> ); t.is( result, `${SVGInlineStart} role="img" aria-labelledby="SVGInline-0-title"><title id="SVGInline-0-title">My test title` ); }); test("SVGInline: accessibilityLabel IDs are not the same", t => { const result1 = ReactDOMServer.renderToStaticMarkup( "} accessibilityLabel="First test title" /> ); const result2 = ReactDOMServer.renderToStaticMarkup( "} accessibilityLabel="Second test title" /> ); t.is( result1, `${SVGInlineStart} role="img" aria-labelledby="SVGInline-1-title">First test title` ); t.is( result2, `${SVGInlineStart} role="img" aria-labelledby="SVGInline-2-title">Second test title` ); }); test("SVGInline: includes desc element if accessibilityDesc is provided", t => { const result = ReactDOMServer.renderToStaticMarkup( "} accessibilityDesc="Longer accessibility description of this svg image" /> ); t.is( result, `${SVGInlineStart}>Longer accessibility description of this svg image` ); }); test("SVGInline: accessibilityLabel doesn't crash on svg tag with newlines", t => { const result1 = ReactDOMServer.renderToStaticMarkup( "} accessibilityLabel="Third test title" /> ); t.is( result1, `${SVGInlineStart} ${"\n"} role="img" aria-labelledby="SVGInline-3-title">Third test title` ); }); ================================================ FILE: src/index.css ================================================ .SVGInline { transform: translate3d(0, 0, 0); /* fix webkit/blink poor rendering issues */ /* it's better defined directly because of the cascade shit width: inherit; height: inherit; line-height: inherit; */ vertical-align: middle; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .SVGInline-svg { width: inherit; height: inherit; line-height: inherit; color: inherit; fill: currentColor; } ================================================ FILE: src/index.js ================================================ import React, { Component } from "react"; import PropTypes from "prop-types"; import cx from "classnames"; // import styles from "./styles" const cleanups = { // some useless stuff for us // that svgo doesn't remove title: /.*<\/title>/gi, desc: /<desc>.*<\/desc>/gi, comment: /<!--.*-->/gi, defs: /<defs>.*<\/defs>/gi, // remove hardcoded dimensions width: / +width="\d+(\.\d+)?(px)?"/gi, height: / +height="\d+(\.\d+)?(px)?"/gi, // remove fill fill: / +fill="(none|#[0-9a-f]+)"/gi, // Sketch.app shit sketchMSShapeGroup: / +sketch:type="MSShapeGroup"/gi, sketchMSPage: / +sketch:type="MSPage"/gi, sketchMSLayerGroup: / +sketch:type="MSLayerGroup"/gi }; // @styled(styles) class SVGInline extends Component { render() { const { className, component, svg, fill, width, accessibilityLabel, accessibilityDesc, classSuffix, cleanupExceptions, ...componentProps } = this.props; let { cleanup, height } = this.props; if ( // simple way to enable entire cleanup cleanup === true || // passing cleanupExceptions enable cleanup as well (cleanup.length === 0 && cleanupExceptions.length > 0) ) { cleanup = Object.keys(cleanups); } cleanup = cleanup.filter(key => { return !(cleanupExceptions.indexOf(key) > -1); }); if (width && height === undefined) { height = width; } // remove useless props for wrapper delete componentProps.cleanup; delete componentProps.height; const classes = cx({ SVGInline: true, "SVGInline--cleaned": cleanup.length, [className]: className }); const svgClasses = classes.split(" ").join(classSuffix + " ") + classSuffix; let svgStr = SVGInline.cleanupSvg(svg, cleanup).replace( /<svg/, `<svg class="${svgClasses}"` + (fill ? ` fill="${fill}"` : "") + (width || height ? ' style="' + (width ? `width: ${width};` : "") + (height ? `height: ${height};` : "") + '"' : "") ); let match; if (accessibilityDesc) { match = /<svg(.|\n|\r\n)*?>/.exec(svgStr); const pos = match.index + match[0].length; svgStr = svgStr.substr(0, pos) + `<desc>${accessibilityDesc}</desc>` + svgStr.substr(pos); } if (accessibilityLabel) { match = match || /<svg(.|\n|\r\n)*?>/.exec(svgStr); const pos = match.index + match[0].length - 1; const id = `SVGInline-${SVGInline.idCount++}-title`; svgStr = svgStr.substr(0, pos) + ` role="img" aria-labelledby="${id}"` + svgStr.substr(pos, 1) + `<title id="${id}">${accessibilityLabel}` + svgStr.substr(pos + 1); } return React.createElement(component, { ...componentProps, // take most props className: classes, dangerouslySetInnerHTML: { __html: svgStr } }); } } SVGInline.propTypes = { className: PropTypes.string, classSuffix: PropTypes.string, component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), svg: PropTypes.string.isRequired, fill: PropTypes.string, cleanup: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]), cleanupExceptions: PropTypes.array, width: PropTypes.string, height: PropTypes.string, accessibilityLabel: PropTypes.string, accessibilityDesc: PropTypes.string }; SVGInline.defaultProps = { component: "span", classSuffix: "-svg", cleanup: [], cleanupExceptions: [] }; SVGInline.idCount = 0; SVGInline.cleanupSvg = (svg, cleanup = []) => { return Object.keys(cleanups) .filter(key => cleanup.indexOf(key) > -1) .reduce((acc, key) => { return acc.replace(cleanups[key], ""); }, svg) .trim(); }; export default SVGInline;