react-svg
Version:
A React component that injects SVG into the DOM.
271 lines (263 loc) • 9.69 kB
JavaScript
var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose');
var _extends = require('@babel/runtime/helpers/extends');
var _inheritsLoose = require('@babel/runtime/helpers/inheritsLoose');
var svgInjector = require('@tanem/svg-injector');
var PropTypes = require('prop-types');
var React = require('react');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var PropTypes__namespace = /*#__PURE__*/_interopNamespaceDefault(PropTypes);
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(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.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__namespace.createElement(Wrapper, _extends({}, rest, {
ref: this.refCallback
}, wrapper === 'svg' ? {
xmlns: svgNamespace,
xmlnsXlink: xlinkNamespace
} : {}), this.state.isLoading && Loading && /*#__PURE__*/React__namespace.createElement(Loading, null), this.state.hasError && Fallback && /*#__PURE__*/React__namespace.createElement(Fallback, null));
};
return ReactSVG;
}(React__namespace.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__namespace.func,
beforeInjection: PropTypes__namespace.func,
desc: PropTypes__namespace.string,
evalScripts: PropTypes__namespace.oneOf(['always', 'once', 'never']),
fallback: PropTypes__namespace.oneOfType([PropTypes__namespace.func, PropTypes__namespace.object, PropTypes__namespace.string]),
httpRequestWithCredentials: PropTypes__namespace.bool,
loading: PropTypes__namespace.oneOfType([PropTypes__namespace.func, PropTypes__namespace.object, PropTypes__namespace.string]),
onError: PropTypes__namespace.func,
renumerateIRIElements: PropTypes__namespace.bool,
src: PropTypes__namespace.string.isRequired,
title: PropTypes__namespace.string,
useRequestCache: PropTypes__namespace.bool,
wrapper: PropTypes__namespace.oneOf(['div', 'span', 'svg'])
};
exports.ReactSVG = ReactSVG;
//# sourceMappingURL=react-svg.cjs.development.js.map
;