UNPKG

react-svg

Version:

A React component that injects SVG into the DOM.

249 lines (244 loc) 8.75 kB
import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose'; import _extends from '@babel/runtime/helpers/extends'; import _inheritsLoose from '@babel/runtime/helpers/inheritsLoose'; import { SVGInjector } from '@tanem/svg-injector'; import * as PropTypes from 'prop-types'; import * as React from 'react'; // Hat-tip: https://github.com/mui/material-ui/tree/master/packages/mui-utils/src. var ownerWindow = function ownerWindow(node) { var doc = (node == null ? undefined : node.ownerDocument) || document; return doc.defaultView || window; }; // Hat-tip: https://github.com/developit/preact-compat/blob/master/src/index.js#L402. var shallowDiffers = function shallowDiffers(a, b) { for (var i in a) { if (!(i in b)) { return true; } } for (var _i in b) { if (a[_i] !== b[_i]) { return true; } } return false; }; var _excluded = ["afterInjection", "beforeInjection", "desc", "evalScripts", "fallback", "httpRequestWithCredentials", "loading", "renumerateIRIElements", "src", "title", "useRequestCache", "wrapper"]; var svgNamespace = 'http://www.w3.org/2000/svg'; var xlinkNamespace = 'http://www.w3.org/1999/xlink'; var ReactSVG = /*#__PURE__*/function (_React$Component) { function ReactSVG() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this; _this.initialState = { hasError: false, isLoading: true }; _this.state = _this.initialState; _this._isMounted = false; _this.reactWrapper = undefined; _this.nonReactWrapper = undefined; _this.refCallback = function (reactWrapper) { _this.reactWrapper = reactWrapper; }; return _this; } _inheritsLoose(ReactSVG, _React$Component); var _proto = ReactSVG.prototype; _proto.renderSVG = function renderSVG() { var _this2 = this; /* istanbul ignore else */ if (this.reactWrapper instanceof ownerWindow(this.reactWrapper).Node) { var _this$props = this.props, desc = _this$props.desc, evalScripts = _this$props.evalScripts, httpRequestWithCredentials = _this$props.httpRequestWithCredentials, renumerateIRIElements = _this$props.renumerateIRIElements, src = _this$props.src, title = _this$props.title, useRequestCache = _this$props.useRequestCache; /* eslint-disable @typescript-eslint/no-non-null-assertion */ var onError = this.props.onError; var beforeInjection = this.props.beforeInjection; var afterInjection = this.props.afterInjection; var wrapper = this.props.wrapper; var nonReactWrapper; var nonReactTarget; if (wrapper === 'svg') { nonReactWrapper = document.createElementNS(svgNamespace, wrapper); nonReactWrapper.setAttribute('xmlns', svgNamespace); nonReactWrapper.setAttribute('xmlns:xlink', xlinkNamespace); nonReactTarget = document.createElementNS(svgNamespace, wrapper); } else { nonReactWrapper = document.createElement(wrapper); nonReactTarget = document.createElement(wrapper); } nonReactWrapper.appendChild(nonReactTarget); nonReactTarget.dataset.src = src; this.nonReactWrapper = this.reactWrapper.appendChild(nonReactWrapper); var handleError = function handleError(error) { _this2.removeSVG(); if (!_this2._isMounted) { onError(error); return; } _this2.setState(function () { return { hasError: true, isLoading: false }; }, function () { onError(error); }); }; var afterEach = function afterEach(error, svg) { if (error) { handleError(error); return; } // TODO (Tane): It'd be better to cleanly unsubscribe from SVGInjector // callbacks instead of tracking a property like this. if (_this2._isMounted) { _this2.setState(function () { return { isLoading: false }; }, function () { try { afterInjection(svg); } catch (afterInjectionError) { handleError(afterInjectionError); } }); } }; var beforeEach = function beforeEach(svg) { svg.setAttribute('role', 'img'); if (desc) { var originalDesc = svg.querySelector(':scope > desc'); if (originalDesc) { svg.removeChild(originalDesc); } var newDesc = document.createElement('desc'); newDesc.innerHTML = desc; svg.prepend(newDesc); } if (title) { var originalTitle = svg.querySelector(':scope > title'); if (originalTitle) { svg.removeChild(originalTitle); } var newTitle = document.createElement('title'); newTitle.innerHTML = title; svg.prepend(newTitle); } try { beforeInjection(svg); } catch (error) { handleError(error); } }; SVGInjector(nonReactTarget, { afterEach: afterEach, beforeEach: beforeEach, cacheRequests: useRequestCache, evalScripts: evalScripts, httpRequestWithCredentials: httpRequestWithCredentials, renumerateIRIElements: renumerateIRIElements }); } }; _proto.removeSVG = function removeSVG() { var _this$nonReactWrapper; if ((_this$nonReactWrapper = this.nonReactWrapper) != null && _this$nonReactWrapper.parentNode) { this.nonReactWrapper.parentNode.removeChild(this.nonReactWrapper); this.nonReactWrapper = null; } }; _proto.componentDidMount = function componentDidMount() { this._isMounted = true; this.renderSVG(); }; _proto.componentDidUpdate = function componentDidUpdate(prevProps) { var _this3 = this; if (shallowDiffers(_extends({}, prevProps), this.props)) { this.setState(function () { return _this3.initialState; }, function () { _this3.removeSVG(); _this3.renderSVG(); }); } }; _proto.componentWillUnmount = function componentWillUnmount() { this._isMounted = false; this.removeSVG(); }; _proto.render = function render() { /* eslint-disable @typescript-eslint/no-unused-vars */ var _this$props2 = this.props; _this$props2.afterInjection; _this$props2.beforeInjection; _this$props2.desc; _this$props2.evalScripts; var Fallback = _this$props2.fallback; _this$props2.httpRequestWithCredentials; var Loading = _this$props2.loading; _this$props2.renumerateIRIElements; _this$props2.src; _this$props2.title; _this$props2.useRequestCache; var wrapper = _this$props2.wrapper, rest = _objectWithoutPropertiesLoose(_this$props2, _excluded); /* eslint-enable @typescript-eslint/no-unused-vars */ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var Wrapper = wrapper; return /*#__PURE__*/React.createElement(Wrapper, _extends({}, rest, { ref: this.refCallback }, wrapper === 'svg' ? { xmlns: svgNamespace, xmlnsXlink: xlinkNamespace } : {}), this.state.isLoading && Loading && /*#__PURE__*/React.createElement(Loading, null), this.state.hasError && Fallback && /*#__PURE__*/React.createElement(Fallback, null)); }; return ReactSVG; }(React.Component); ReactSVG.defaultProps = { afterInjection: function afterInjection() { return undefined; }, beforeInjection: function beforeInjection() { return undefined; }, desc: '', evalScripts: 'never', fallback: null, httpRequestWithCredentials: false, loading: null, onError: function onError() { return undefined; }, renumerateIRIElements: true, title: '', useRequestCache: true, wrapper: 'div' }; ReactSVG.propTypes = { afterInjection: PropTypes.func, beforeInjection: PropTypes.func, desc: PropTypes.string, evalScripts: PropTypes.oneOf(['always', 'once', 'never']), fallback: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]), httpRequestWithCredentials: PropTypes.bool, loading: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]), onError: PropTypes.func, renumerateIRIElements: PropTypes.bool, src: PropTypes.string.isRequired, title: PropTypes.string, useRequestCache: PropTypes.bool, wrapper: PropTypes.oneOf(['div', 'span', 'svg']) } ; export { ReactSVG }; //# sourceMappingURL=react-svg.esm.js.map