├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── __tests__ ├── .eslintrc ├── test.js └── util.js ├── dist ├── index.es.js ├── index.es.js.map ├── index.js └── index.js.map ├── package.json ├── rollup.config.js ├── screenshots ├── react-bulletproof-button-2.png └── react-bulletproof-button.png ├── src ├── index.js └── util.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | "@babel/plugin-transform-runtime" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react" 6 | ], 7 | "env": { 8 | "es6": true 9 | }, 10 | "plugins": [ 11 | "react" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | // don't force es6 functions to include space before paren 18 | "space-before-function-paren": 0, 19 | 20 | // allow specifying true explicitly for boolean props 21 | "react/jsx-boolean-value": 0, 22 | 23 | "semi": [1, "always"] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # production 5 | /build 6 | /demo 7 | 8 | # testing 9 | /coverage 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 9 4 | - 8 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jackson Trieu 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-bulletproof-button 2 | React component that allows you design and create goregous email buttons that are compatible with modern email clients & Outlook 2007+. HTML output is based on [Campaign Monitor's "Bulletproof email buttons" concept](https://buttons.cm/). 3 | 4 | ## Table of contents 5 | 6 | - [Why Do I Need Bulletproof Buttons?](#why-do-i-need-bulletproof-buttons) 7 | - [Screenshots](#screenshots) 8 | - [Default Button style](#default-button-style) 9 | - [Button with updated colors and border radius](#button-with-updated-colors-and-border-radius) 10 | - [Install](#install) 11 | - [Usage](#usage) 12 | - [API](#api) 13 | - [Props](#props) 14 | - [Development](#development) 15 | - [Test](#test) 16 | - [Coverage](#coverage) 17 | - [License](#license) 18 | 19 | 20 | ## Why Do I Need Bulletproof Buttons? 21 | 22 | CSS support for HTML emails differs wildly between email clients, making it difficult to create HTML that will render consistently across a wide range of email clients. 23 | 24 | In particular, older Outlook clients (2007/2010/2013) use the Microsoft Word rendering engine which limits HTML emails to a subset of the modern CSS spec. 25 | 26 | Bulletproof buttons allow you to design and render gorgeous buttons using progressively enhanced VML and CSS. 27 | 28 | Older Outlook clients are supported by the use of VML and conditional rendering via the `').join('') 18 | 19 | const parser = new DOMParser(); 20 | const doc = parser.parseFromString(strippedofIfs, 'text/xml'); 21 | 22 | return doc.documentElement; 23 | }; 24 | 25 | const getVmlCenterElement = (vmlElement) => { 26 | return vmlElement.querySelector('center'); 27 | }; 28 | 29 | test('vendor specific styles are rendered', async () => { 30 | const { container } = render( 31 | 33 | ); 34 | const linkElement = getLinkElement(container); 35 | 36 | expect(linkElement.getAttribute('style').includes('mso-hide: all')).toBeTruthy(); 37 | expect(linkElement.getAttribute('style').includes('-webkit-text-size-adjust: none')).toBeTruthy(); 38 | }); 39 | 40 | test("'backgroundColor' prop is rendered", async () => { 41 | const backgroundColor = '#123456'; 42 | 43 | const { container } = render( 44 | 47 | ); 48 | const linkElement = getLinkElement(container); 49 | const vmlElement = getVmlElement(container); 50 | 51 | expect(linkElement).toHaveStyle(`background-color: ${backgroundColor}`, requiredProps.backgroundColor); 52 | expect(vmlElement.getAttribute('fillcolor')).toBe(backgroundColor); 53 | }); 54 | 55 | test("'borderColor' prop is rendered", async () => { 56 | const borderColor = '#123456'; 57 | 58 | const { container } = render( 59 | 62 | ); 63 | const linkElement = getLinkElement(container); 64 | const vmlElement = getVmlElement(container); 65 | 66 | expect(linkElement).toHaveStyle(`border-color: ${borderColor}`, requiredProps.borderColor); 67 | expect(vmlElement.getAttribute('strokecolor')).toBe(borderColor); 68 | }); 69 | 70 | test("'borderStyle' prop is rendered", async () => { 71 | const borderStyle = 'dashed'; 72 | 73 | const { container } = render( 74 | 77 | ); 78 | const linkElement = getLinkElement(container); 79 | 80 | expect(linkElement).toHaveStyle(`border-style: ${borderStyle}`, borderStyle); 81 | }); 82 | 83 | test("'borderWidth' prop is rendered", async () => { 84 | const borderWidth = 20; 85 | 86 | const { container } = render( 87 | 90 | ); 91 | const linkElement = getLinkElement(container); 92 | 93 | expect(linkElement).toHaveStyle(`border-width: ${borderWidth}px`, borderWidth); 94 | }); 95 | 96 | test("'fontColor' prop is rendered", async () => { 97 | const fontColor = '#654321'; 98 | 99 | const { container } = render( 100 | 103 | ); 104 | const linkElement = getLinkElement(container); 105 | const vmlElement = getVmlElement(container); 106 | const vmlCenterElement = getVmlCenterElement(vmlElement); 107 | 108 | expect(linkElement).toHaveStyle(`color: ${fontColor}`, fontColor); 109 | expect(vmlCenterElement.getAttribute('style').includes(`color: ${fontColor}`)).toBeTruthy(); 110 | }); 111 | 112 | test("'fontFamily' prop is rendered", async () => { 113 | const fontFamily = 'Arial, sans-serif, serif'; 114 | 115 | const { container } = render( 116 | 119 | ); 120 | const linkElement = getLinkElement(container); 121 | const vmlElement = getVmlElement(container); 122 | const vmlCenterElement = getVmlCenterElement(vmlElement); 123 | 124 | expect(linkElement).toHaveStyle(`font-family: ${fontFamily}`, fontFamily); 125 | expect(vmlCenterElement.getAttribute('style').includes(`font-family: ${fontFamily}`)).toBeTruthy(); 126 | }); 127 | 128 | test("'fontSize' prop is rendered", async () => { 129 | const fontSize = 24; 130 | 131 | const { container } = render( 132 | 135 | ); 136 | const linkElement = getLinkElement(container); 137 | const vmlElement = getVmlElement(container); 138 | const vmlCenterElement = getVmlCenterElement(vmlElement); 139 | 140 | expect(linkElement).toHaveStyle(`font-size: ${fontSize}px`, fontSize); 141 | expect(vmlCenterElement.getAttribute('style').includes(`font-size: ${fontSize}px`)).toBeTruthy(); 142 | }); 143 | 144 | test("'fontWeight' prop is rendered", async () => { 145 | const fontWeight = '600'; 146 | 147 | const { container } = render( 148 | 151 | ); 152 | const linkElement = getLinkElement(container); 153 | const vmlElement = getVmlElement(container); 154 | const vmlCenterElement = getVmlCenterElement(vmlElement); 155 | 156 | expect(linkElement).toHaveStyle(`font-weight: ${fontWeight}`, fontWeight); 157 | expect(vmlCenterElement.getAttribute('style').includes(`font-weight: ${fontWeight}`)).toBeTruthy(); 158 | }); 159 | 160 | test("'height' prop is rendered", async () => { 161 | const height = 55; 162 | 163 | const { container } = render( 164 | 167 | ); 168 | const linkElement = getLinkElement(container); 169 | const vmlElement = getVmlElement(container); 170 | 171 | expect(linkElement).toHaveStyle(`height: ${height}px`, height); 172 | expect(linkElement).toHaveStyle(`line-height: ${height}px`, height); 173 | expect(vmlElement.getAttribute('style').includes(`height: ${height}px`)).toBeTruthy(); 174 | }); 175 | 176 | test("'width' prop is rendered", async () => { 177 | const width = 222; 178 | 179 | const { container } = render( 180 | 183 | ); 184 | const linkElement = getLinkElement(container); 185 | const vmlElement = getVmlElement(container); 186 | 187 | expect(linkElement).toHaveStyle(`width: ${width}px`, width); 188 | expect(vmlElement.getAttribute('style').includes(`width: ${width}px`)).toBeTruthy(); 189 | }); 190 | 191 | test("'href' prop is rendered", async () => { 192 | const { container } = render( 193 | 195 | ); 196 | const linkElement = getLinkElement(container); 197 | const vmlElement = getVmlElement(container); 198 | 199 | expect(linkElement).toHaveAttribute('href', requiredProps.href); 200 | expect(vmlElement.getAttribute('href')).toBe(requiredProps.href); 201 | }); 202 | 203 | test("'text' prop is rendered", async () => { 204 | const { container } = render( 205 | 207 | ); 208 | const linkElement = getLinkElement(container); 209 | const vmlElement = getVmlElement(container); 210 | const vmlCenterElement = getVmlCenterElement(vmlElement); 211 | 212 | expect(linkElement).toHaveTextContent(requiredProps.text); 213 | expect(vmlCenterElement.textContent.trim()).toBe(requiredProps.text); 214 | }); 215 | -------------------------------------------------------------------------------- /__tests__/util.js: -------------------------------------------------------------------------------- 1 | import { hashToStyles, toPx } from '../src/util'; 2 | 3 | test('hashToStyles generates a css style formatted string', async () => { 4 | const styleHash = { 5 | 'background': '#fff', 6 | 'font-size': '13px', 7 | '-webkit-text-size-adjust': 'none' 8 | }; 9 | const styleString = hashToStyles(styleHash); 10 | 11 | expect(styleString).toEqual('background: #fff; font-size: 13px; -webkit-text-size-adjust: none'); 12 | }); 13 | 14 | test('hashToStyles does not sort', async () => { 15 | const styleHash = { 16 | 'font-size': '13px', 17 | 'background': '#fff', 18 | '-webkit-text-size-adjust': 'none' 19 | }; 20 | const styleString = hashToStyles(styleHash); 21 | 22 | expect(styleString).toEqual('font-size: 13px; background: #fff; -webkit-text-size-adjust: none'); 23 | }); 24 | 25 | test('toPx adds px to end of number', async () => { 26 | expect(toPx(10)).toEqual('10px'); 27 | }); 28 | 29 | test('toPx does not add px to string already ending with px', async () => { 30 | expect(toPx('10px')).toEqual('10px'); 31 | }); 32 | 33 | test('toPx returns 0 if value is falsy', async () => { 34 | expect(toPx(null)).toEqual('0'); 35 | expect(toPx(undefined)).toEqual('0'); 36 | expect(toPx('')).toEqual('0'); 37 | }); 38 | -------------------------------------------------------------------------------- /dist/index.es.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function _classCallCheck(instance, Constructor) { 5 | if (!(instance instanceof Constructor)) { 6 | throw new TypeError("Cannot call a class as a function"); 7 | } 8 | } 9 | 10 | var classCallCheck = _classCallCheck; 11 | 12 | function _defineProperties(target, props) { 13 | for (var i = 0; i < props.length; i++) { 14 | var descriptor = props[i]; 15 | descriptor.enumerable = descriptor.enumerable || false; 16 | descriptor.configurable = true; 17 | if ("value" in descriptor) descriptor.writable = true; 18 | Object.defineProperty(target, descriptor.key, descriptor); 19 | } 20 | } 21 | 22 | function _createClass(Constructor, protoProps, staticProps) { 23 | if (protoProps) _defineProperties(Constructor.prototype, protoProps); 24 | if (staticProps) _defineProperties(Constructor, staticProps); 25 | return Constructor; 26 | } 27 | 28 | var createClass = _createClass; 29 | 30 | function createCommonjsModule(fn, module) { 31 | return module = { exports: {} }, fn(module, module.exports), module.exports; 32 | } 33 | 34 | var _typeof_1 = createCommonjsModule(function (module) { 35 | function _typeof2(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof2(obj); } 36 | 37 | function _typeof(obj) { 38 | if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") { 39 | module.exports = _typeof = function _typeof(obj) { 40 | return _typeof2(obj); 41 | }; 42 | } else { 43 | module.exports = _typeof = function _typeof(obj) { 44 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj); 45 | }; 46 | } 47 | 48 | return _typeof(obj); 49 | } 50 | 51 | module.exports = _typeof; 52 | }); 53 | 54 | function _assertThisInitialized(self) { 55 | if (self === void 0) { 56 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 57 | } 58 | 59 | return self; 60 | } 61 | 62 | var assertThisInitialized = _assertThisInitialized; 63 | 64 | function _possibleConstructorReturn(self, call) { 65 | if (call && (_typeof_1(call) === "object" || typeof call === "function")) { 66 | return call; 67 | } 68 | 69 | return assertThisInitialized(self); 70 | } 71 | 72 | var possibleConstructorReturn = _possibleConstructorReturn; 73 | 74 | var getPrototypeOf = createCommonjsModule(function (module) { 75 | function _getPrototypeOf(o) { 76 | module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 77 | return o.__proto__ || Object.getPrototypeOf(o); 78 | }; 79 | return _getPrototypeOf(o); 80 | } 81 | 82 | module.exports = _getPrototypeOf; 83 | }); 84 | 85 | var setPrototypeOf = createCommonjsModule(function (module) { 86 | function _setPrototypeOf(o, p) { 87 | module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 88 | o.__proto__ = p; 89 | return o; 90 | }; 91 | 92 | return _setPrototypeOf(o, p); 93 | } 94 | 95 | module.exports = _setPrototypeOf; 96 | }); 97 | 98 | function _inherits(subClass, superClass) { 99 | if (typeof superClass !== "function" && superClass !== null) { 100 | throw new TypeError("Super expression must either be null or a function"); 101 | } 102 | 103 | subClass.prototype = Object.create(superClass && superClass.prototype, { 104 | constructor: { 105 | value: subClass, 106 | writable: true, 107 | configurable: true 108 | } 109 | }); 110 | if (superClass) setPrototypeOf(subClass, superClass); 111 | } 112 | 113 | var inherits = _inherits; 114 | 115 | function _defineProperty(obj, key, value) { 116 | if (key in obj) { 117 | Object.defineProperty(obj, key, { 118 | value: value, 119 | enumerable: true, 120 | configurable: true, 121 | writable: true 122 | }); 123 | } else { 124 | obj[key] = value; 125 | } 126 | 127 | return obj; 128 | } 129 | 130 | var defineProperty = _defineProperty; 131 | 132 | var hashToStyles = function hashToStyles(styleHash) { 133 | var result = ''; 134 | var keys = Object.keys(styleHash); 135 | 136 | for (var _i = 0; _i < keys.length; _i++) { 137 | var key = keys[_i]; 138 | 139 | if (result) { 140 | result += '; '; 141 | } 142 | 143 | result += key + ': ' + styleHash[key]; 144 | } 145 | 146 | return result; 147 | }; 148 | var toPx = function toPx(value) { 149 | if (!value) { 150 | return '0'; 151 | } 152 | 153 | if (typeof value === 'string' && value.endsWith('px')) { 154 | return value; 155 | } 156 | 157 | return "".concat(value, "px"); 158 | }; 159 | 160 | var BulletproofButton = 161 | /*#__PURE__*/ 162 | function (_Component) { 163 | inherits(BulletproofButton, _Component); 164 | 165 | function BulletproofButton() { 166 | var _getPrototypeOf2; 167 | 168 | var _this; 169 | 170 | classCallCheck(this, BulletproofButton); 171 | 172 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 173 | args[_key] = arguments[_key]; 174 | } 175 | 176 | _this = possibleConstructorReturn(this, (_getPrototypeOf2 = getPrototypeOf(BulletproofButton)).call.apply(_getPrototypeOf2, [this].concat(args))); 177 | 178 | defineProperty(assertThisInitialized(assertThisInitialized(_this)), "calculateVmlArcSize", function () { 179 | return Math.round(_this.props.borderRadius / _this.props.width * 100).toString() + '%'; 180 | }); 181 | 182 | return _this; 183 | } 184 | 185 | createClass(BulletproofButton, [{ 186 | key: "render", 187 | value: function render() { 188 | var vmlButton = this.renderVmlButton(); 189 | var htmlButton = this.renderHtmlButton(); 190 | return React.createElement("div", null, React.createElement("div", { 191 | dangerouslySetInnerHTML: { 192 | __html: vmlButton 193 | } 194 | }), React.createElement("div", { 195 | dangerouslySetInnerHTML: { 196 | __html: htmlButton 197 | } 198 | })); 199 | } 200 | }, { 201 | key: "renderVmlButton", 202 | value: function renderVmlButton() { 203 | var vmlRectStyles = this.calculateVmlRectStyles(); 204 | var vmlCenterStyles = this.calculateVmlCenterStyles(); 205 | var vmlArcSize = this.calculateVmlArcSize(); 206 | return "\n \n "); 207 | } 208 | }, { 209 | key: "calculateVmlRectStyles", 210 | value: function calculateVmlRectStyles() { 211 | return hashToStyles({ 212 | 'height': toPx(this.props.height), 213 | 'v-text-anchor': 'middle', 214 | 'width': toPx(this.props.width) 215 | }); 216 | } 217 | }, { 218 | key: "calculateVmlCenterStyles", 219 | value: function calculateVmlCenterStyles() { 220 | return hashToStyles({ 221 | 'color': this.props.fontColor, 222 | 'font-family': this.props.fontFamily, 223 | 'font-size': toPx(this.props.fontSize), 224 | 'font-weight': this.props.fontWeight 225 | }); 226 | } 227 | }, { 228 | key: "renderHtmlButton", 229 | value: function renderHtmlButton() { 230 | var htmlLinkStyles = this.calculateHtmlLinkStyles(); 231 | return "\n \n ").concat(this.props.text, "\n \n "); 232 | } 233 | }, { 234 | key: "calculateHtmlLinkStyles", 235 | value: function calculateHtmlLinkStyles() { 236 | return hashToStyles({ 237 | 'background-color': this.props.backgroundColor, 238 | 'border-color': this.props.borderColor, 239 | 'border-style': this.props.borderStyle, 240 | 'border-width': toPx(this.props.borderWidth), 241 | 'border-radius': toPx(this.props.borderRadius), 242 | 'color': this.props.fontColor, 243 | 'display': 'inline-block', 244 | 'font-family': this.props.fontFamily, 245 | 'font-size': toPx(this.props.fontSize), 246 | 'font-weight': this.props.fontWeight, 247 | 'height': toPx(this.props.height), 248 | 'line-height': toPx(this.props.height), 249 | 'mso-hide': 'all', 250 | 'text-align': 'center', 251 | 'text-decoration': 'none', 252 | 'width': toPx(this.props.width), 253 | '-webkit-text-size-adjust': 'none' 254 | }); 255 | } 256 | }]); 257 | 258 | return BulletproofButton; 259 | }(Component); 260 | BulletproofButton.defaultProps = { 261 | backgroundColor: '#556270', 262 | borderColor: '#1e3650', 263 | borderRadius: 4, 264 | borderStyle: 'solid', 265 | borderWidth: 1, 266 | fontFamily: 'sans-serif', 267 | fontSize: 13, 268 | fontWeight: 'bold', 269 | fontColor: '#fff', 270 | height: 40, 271 | width: 200 272 | }; 273 | BulletproofButton.propTypes = { 274 | backgroundColor: PropTypes.string, 275 | borderColor: PropTypes.string, 276 | borderRadius: PropTypes.number, 277 | borderStyle: PropTypes.string, 278 | borderWidth: PropTypes.number, 279 | fontColor: PropTypes.string, 280 | fontFamily: PropTypes.string, 281 | fontSize: PropTypes.number, 282 | fontWeight: PropTypes.string, 283 | height: PropTypes.number, 284 | href: PropTypes.string.isRequired, 285 | text: PropTypes.string.isRequired, 286 | width: PropTypes.number 287 | }; 288 | 289 | export default BulletproofButton; 290 | //# sourceMappingURL=index.es.js.map 291 | -------------------------------------------------------------------------------- /dist/index.es.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.es.js","sources":["../node_modules/@babel/runtime/helpers/classCallCheck.js","../node_modules/@babel/runtime/helpers/createClass.js","../node_modules/@babel/runtime/helpers/typeof.js","../node_modules/@babel/runtime/helpers/assertThisInitialized.js","../node_modules/@babel/runtime/helpers/possibleConstructorReturn.js","../node_modules/@babel/runtime/helpers/getPrototypeOf.js","../node_modules/@babel/runtime/helpers/setPrototypeOf.js","../node_modules/@babel/runtime/helpers/inherits.js","../node_modules/@babel/runtime/helpers/defineProperty.js","../src/util.js","../src/index.js"],"sourcesContent":["function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\nmodule.exports = _classCallCheck;","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\n\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\nmodule.exports = _createClass;","function _typeof2(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof2(obj); }\n\nfunction _typeof(obj) {\n if (typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\") {\n module.exports = _typeof = function _typeof(obj) {\n return _typeof2(obj);\n };\n } else {\n module.exports = _typeof = function _typeof(obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n }\n\n return _typeof(obj);\n}\n\nmodule.exports = _typeof;","function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}\n\nmodule.exports = _assertThisInitialized;","var _typeof = require(\"../helpers/typeof\");\n\nvar assertThisInitialized = require(\"./assertThisInitialized\");\n\nfunction _possibleConstructorReturn(self, call) {\n if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) {\n return call;\n }\n\n return assertThisInitialized(self);\n}\n\nmodule.exports = _possibleConstructorReturn;","function _getPrototypeOf(o) {\n module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {\n return o.__proto__ || Object.getPrototypeOf(o);\n };\n return _getPrototypeOf(o);\n}\n\nmodule.exports = _getPrototypeOf;","function _setPrototypeOf(o, p) {\n module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}\n\nmodule.exports = _setPrototypeOf;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inherits;","function _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}\n\nmodule.exports = _defineProperty;","export const hashToStyles = (styleHash) => {\n let result = '';\n\n const keys = Object.keys(styleHash);\n\n for (let key of keys) {\n if (result) {\n result += '; ';\n }\n\n result += key + ': ' + styleHash[key];\n }\n\n return result;\n};\n\nexport const toPx = (value) => {\n if (!value) { return '0'; }\n if (typeof(value) === 'string' && value.endsWith('px')) { return value; }\n\n return `${value}px`;\n};\n","import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { hashToStyles, toPx } from './util';\n\nexport default class BulletproofButton extends Component {\n render() {\n const vmlButton = this.renderVmlButton();\n const htmlButton = this.renderHtmlButton();\n\n return (\n
\n
\n
\n
\n );\n }\n\n renderVmlButton() {\n const vmlRectStyles = this.calculateVmlRectStyles();\n const vmlCenterStyles = this.calculateVmlCenterStyles();\n const vmlArcSize = this.calculateVmlArcSize();\n\n return `\n \n `;\n }\n\n calculateVmlRectStyles() {\n return hashToStyles({\n 'height': toPx(this.props.height),\n 'v-text-anchor': 'middle',\n 'width': toPx(this.props.width)\n });\n }\n\n calculateVmlCenterStyles() {\n return hashToStyles({\n 'color': this.props.fontColor,\n 'font-family': this.props.fontFamily,\n 'font-size': toPx(this.props.fontSize),\n 'font-weight': this.props.fontWeight\n });\n }\n\n calculateVmlArcSize = () => {\n return Math.round((this.props.borderRadius / this.props.width) * 100).toString() + '%';\n }\n\n renderHtmlButton() {\n const htmlLinkStyles = this.calculateHtmlLinkStyles();\n return `\n \n ${this.props.text}\n \n `;\n }\n\n calculateHtmlLinkStyles() {\n return hashToStyles({\n 'background-color': this.props.backgroundColor,\n 'border-color': this.props.borderColor,\n 'border-style': this.props.borderStyle,\n 'border-width': toPx(this.props.borderWidth),\n 'border-radius': toPx(this.props.borderRadius),\n 'color': this.props.fontColor,\n 'display': 'inline-block',\n 'font-family': this.props.fontFamily,\n 'font-size': toPx(this.props.fontSize),\n 'font-weight': this.props.fontWeight,\n 'height': toPx(this.props.height),\n 'line-height': toPx(this.props.height),\n 'mso-hide': 'all',\n 'text-align': 'center',\n 'text-decoration': 'none',\n 'width': toPx(this.props.width),\n '-webkit-text-size-adjust': 'none'\n });\n }\n}\n\nBulletproofButton.defaultProps = {\n backgroundColor: '#556270',\n borderColor: '#1e3650',\n borderRadius: 4,\n borderStyle: 'solid',\n borderWidth: 1,\n fontFamily: 'sans-serif',\n fontSize: 13,\n fontWeight: 'bold',\n fontColor: '#fff',\n height: 40,\n width: 200\n};\n\nBulletproofButton.propTypes = {\n backgroundColor: PropTypes.string,\n borderColor: PropTypes.string,\n borderRadius: PropTypes.number,\n borderStyle: PropTypes.string,\n borderWidth: PropTypes.number,\n fontColor: PropTypes.string,\n fontFamily: PropTypes.string,\n fontSize: PropTypes.number,\n fontWeight: PropTypes.string,\n height: PropTypes.number,\n href: PropTypes.string.isRequired,\n text: PropTypes.string.isRequired,\n width: PropTypes.number\n};\n"],"names":["_typeof","hashToStyles","styleHash","result","keys","Object","key","toPx","value","endsWith","BulletproofButton","Math","round","props","borderRadius","width","toString","vmlButton","renderVmlButton","htmlButton","renderHtmlButton","__html","vmlRectStyles","calculateVmlRectStyles","vmlCenterStyles","calculateVmlCenterStyles","vmlArcSize","calculateVmlArcSize","href","borderColor","backgroundColor","text","height","fontColor","fontFamily","fontSize","fontWeight","htmlLinkStyles","calculateHtmlLinkStyles","borderStyle","borderWidth","Component","defaultProps","propTypes","PropTypes","string","number","isRequired"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 4 | 5 | var React = require('react'); 6 | var React__default = _interopDefault(React); 7 | var PropTypes = _interopDefault(require('prop-types')); 8 | 9 | function _classCallCheck(instance, Constructor) { 10 | if (!(instance instanceof Constructor)) { 11 | throw new TypeError("Cannot call a class as a function"); 12 | } 13 | } 14 | 15 | var classCallCheck = _classCallCheck; 16 | 17 | function _defineProperties(target, props) { 18 | for (var i = 0; i < props.length; i++) { 19 | var descriptor = props[i]; 20 | descriptor.enumerable = descriptor.enumerable || false; 21 | descriptor.configurable = true; 22 | if ("value" in descriptor) descriptor.writable = true; 23 | Object.defineProperty(target, descriptor.key, descriptor); 24 | } 25 | } 26 | 27 | function _createClass(Constructor, protoProps, staticProps) { 28 | if (protoProps) _defineProperties(Constructor.prototype, protoProps); 29 | if (staticProps) _defineProperties(Constructor, staticProps); 30 | return Constructor; 31 | } 32 | 33 | var createClass = _createClass; 34 | 35 | function createCommonjsModule(fn, module) { 36 | return module = { exports: {} }, fn(module, module.exports), module.exports; 37 | } 38 | 39 | var _typeof_1 = createCommonjsModule(function (module) { 40 | function _typeof2(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof2(obj); } 41 | 42 | function _typeof(obj) { 43 | if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") { 44 | module.exports = _typeof = function _typeof(obj) { 45 | return _typeof2(obj); 46 | }; 47 | } else { 48 | module.exports = _typeof = function _typeof(obj) { 49 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj); 50 | }; 51 | } 52 | 53 | return _typeof(obj); 54 | } 55 | 56 | module.exports = _typeof; 57 | }); 58 | 59 | function _assertThisInitialized(self) { 60 | if (self === void 0) { 61 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 62 | } 63 | 64 | return self; 65 | } 66 | 67 | var assertThisInitialized = _assertThisInitialized; 68 | 69 | function _possibleConstructorReturn(self, call) { 70 | if (call && (_typeof_1(call) === "object" || typeof call === "function")) { 71 | return call; 72 | } 73 | 74 | return assertThisInitialized(self); 75 | } 76 | 77 | var possibleConstructorReturn = _possibleConstructorReturn; 78 | 79 | var getPrototypeOf = createCommonjsModule(function (module) { 80 | function _getPrototypeOf(o) { 81 | module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 82 | return o.__proto__ || Object.getPrototypeOf(o); 83 | }; 84 | return _getPrototypeOf(o); 85 | } 86 | 87 | module.exports = _getPrototypeOf; 88 | }); 89 | 90 | var setPrototypeOf = createCommonjsModule(function (module) { 91 | function _setPrototypeOf(o, p) { 92 | module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 93 | o.__proto__ = p; 94 | return o; 95 | }; 96 | 97 | return _setPrototypeOf(o, p); 98 | } 99 | 100 | module.exports = _setPrototypeOf; 101 | }); 102 | 103 | function _inherits(subClass, superClass) { 104 | if (typeof superClass !== "function" && superClass !== null) { 105 | throw new TypeError("Super expression must either be null or a function"); 106 | } 107 | 108 | subClass.prototype = Object.create(superClass && superClass.prototype, { 109 | constructor: { 110 | value: subClass, 111 | writable: true, 112 | configurable: true 113 | } 114 | }); 115 | if (superClass) setPrototypeOf(subClass, superClass); 116 | } 117 | 118 | var inherits = _inherits; 119 | 120 | function _defineProperty(obj, key, value) { 121 | if (key in obj) { 122 | Object.defineProperty(obj, key, { 123 | value: value, 124 | enumerable: true, 125 | configurable: true, 126 | writable: true 127 | }); 128 | } else { 129 | obj[key] = value; 130 | } 131 | 132 | return obj; 133 | } 134 | 135 | var defineProperty = _defineProperty; 136 | 137 | var hashToStyles = function hashToStyles(styleHash) { 138 | var result = ''; 139 | var keys = Object.keys(styleHash); 140 | 141 | for (var _i = 0; _i < keys.length; _i++) { 142 | var key = keys[_i]; 143 | 144 | if (result) { 145 | result += '; '; 146 | } 147 | 148 | result += key + ': ' + styleHash[key]; 149 | } 150 | 151 | return result; 152 | }; 153 | var toPx = function toPx(value) { 154 | if (!value) { 155 | return '0'; 156 | } 157 | 158 | if (typeof value === 'string' && value.endsWith('px')) { 159 | return value; 160 | } 161 | 162 | return "".concat(value, "px"); 163 | }; 164 | 165 | var BulletproofButton = 166 | /*#__PURE__*/ 167 | function (_Component) { 168 | inherits(BulletproofButton, _Component); 169 | 170 | function BulletproofButton() { 171 | var _getPrototypeOf2; 172 | 173 | var _this; 174 | 175 | classCallCheck(this, BulletproofButton); 176 | 177 | for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 178 | args[_key] = arguments[_key]; 179 | } 180 | 181 | _this = possibleConstructorReturn(this, (_getPrototypeOf2 = getPrototypeOf(BulletproofButton)).call.apply(_getPrototypeOf2, [this].concat(args))); 182 | 183 | defineProperty(assertThisInitialized(assertThisInitialized(_this)), "calculateVmlArcSize", function () { 184 | return Math.round(_this.props.borderRadius / _this.props.width * 100).toString() + '%'; 185 | }); 186 | 187 | return _this; 188 | } 189 | 190 | createClass(BulletproofButton, [{ 191 | key: "render", 192 | value: function render() { 193 | var vmlButton = this.renderVmlButton(); 194 | var htmlButton = this.renderHtmlButton(); 195 | return React__default.createElement("div", null, React__default.createElement("div", { 196 | dangerouslySetInnerHTML: { 197 | __html: vmlButton 198 | } 199 | }), React__default.createElement("div", { 200 | dangerouslySetInnerHTML: { 201 | __html: htmlButton 202 | } 203 | })); 204 | } 205 | }, { 206 | key: "renderVmlButton", 207 | value: function renderVmlButton() { 208 | var vmlRectStyles = this.calculateVmlRectStyles(); 209 | var vmlCenterStyles = this.calculateVmlCenterStyles(); 210 | var vmlArcSize = this.calculateVmlArcSize(); 211 | return "\n \n "); 212 | } 213 | }, { 214 | key: "calculateVmlRectStyles", 215 | value: function calculateVmlRectStyles() { 216 | return hashToStyles({ 217 | 'height': toPx(this.props.height), 218 | 'v-text-anchor': 'middle', 219 | 'width': toPx(this.props.width) 220 | }); 221 | } 222 | }, { 223 | key: "calculateVmlCenterStyles", 224 | value: function calculateVmlCenterStyles() { 225 | return hashToStyles({ 226 | 'color': this.props.fontColor, 227 | 'font-family': this.props.fontFamily, 228 | 'font-size': toPx(this.props.fontSize), 229 | 'font-weight': this.props.fontWeight 230 | }); 231 | } 232 | }, { 233 | key: "renderHtmlButton", 234 | value: function renderHtmlButton() { 235 | var htmlLinkStyles = this.calculateHtmlLinkStyles(); 236 | return "\n \n ").concat(this.props.text, "\n \n "); 237 | } 238 | }, { 239 | key: "calculateHtmlLinkStyles", 240 | value: function calculateHtmlLinkStyles() { 241 | return hashToStyles({ 242 | 'background-color': this.props.backgroundColor, 243 | 'border-color': this.props.borderColor, 244 | 'border-style': this.props.borderStyle, 245 | 'border-width': toPx(this.props.borderWidth), 246 | 'border-radius': toPx(this.props.borderRadius), 247 | 'color': this.props.fontColor, 248 | 'display': 'inline-block', 249 | 'font-family': this.props.fontFamily, 250 | 'font-size': toPx(this.props.fontSize), 251 | 'font-weight': this.props.fontWeight, 252 | 'height': toPx(this.props.height), 253 | 'line-height': toPx(this.props.height), 254 | 'mso-hide': 'all', 255 | 'text-align': 'center', 256 | 'text-decoration': 'none', 257 | 'width': toPx(this.props.width), 258 | '-webkit-text-size-adjust': 'none' 259 | }); 260 | } 261 | }]); 262 | 263 | return BulletproofButton; 264 | }(React.Component); 265 | BulletproofButton.defaultProps = { 266 | backgroundColor: '#556270', 267 | borderColor: '#1e3650', 268 | borderRadius: 4, 269 | borderStyle: 'solid', 270 | borderWidth: 1, 271 | fontFamily: 'sans-serif', 272 | fontSize: 13, 273 | fontWeight: 'bold', 274 | fontColor: '#fff', 275 | height: 40, 276 | width: 200 277 | }; 278 | BulletproofButton.propTypes = { 279 | backgroundColor: PropTypes.string, 280 | borderColor: PropTypes.string, 281 | borderRadius: PropTypes.number, 282 | borderStyle: PropTypes.string, 283 | borderWidth: PropTypes.number, 284 | fontColor: PropTypes.string, 285 | fontFamily: PropTypes.string, 286 | fontSize: PropTypes.number, 287 | fontWeight: PropTypes.string, 288 | height: PropTypes.number, 289 | href: PropTypes.string.isRequired, 290 | text: PropTypes.string.isRequired, 291 | width: PropTypes.number 292 | }; 293 | 294 | module.exports = BulletproofButton; 295 | //# sourceMappingURL=index.js.map 296 | -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sources":["../node_modules/@babel/runtime/helpers/classCallCheck.js","../node_modules/@babel/runtime/helpers/createClass.js","../node_modules/@babel/runtime/helpers/typeof.js","../node_modules/@babel/runtime/helpers/assertThisInitialized.js","../node_modules/@babel/runtime/helpers/possibleConstructorReturn.js","../node_modules/@babel/runtime/helpers/getPrototypeOf.js","../node_modules/@babel/runtime/helpers/setPrototypeOf.js","../node_modules/@babel/runtime/helpers/inherits.js","../node_modules/@babel/runtime/helpers/defineProperty.js","../src/util.js","../src/index.js"],"sourcesContent":["function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\nmodule.exports = _classCallCheck;","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\n\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\nmodule.exports = _createClass;","function _typeof2(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof2(obj); }\n\nfunction _typeof(obj) {\n if (typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\") {\n module.exports = _typeof = function _typeof(obj) {\n return _typeof2(obj);\n };\n } else {\n module.exports = _typeof = function _typeof(obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n }\n\n return _typeof(obj);\n}\n\nmodule.exports = _typeof;","function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}\n\nmodule.exports = _assertThisInitialized;","var _typeof = require(\"../helpers/typeof\");\n\nvar assertThisInitialized = require(\"./assertThisInitialized\");\n\nfunction _possibleConstructorReturn(self, call) {\n if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) {\n return call;\n }\n\n return assertThisInitialized(self);\n}\n\nmodule.exports = _possibleConstructorReturn;","function _getPrototypeOf(o) {\n module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {\n return o.__proto__ || Object.getPrototypeOf(o);\n };\n return _getPrototypeOf(o);\n}\n\nmodule.exports = _getPrototypeOf;","function _setPrototypeOf(o, p) {\n module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}\n\nmodule.exports = _setPrototypeOf;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inherits;","function _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}\n\nmodule.exports = _defineProperty;","export const hashToStyles = (styleHash) => {\n let result = '';\n\n const keys = Object.keys(styleHash);\n\n for (let key of keys) {\n if (result) {\n result += '; ';\n }\n\n result += key + ': ' + styleHash[key];\n }\n\n return result;\n};\n\nexport const toPx = (value) => {\n if (!value) { return '0'; }\n if (typeof(value) === 'string' && value.endsWith('px')) { return value; }\n\n return `${value}px`;\n};\n","import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { hashToStyles, toPx } from './util';\n\nexport default class BulletproofButton extends Component {\n render() {\n const vmlButton = this.renderVmlButton();\n const htmlButton = this.renderHtmlButton();\n\n return (\n
\n
\n
\n
\n );\n }\n\n renderVmlButton() {\n const vmlRectStyles = this.calculateVmlRectStyles();\n const vmlCenterStyles = this.calculateVmlCenterStyles();\n const vmlArcSize = this.calculateVmlArcSize();\n\n return `\n \n `;\n }\n\n calculateVmlRectStyles() {\n return hashToStyles({\n 'height': toPx(this.props.height),\n 'v-text-anchor': 'middle',\n 'width': toPx(this.props.width)\n });\n }\n\n calculateVmlCenterStyles() {\n return hashToStyles({\n 'color': this.props.fontColor,\n 'font-family': this.props.fontFamily,\n 'font-size': toPx(this.props.fontSize),\n 'font-weight': this.props.fontWeight\n });\n }\n\n calculateVmlArcSize = () => {\n return Math.round((this.props.borderRadius / this.props.width) * 100).toString() + '%';\n }\n\n renderHtmlButton() {\n const htmlLinkStyles = this.calculateHtmlLinkStyles();\n return `\n \n ${this.props.text}\n \n `;\n }\n\n calculateHtmlLinkStyles() {\n return hashToStyles({\n 'background-color': this.props.backgroundColor,\n 'border-color': this.props.borderColor,\n 'border-style': this.props.borderStyle,\n 'border-width': toPx(this.props.borderWidth),\n 'border-radius': toPx(this.props.borderRadius),\n 'color': this.props.fontColor,\n 'display': 'inline-block',\n 'font-family': this.props.fontFamily,\n 'font-size': toPx(this.props.fontSize),\n 'font-weight': this.props.fontWeight,\n 'height': toPx(this.props.height),\n 'line-height': toPx(this.props.height),\n 'mso-hide': 'all',\n 'text-align': 'center',\n 'text-decoration': 'none',\n 'width': toPx(this.props.width),\n '-webkit-text-size-adjust': 'none'\n });\n }\n}\n\nBulletproofButton.defaultProps = {\n backgroundColor: '#556270',\n borderColor: '#1e3650',\n borderRadius: 4,\n borderStyle: 'solid',\n borderWidth: 1,\n fontFamily: 'sans-serif',\n fontSize: 13,\n fontWeight: 'bold',\n fontColor: '#fff',\n height: 40,\n width: 200\n};\n\nBulletproofButton.propTypes = {\n backgroundColor: PropTypes.string,\n borderColor: PropTypes.string,\n borderRadius: PropTypes.number,\n borderStyle: PropTypes.string,\n borderWidth: PropTypes.number,\n fontColor: PropTypes.string,\n fontFamily: PropTypes.string,\n fontSize: PropTypes.number,\n fontWeight: PropTypes.string,\n height: PropTypes.number,\n href: PropTypes.string.isRequired,\n text: PropTypes.string.isRequired,\n width: PropTypes.number\n};\n"],"names":["_typeof","hashToStyles","styleHash","result","keys","Object","key","toPx","value","endsWith","BulletproofButton","Math","round","props","borderRadius","width","toString","vmlButton","renderVmlButton","htmlButton","renderHtmlButton","React","__html","vmlRectStyles","calculateVmlRectStyles","vmlCenterStyles","calculateVmlCenterStyles","vmlArcSize","calculateVmlArcSize","href","borderColor","backgroundColor","text","height","fontColor","fontFamily","fontSize","fontWeight","htmlLinkStyles","calculateHtmlLinkStyles","borderStyle","borderWidth","Component","defaultProps","propTypes","PropTypes","string","number","isRequired"],"mappings":"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"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bulletproof-button", 3 | "version": "1.0.4", 4 | "description": "React component that creates styled <a> bulletproof email buttons that are compatible with a large list of email clients.", 5 | "author": "jacksontrieu", 6 | "license": "MIT", 7 | "repository": "jacksontrieu/react-bulletproof-button", 8 | "main": "dist/index.js", 9 | "module": "dist/index.es.js", 10 | "jsnext:main": "dist/index.es.js", 11 | "engines": { 12 | "node": ">=8", 13 | "npm": ">=5" 14 | }, 15 | "scripts": { 16 | "test": "jest", 17 | "coverage": "jest --coverage", 18 | "test:watch": "react-scripts test --env=jsdom", 19 | "build": "rollup -c", 20 | "start": "rollup -c -w", 21 | "prepare": "yarn run build" 22 | }, 23 | "peerDependencies": { 24 | "prop-types": "^15.5.4", 25 | "react": "^15.0.0 || ^16.0.0", 26 | "react-dom": "^15.0.0 || ^16.0.0" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "^7.2.2", 30 | "@babel/plugin-external-helpers": "^7.2.0", 31 | "@babel/plugin-proposal-class-properties": "^7.3.0", 32 | "@babel/plugin-transform-runtime": "^7.2.0", 33 | "@babel/preset-env": "^7.3.1", 34 | "@babel/preset-es2015": "^7.0.0-beta.53", 35 | "@babel/preset-es2016": "^7.0.0-beta.53", 36 | "@babel/preset-react": "^7.0.0", 37 | "@babel/preset-stage-0": "^7.0.0", 38 | "@babel/runtime": "^7.3.1", 39 | "@svgr/rollup": "^2.4.1", 40 | "babel-eslint": "^8.2.6", 41 | "cross-env": "^5.1.4", 42 | "eslint": "^5.0.1", 43 | "eslint-config-standard": "^11.0.0", 44 | "eslint-config-standard-react": "^6.0.0", 45 | "eslint-plugin-import": "^2.13.0", 46 | "eslint-plugin-node": "^7.0.1", 47 | "eslint-plugin-promise": "^4.0.0", 48 | "eslint-plugin-react": "^7.10.0", 49 | "eslint-plugin-standard": "^3.1.0", 50 | "gh-pages": "^1.2.0", 51 | "jest": "^24.0.0", 52 | "jest-dom": "^3.0.1", 53 | "react": "^16.4.1", 54 | "react-dom": "^16.4.1", 55 | "react-scripts": "^2.1.3", 56 | "react-test-renderer": "^16.7.0", 57 | "react-testing-library": "^5.4.4", 58 | "rollup": "^0.64.1", 59 | "rollup-plugin-babel": "^4.3.2", 60 | "rollup-plugin-commonjs": "^9.1.3", 61 | "rollup-plugin-node-resolve": "^3.3.0", 62 | "rollup-plugin-peer-deps-external": "^2.2.0", 63 | "rollup-plugin-postcss": "^1.6.2", 64 | "rollup-plugin-url": "^1.4.0" 65 | }, 66 | "files": [ 67 | "dist" 68 | ], 69 | "keywords": [ 70 | "react", 71 | "email", 72 | "reactjs", 73 | "react-components", 74 | "bulletproof-button", 75 | "email-template", 76 | "email-boilerplate", 77 | "email-button", 78 | "bulletproof", 79 | "email-css", 80 | "vml" 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import external from 'rollup-plugin-peer-deps-external' 4 | import postcss from 'rollup-plugin-postcss' 5 | import resolve from 'rollup-plugin-node-resolve' 6 | import url from 'rollup-plugin-url' 7 | import svgr from '@svgr/rollup' 8 | 9 | import pkg from './package.json' 10 | 11 | export default { 12 | input: 'src/index.js', 13 | output: [ 14 | { 15 | file: pkg.main, 16 | format: 'cjs', 17 | sourcemap: true 18 | }, 19 | { 20 | file: pkg.module, 21 | format: 'es', 22 | sourcemap: true 23 | } 24 | ], 25 | plugins: [ 26 | external(), 27 | postcss({ 28 | modules: true 29 | }), 30 | url(), 31 | svgr(), 32 | babel({ 33 | exclude: 'node_modules/**', 34 | runtimeHelpers: true 35 | }), 36 | resolve(), 37 | commonjs() 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /screenshots/react-bulletproof-button-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksontrieu/react-bulletproof-button/560022650729c6c40323b16b9e8b71d7ef83aa2f/screenshots/react-bulletproof-button-2.png -------------------------------------------------------------------------------- /screenshots/react-bulletproof-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacksontrieu/react-bulletproof-button/560022650729c6c40323b16b9e8b71d7ef83aa2f/screenshots/react-bulletproof-button.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { hashToStyles, toPx } from './util'; 4 | 5 | export default class BulletproofButton extends Component { 6 | render() { 7 | const vmlButton = this.renderVmlButton(); 8 | const htmlButton = this.renderHtmlButton(); 9 | 10 | return ( 11 |
12 |
13 |
14 |
15 | ); 16 | } 17 | 18 | renderVmlButton() { 19 | const vmlRectStyles = this.calculateVmlRectStyles(); 20 | const vmlCenterStyles = this.calculateVmlCenterStyles(); 21 | const vmlArcSize = this.calculateVmlArcSize(); 22 | 23 | return ` 24 | 38 | `; 39 | } 40 | 41 | calculateVmlRectStyles() { 42 | return hashToStyles({ 43 | 'height': toPx(this.props.height), 44 | 'v-text-anchor': 'middle', 45 | 'width': toPx(this.props.width) 46 | }); 47 | } 48 | 49 | calculateVmlCenterStyles() { 50 | return hashToStyles({ 51 | 'color': this.props.fontColor, 52 | 'font-family': this.props.fontFamily, 53 | 'font-size': toPx(this.props.fontSize), 54 | 'font-weight': this.props.fontWeight 55 | }); 56 | } 57 | 58 | calculateVmlArcSize = () => { 59 | return Math.round((this.props.borderRadius / this.props.width) * 100).toString() + '%'; 60 | } 61 | 62 | renderHtmlButton() { 63 | const htmlLinkStyles = this.calculateHtmlLinkStyles(); 64 | return ` 65 | 68 | ${this.props.text} 69 | 70 | `; 71 | } 72 | 73 | calculateHtmlLinkStyles() { 74 | return hashToStyles({ 75 | 'background-color': this.props.backgroundColor, 76 | 'border-color': this.props.borderColor, 77 | 'border-style': this.props.borderStyle, 78 | 'border-width': toPx(this.props.borderWidth), 79 | 'border-radius': toPx(this.props.borderRadius), 80 | 'color': this.props.fontColor, 81 | 'display': 'inline-block', 82 | 'font-family': this.props.fontFamily, 83 | 'font-size': toPx(this.props.fontSize), 84 | 'font-weight': this.props.fontWeight, 85 | 'height': toPx(this.props.height), 86 | 'line-height': toPx(this.props.height), 87 | 'mso-hide': 'all', 88 | 'text-align': 'center', 89 | 'text-decoration': 'none', 90 | 'width': toPx(this.props.width), 91 | '-webkit-text-size-adjust': 'none' 92 | }); 93 | } 94 | } 95 | 96 | BulletproofButton.defaultProps = { 97 | backgroundColor: '#556270', 98 | borderColor: '#1e3650', 99 | borderRadius: 4, 100 | borderStyle: 'solid', 101 | borderWidth: 1, 102 | fontFamily: 'sans-serif', 103 | fontSize: 13, 104 | fontWeight: 'bold', 105 | fontColor: '#fff', 106 | height: 40, 107 | width: 200 108 | }; 109 | 110 | BulletproofButton.propTypes = { 111 | backgroundColor: PropTypes.string, 112 | borderColor: PropTypes.string, 113 | borderRadius: PropTypes.number, 114 | borderStyle: PropTypes.string, 115 | borderWidth: PropTypes.number, 116 | fontColor: PropTypes.string, 117 | fontFamily: PropTypes.string, 118 | fontSize: PropTypes.number, 119 | fontWeight: PropTypes.string, 120 | height: PropTypes.number, 121 | href: PropTypes.string.isRequired, 122 | text: PropTypes.string.isRequired, 123 | width: PropTypes.number 124 | }; 125 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | export const hashToStyles = (styleHash) => { 2 | let result = ''; 3 | 4 | const keys = Object.keys(styleHash); 5 | 6 | for (let key of keys) { 7 | if (result) { 8 | result += '; '; 9 | } 10 | 11 | result += key + ': ' + styleHash[key]; 12 | } 13 | 14 | return result; 15 | }; 16 | 17 | export const toPx = (value) => { 18 | if (!value) { return '0'; } 19 | if (typeof(value) === 'string' && value.endsWith('px')) { return value; } 20 | 21 | return `${value}px`; 22 | }; 23 | --------------------------------------------------------------------------------