UNPKG

babel-plugin-react-svg

Version:
130 lines (105 loc) 4.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = _default; var _cssToObj = _interopRequireDefault(require("./css-to-obj")); var _camelize = require("./camelize"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _default(babel) { const t = babel.types; const restElement = t.restElement ? t.restElement : t.restProperty; const createClass = className => t.logicalExpression("||", t.memberExpression( /* object = */ t.identifier("styles"), /* property = */ t.stringLiteral(className), /* computed = */ true), t.stringLiteral(className)); const attrVisitor = { JSXAttribute(path) { const name = path.get("name"); const value = path.get("value"); if (name.isJSXNamespacedName()) { // converts // <svg xmlns:xlink="asdf"> // to // <svg xmlnsXlink="asdf"> name.replaceWith(t.jSXIdentifier((0, _camelize.namespaceToCamel)(path.node.name.namespace.name, path.node.name.name.name))); } else if (name.isJSXIdentifier()) { if (name.node.name === "class") { // converts // <tag class="blah blah1"/> // to // <tag className="blah blah1"/> name.replaceWith(t.jSXIdentifier("className")); // converts // className="foo bar" // to // className={(styles["foo"] || "foo") + " " + (styles["bar"] || "bar")} let classes = value.node.value.split(/\s/); if (classes.length > 0) { let expr = createClass(classes[0]); for (let i = 1; i < classes.length; i++) { expr = t.binaryExpression("+", // (props.styles["foo"] || "foo") + " " t.binaryExpression("+", expr, t.stringLiteral(" ")), // (props.styles["bar"] || "bar") createClass(classes[i])); } value.replaceWith(t.jSXExpressionContainer(expr)); } } // converts // <tag style="text-align: center; width: 50px"> // to // <tag style={{textAlign: 'center', width: '50px'}}> if (name.node.name === "style") { let csso = (0, _cssToObj.default)(value.node.value); let properties = Object.keys(csso).map(prop => t.objectProperty(t.identifier((0, _camelize.hyphenToCamel)(prop)), t.stringLiteral(csso[prop]))); value.replaceWith(t.jSXExpressionContainer(t.objectExpression(properties))); } // converts // <svg stroke-width="5" data-x="0" aria-label="foo"> // to // <svg strokeWidth="5" data-x="0" aria-label="foo"> if (!/^(data-|aria-)/.test(name.node.name)) { name.replaceWith(t.jSXIdentifier((0, _camelize.hyphenToCamel)(path.node.name.name))); } } } }; // returns // export default (props) => ${input_svg_node} const getExport = function (svg) { return t.exportDefaultDeclaration(t.arrowFunctionExpression([t.objectPattern([t.objectProperty(t.identifier("styles"), t.assignmentPattern(t.identifier("styles"), t.objectExpression([])), false, true), restElement(t.identifier("props"))])], svg)); }; // converts // <svg> // to // <svg {this.props}> // after passing through attributes visitors const svgVisitor = { JSXOpeningElement(path) { if (path.node.name.name.toLowerCase() === "svg") { // add spread props path.node.attributes.push(t.jSXSpreadAttribute(t.identifier("props"))); } } }; // converts // <svg/> // to // import React from 'react'; // export default props => <svg {...props}/>; // after passing through other visitors const svgExpressionVisitor = { ExpressionStatement(path) { if (!path.get("expression").isJSXElement()) return; if (path.get("expression.openingElement.name").node.name !== "svg") return; path.replaceWith(getExport(path.get("expression").node)); } }; const programVisitor = { Program(path) { // add import react statement path.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier("React"))], t.stringLiteral("react"))); } }; return { visitor: Object.assign({}, programVisitor, svgExpressionVisitor, svgVisitor, attrVisitor) }; } module.exports = exports.default;