qrcode.react
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -1,4 +0,11 @@ | ||
## [Unreleased] | ||
## [0.9.0] - 2018-12-22 | ||
### Added | ||
- Support for `includeMargin` prop, to include the "quiet zone" in rendering | ||
### Changed | ||
- Updated canvas renderer to use Path2D (where available), and simplify the render. This fixes some rendering inconsistencies. | ||
- Switched to using `React.PureComponent` instead of a custom `shouldComponentUpdate` method. | ||
## [0.8.0] - 2018-02-19 | ||
@@ -5,0 +12,0 @@ |
302
lib/index.js
@@ -7,4 +7,8 @@ 'use strict'; | ||
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } | ||
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } | ||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -16,8 +20,14 @@ | ||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
var React = require('react'); | ||
@@ -31,13 +41,3 @@ | ||
var ErrorCorrectLevel = require('qr.js/lib/ErrorCorrectLevel'); | ||
function getBackingStorePixelRatio(ctx) { | ||
return (// $FlowFixMe | ||
ctx.webkitBackingStorePixelRatio || // $FlowFixMe | ||
ctx.mozBackingStorePixelRatio || // $FlowFixMe | ||
ctx.msBackingStorePixelRatio || // $FlowFixMe | ||
ctx.oBackingStorePixelRatio || // $FlowFixMe | ||
ctx.backingStorePixelRatio || 1 | ||
); | ||
} // Convert from UTF-16, forcing the use of byte-mode encoding in our QR Code. | ||
var ErrorCorrectLevel = require('qr.js/lib/ErrorCorrectLevel'); // Convert from UTF-16, forcing the use of byte-mode encoding in our QR Code. | ||
// This allows us to encode Hanji, Kanji, emoji, etc. Ideally we'd do more | ||
@@ -83,3 +83,4 @@ // detection and not resort to byte-mode if possible, but we're trading off | ||
bgColor: '#FFFFFF', | ||
fgColor: '#000000' | ||
fgColor: '#000000', | ||
includeMargin: false | ||
}; | ||
@@ -91,14 +92,62 @@ var PROP_TYPES = { | ||
bgColor: PropTypes.string, | ||
fgColor: PropTypes.string | ||
fgColor: PropTypes.string, | ||
includeMargin: PropTypes.bool | ||
}; | ||
var MARGIN_SIZE = 4; | ||
function generatePath(modules) { | ||
var margin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
var ops = []; | ||
modules.forEach(function (row, y) { | ||
var start = null; | ||
row.forEach(function (cell, x) { | ||
if (!cell && start !== null) { | ||
// M0 0h7v1H0z injects the space with the move and drops the comma, | ||
// saving a char per operation | ||
ops.push("M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z")); | ||
start = null; | ||
return; | ||
} // end of row, clean up or skip | ||
if (x === row.length - 1) { | ||
if (!cell) { | ||
// We would have closed the op above already so this can only mean | ||
// 2+ light modules in a row. | ||
return; | ||
} | ||
if (start === null) { | ||
// Just a single dark module. | ||
ops.push("M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z")); | ||
} else { | ||
// Otherwise finish the current line. | ||
ops.push("M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z")); | ||
} | ||
return; | ||
} | ||
if (cell && start === null) { | ||
start = x; | ||
} | ||
}); | ||
}); | ||
return ops.join(''); | ||
} // For canvas we're going to switch our drawing mode based on whether or not | ||
// the environment supports Path2D. We only need the constructor to be | ||
// supported. | ||
var SUPPORTS_PATH2D = typeof Path2D === 'function'; | ||
var QRCodeCanvas = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(QRCodeCanvas, _React$Component); | ||
function (_React$PureComponent) { | ||
_inherits(QRCodeCanvas, _React$PureComponent); | ||
function QRCodeCanvas() { | ||
var _ref; | ||
var _getPrototypeOf2; | ||
var _temp, _this; | ||
var _this; | ||
@@ -111,20 +160,10 @@ _classCallCheck(this, QRCodeCanvas); | ||
return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_ref = QRCodeCanvas.__proto__ || Object.getPrototypeOf(QRCodeCanvas)).call.apply(_ref, [this].concat(args))), Object.defineProperty(_assertThisInitialized(_this), "_canvas", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value: void 0 | ||
}), _temp)); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(QRCodeCanvas)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_canvas", void 0); | ||
return _this; | ||
} | ||
_createClass(QRCodeCanvas, [{ | ||
key: "shouldComponentUpdate", | ||
value: function shouldComponentUpdate(nextProps) { | ||
var _this2 = this; | ||
return Object.keys(QRCodeCanvas.propTypes).some(function (k) { | ||
return _this2.props[k] !== nextProps[k]; | ||
}); | ||
} | ||
}, { | ||
key: "componentDidMount", | ||
@@ -142,8 +181,9 @@ value: function componentDidMount() { | ||
value: function update() { | ||
var _props = this.props, | ||
value = _props.value, | ||
size = _props.size, | ||
level = _props.level, | ||
bgColor = _props.bgColor, | ||
fgColor = _props.fgColor; // We'll use type===-1 to force QRCode to automatically pick the best type | ||
var _this$props = this.props, | ||
value = _this$props.value, | ||
size = _this$props.size, | ||
level = _this$props.level, | ||
bgColor = _this$props.bgColor, | ||
fgColor = _this$props.fgColor, | ||
includeMargin = _this$props.includeMargin; // We'll use type===-1 to force QRCode to automatically pick the best type | ||
@@ -168,15 +208,29 @@ var qrcode = new QRCodeImpl(-1, ErrorCorrectLevel[level]); | ||
var tileW = size / cells.length; | ||
var tileH = size / cells.length; | ||
var scale = (window.devicePixelRatio || 1) / getBackingStorePixelRatio(ctx); | ||
canvas.height = canvas.width = size * scale; | ||
ctx.scale(scale, scale); | ||
cells.forEach(function (row, rdx) { | ||
row.forEach(function (cell, cdx) { | ||
ctx && (ctx.fillStyle = cell ? fgColor : bgColor); | ||
var w = Math.ceil((cdx + 1) * tileW) - Math.floor(cdx * tileW); | ||
var h = Math.ceil((rdx + 1) * tileH) - Math.floor(rdx * tileH); | ||
ctx && ctx.fillRect(Math.round(cdx * tileW), Math.round(rdx * tileH), w, h); | ||
var margin = includeMargin ? MARGIN_SIZE : 0; | ||
var numCells = cells.length + margin * 2; // We're going to scale this so that the number of drawable units | ||
// matches the number of cells. This avoids rounding issues, but does | ||
// result in some potentially unwanted single pixel issues between | ||
// blocks, only in environments that don't support Path2D. | ||
var pixelRatio = window.devicePixelRatio || 1; | ||
canvas.height = canvas.width = size * pixelRatio; | ||
var scale = size / numCells * pixelRatio; | ||
ctx.scale(scale, scale); // Draw solid background, only paint dark modules. | ||
ctx.fillStyle = bgColor; | ||
ctx.fillRect(0, 0, numCells, numCells); | ||
ctx.fillStyle = fgColor; | ||
if (SUPPORTS_PATH2D) { | ||
// $FlowFixMe: Path2D c'tor doesn't support args yet. | ||
ctx.fill(new Path2D(generatePath(cells))); | ||
} else { | ||
cells.forEach(function (row, rdx) { | ||
row.forEach(function (cell, cdx) { | ||
if (cell) { | ||
ctx.fillRect(cdx + margin, rdx + margin, 1, 1); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -187,14 +241,14 @@ } | ||
value: function render() { | ||
var _this3 = this; | ||
var _this2 = this; | ||
var _props2 = this.props, | ||
value = _props2.value, | ||
size = _props2.size, | ||
level = _props2.level, | ||
bgColor = _props2.bgColor, | ||
fgColor = _props2.fgColor, | ||
style = _props2.style, | ||
otherProps = _objectWithoutProperties(_props2, ["value", "size", "level", "bgColor", "fgColor", "style"]); | ||
var _this$props2 = this.props, | ||
value = _this$props2.value, | ||
size = _this$props2.size, | ||
level = _this$props2.level, | ||
bgColor = _this$props2.bgColor, | ||
fgColor = _this$props2.fgColor, | ||
style = _this$props2.style, | ||
otherProps = _objectWithoutProperties(_this$props2, ["value", "size", "level", "bgColor", "fgColor", "style"]); | ||
var canvasStyle = _extends({ | ||
var canvasStyle = _objectSpread({ | ||
height: size, | ||
@@ -208,4 +262,4 @@ width: size | ||
width: size, | ||
ref: function ref(_ref2) { | ||
return _this3._canvas = _ref2; | ||
ref: function ref(_ref) { | ||
return _this2._canvas = _ref; | ||
} | ||
@@ -217,21 +271,12 @@ }, otherProps)); | ||
return QRCodeCanvas; | ||
}(React.Component); | ||
}(React.PureComponent); | ||
Object.defineProperty(QRCodeCanvas, "defaultProps", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value: DEFAULT_PROPS | ||
}); | ||
Object.defineProperty(QRCodeCanvas, "propTypes", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value: PROP_TYPES | ||
}); | ||
_defineProperty(QRCodeCanvas, "defaultProps", DEFAULT_PROPS); | ||
_defineProperty(QRCodeCanvas, "propTypes", PROP_TYPES); | ||
var QRCodeSVG = | ||
/*#__PURE__*/ | ||
function (_React$Component2) { | ||
_inherits(QRCodeSVG, _React$Component2); | ||
function (_React$PureComponent2) { | ||
_inherits(QRCodeSVG, _React$PureComponent2); | ||
@@ -241,24 +286,16 @@ function QRCodeSVG() { | ||
return _possibleConstructorReturn(this, (QRCodeSVG.__proto__ || Object.getPrototypeOf(QRCodeSVG)).apply(this, arguments)); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(QRCodeSVG).apply(this, arguments)); | ||
} | ||
_createClass(QRCodeSVG, [{ | ||
key: "shouldComponentUpdate", | ||
value: function shouldComponentUpdate(nextProps) { | ||
var _this4 = this; | ||
return Object.keys(QRCodeCanvas.propTypes).some(function (k) { | ||
return _this4.props[k] !== nextProps[k]; | ||
}); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _props3 = this.props, | ||
value = _props3.value, | ||
size = _props3.size, | ||
level = _props3.level, | ||
bgColor = _props3.bgColor, | ||
fgColor = _props3.fgColor, | ||
otherProps = _objectWithoutProperties(_props3, ["value", "size", "level", "bgColor", "fgColor"]); // We'll use type===-1 to force QRCode to automatically pick the best type | ||
var _this$props3 = this.props, | ||
value = _this$props3.value, | ||
size = _this$props3.size, | ||
level = _this$props3.level, | ||
bgColor = _this$props3.bgColor, | ||
fgColor = _this$props3.fgColor, | ||
includeMargin = _this$props3.includeMargin, | ||
otherProps = _objectWithoutProperties(_this$props3, ["value", "size", "level", "bgColor", "fgColor", "includeMargin"]); // We'll use type===-1 to force QRCode to automatically pick the best type | ||
@@ -272,4 +309,6 @@ | ||
if (cells === null) { | ||
return; | ||
} // Drawing strategy: instead of a rect per module, we're going to create a | ||
return null; | ||
} | ||
var margin = includeMargin ? MARGIN_SIZE : 0; // Drawing strategy: instead of a rect per module, we're going to create a | ||
// single path for the dark modules and layer that on top of a light rect, | ||
@@ -281,40 +320,4 @@ // for a total of 2 DOM nodes. We pay a bit more in string concat but that's | ||
var ops = []; | ||
cells.forEach(function (row, y) { | ||
var lastIsDark = false; | ||
var start = null; | ||
row.forEach(function (cell, x) { | ||
if (!cell && start !== null) { | ||
// M0 0h7v1H0z injects the space with the move and dropd the comma, | ||
// saving a char per operation | ||
ops.push("M".concat(start, " ").concat(y, "h").concat(x - start, "v1H").concat(start, "z")); | ||
start = null; | ||
return; | ||
} // end of row, clean up or skip | ||
if (x === row.length - 1) { | ||
if (!cell) { | ||
// We would have closed the op above already so this can only mean | ||
// 2+ light modules in a row. | ||
return; | ||
} | ||
if (start === null) { | ||
// Just a single dark module. | ||
ops.push("M".concat(x, ",").concat(y, " h1v1H").concat(x, "z")); | ||
} else { | ||
// Otherwise finish the current line. | ||
ops.push("M".concat(start, ",").concat(y, " h").concat(x + 1 - start, "v1H").concat(start, "z")); | ||
} | ||
return; | ||
} | ||
if (cell && start === null) { | ||
start = x; | ||
} | ||
}); | ||
}); | ||
var fgPath = generatePath(cells, margin); | ||
var numCells = cells.length + margin * 2; | ||
return React.createElement("svg", _extends({ | ||
@@ -324,9 +327,9 @@ shapeRendering: "crispEdges", | ||
width: size, | ||
viewBox: "0 0 ".concat(cells.length, " ").concat(cells.length) | ||
viewBox: "0 0 ".concat(numCells, " ").concat(numCells) | ||
}, otherProps), React.createElement("path", { | ||
fill: bgColor, | ||
d: "M0,0 h".concat(cells.length, "v").concat(cells.length, "H0z") | ||
d: "M0,0 h".concat(numCells, "v").concat(numCells, "H0z") | ||
}), React.createElement("path", { | ||
fill: fgColor, | ||
d: ops.join('') | ||
d: fgPath | ||
})); | ||
@@ -337,17 +340,8 @@ } | ||
return QRCodeSVG; | ||
}(React.Component); | ||
}(React.PureComponent); | ||
Object.defineProperty(QRCodeSVG, "defaultProps", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value: DEFAULT_PROPS | ||
}); | ||
Object.defineProperty(QRCodeSVG, "propTypes", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value: PROP_TYPES | ||
}); | ||
_defineProperty(QRCodeSVG, "defaultProps", DEFAULT_PROPS); | ||
_defineProperty(QRCodeSVG, "propTypes", PROP_TYPES); | ||
var QRCode = function QRCode(props) { | ||
@@ -361,5 +355,5 @@ var renderAs = props.renderAs, | ||
QRCode.defaultProps = _extends({ | ||
QRCode.defaultProps = _objectSpread({ | ||
renderAs: 'canvas' | ||
}, DEFAULT_PROPS); | ||
module.exports = QRCode; |
{ | ||
"name": "qrcode.react", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "React component to generate QR codes", | ||
@@ -14,4 +14,4 @@ "keywords": [ | ||
"flow": "flow", | ||
"lint": "eslint src/ examples/demo.js", | ||
"pretty": "prettier --write --single-quote --bracket-spacing=false --trailing-comma=es5 {.eslintrc.js,src/*.js,examples/demo.js}", | ||
"lint": "eslint .", | ||
"pretty": "prettier --write {*,.*}.{js,json} **/*.{js,json}", | ||
"prepublish": "flow && make clean && make all", | ||
@@ -39,21 +39,24 @@ "prepublish-docs": "make clean && make all", | ||
"devDependencies": { | ||
"@babel/cli": "^7.0.0-beta.39", | ||
"@babel/core": "^7.0.0-beta.39", | ||
"@babel/plugin-proposal-class-properties": "^7.0.0-beta.39", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.39", | ||
"@babel/preset-env": "^7.0.0-beta.39", | ||
"@babel/preset-flow": "^7.0.0-beta.39", | ||
"@babel/preset-react": "^7.0.0-beta.39", | ||
"babel-eslint": "^8.2.1", | ||
"babel-loader": "^8.0.0-beta.0", | ||
"eslint": "^4.17.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
"@babel/cli": "^7.0.0", | ||
"@babel/core": "^7.0.0", | ||
"@babel/plugin-proposal-class-properties": "^7.0.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/preset-env": "^7.0.0", | ||
"@babel/preset-flow": "^7.0.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-loader": "^8.0.0", | ||
"eslint": "^5.4.0", | ||
"eslint-config-prettier": "^3.0.1", | ||
"eslint-plugin-flowtype": "^3.2.0", | ||
"eslint-plugin-prettier": "^3.0.0", | ||
"eslint-plugin-react": "^7.6.1", | ||
"flow-bin": "^0.64.0", | ||
"gh-pages": "^0.12.0", | ||
"flow-bin": "^0.89.0", | ||
"gh-pages": "^2.0.1", | ||
"prettier": "^1.1.0", | ||
"react": "^16.2.0", | ||
"react-dom": "^16.2.0", | ||
"webpack": "^3.11.0" | ||
"webpack": "^4.28.1", | ||
"webpack-cli": "^3.1.2" | ||
} | ||
} |
@@ -33,2 +33,3 @@ # qrcode.react | ||
`level` | `string` (`'L' 'M' 'Q' 'H'`) | `'L'` | ||
`includeMargin` | `boolean` | `false` | ||
@@ -35,0 +36,0 @@ ## Custom Styles |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
19590
45
21
276