UNPKG

@helpscout/artboard

Version:

A tool kit for React UI development and design

296 lines (233 loc) 13.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Eyedropper = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _templateObject = _taggedTemplateLiteral(['\n box-sizing: border-box;\n border: 3px solid white;\n border-radius: 9999px;\n position: fixed;\n z-index: 999999;\n top: 0;\n left: 0;\n will-change: transform, box-shadow;\n\n ', ' * {\n box-sizing: border-box;\n }\n'], ['\n box-sizing: border-box;\n border: 3px solid white;\n border-radius: 9999px;\n position: fixed;\n z-index: 999999;\n top: 0;\n left: 0;\n will-change: transform, box-shadow;\n\n ', ' * {\n box-sizing: border-box;\n }\n']), _templateObject2 = _taggedTemplateLiteral(['\n box-sizing: border-box;\n border: 1px solid white;\n box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);\n border-radius: 9999px;\n height: 6px;\n width: 6px;\n position: absolute;\n top: 50%;\n left: 50%;\n margin: -3px 0 0 -3px;\n z-index: 999999;\n'], ['\n box-sizing: border-box;\n border: 1px solid white;\n box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);\n border-radius: 9999px;\n height: 6px;\n width: 6px;\n position: absolute;\n top: 50%;\n left: 50%;\n margin: -3px 0 0 -3px;\n z-index: 999999;\n']), _templateObject3 = _taggedTemplateLiteral(['\n border-radius: 4px;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Helvetica, Arial,\n sans-serif, \'Apple Color Emoji\', \'Segoe UI Emoji\', \'Segoe UI Symbol\';\n font-size: 10px;\n line-height: 1;\n padding: 4px 4px;\n position: absolute;\n bottom: 13px;\n width: 54px;\n left: 50%;\n margin-left: -27px;\n text-align: center;\n z-index: 999999;\n'], ['\n border-radius: 4px;\n background: rgba(0, 0, 0, 0.7);\n color: white;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Helvetica, Arial,\n sans-serif, \'Apple Color Emoji\', \'Segoe UI Emoji\', \'Segoe UI Symbol\';\n font-size: 10px;\n line-height: 1;\n padding: 4px 4px;\n position: absolute;\n bottom: 13px;\n width: 54px;\n left: 50%;\n margin-left: -27px;\n text-align: center;\n z-index: 999999;\n']), _templateObject4 = _taggedTemplateLiteral(['\n display: block;\n border-radius: 99999px;\n position: absolute;\n top: 50%;\n left: 50%;\n z-index: -1;\n\n ', ';\n'], ['\n display: block;\n border-radius: 99999px;\n position: absolute;\n top: 50%;\n left: 50%;\n z-index: -1;\n\n ', ';\n']), _templateObject5 = _taggedTemplateLiteral(['\n background: url(', ') 1px 1px repeat;\n position: absolute;\n opacity: 0.2;\n top: 0;\n left: 0;\n border-radius: 9999px;\n width: 100%;\n height: 100%;\n z-index: 999999;\n'], ['\n background: url(', ') 1px 1px repeat;\n position: absolute;\n opacity: 0.2;\n top: 0;\n left: 0;\n border-radius: 9999px;\n width: 100%;\n height: 100%;\n z-index: 999999;\n']); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _html2canvas = require('html2canvas'); var _html2canvas2 = _interopRequireDefault(_html2canvas); var _fancy = require('@helpscout/fancy'); var _fancy2 = _interopRequireDefault(_fancy); var _utils = require('../utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } 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; } var GRID_PATTERN = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAGElEQVQYV2NkYGD4z4ADMEIlQTQGGHSSABNFBwdl5cZ4AAAAAElFTkSuQmCC'; var Eyedropper = exports.Eyedropper = function (_React$Component) { _inherits(Eyedropper, _React$Component); function Eyedropper() { var _ref; var _temp, _this, _ret; _classCallCheck(this, Eyedropper); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Eyedropper.__proto__ || Object.getPrototypeOf(Eyedropper)).call.apply(_ref, [this].concat(args))), _this), _this.state = { canvas: undefined, color: undefined, isInPreviewMode: false, mouseX: 0, mouseY: 0, bodyOffsetX: 0, bodyOffsetY: 0, isProcessing: false }, _this._isMounted = false, _this.safeSetState = function (state, callback) { if (!_this._isMounted) return; _this.setState(state, function (props) { if (callback && typeof callback === 'function') { callback(props); } }); }, _this.handleOnClick = function (event) { if (!_this.state.isInPreviewMode) { _this.startPreviewMode(event); } else { _this.stopPreviewMode(); } }, _this.handleOnKeyUp = function (event) { if (_this.state.isInPreviewMode) { if (event.keyCode === _utils.Keys.ESC) { _this.closePreview(); } } }, _this.startPreviewMode = function () { var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { x: 0, y: 0 }; if (!_this.props.isActive) return; if (_this.state.isProcessing) return; var x = event.x, y = event.y; _this.props.onStart(); _this.safeSetState({ isProcessing: true }, function () { (0, _html2canvas2.default)(document.body, { logging: _this.props.__debug, scale: 1 }).then(function (canvas) { document.body.style.cursor = 'none'; _this.props.onReady(); _this.safeSetState({ canvas: canvas, isInPreviewMode: true, isProcessing: false, mouseX: x, mouseY: y }); }); }); }, _this.stopPreviewMode = function () { _this.copyColorToClipboard(); console.log('Selected color ' + _this.state.color); _this.closePreview(); }, _this.closePreview = function () { document.body.style.cursor = null; _this.props.onStop(_this.state.color); _this.safeSetState({ color: undefined, isInPreviewMode: false }); }, _this.colorPreview = function (event) { if (!_this.state.canvas) return; var x = event.x, y = event.y; var color = getColorFromCanvas(_this.state.canvas, x, y); _this.renderPreviewCanvas(x, y); _this.safeSetState({ color: color, mouseX: x, mouseY: y }); }, _this.copyColorToClipboard = function () { var el = document.createElement('textarea'); el.value = _this.state.color; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); }, _this.renderPreviewCanvas = function (x, y) { if (!_this.state.canvas || !_this.previewCanvas) return; if (!_this.state.isInPreviewMode) return; var _this$props = _this.props, previewSize = _this$props.previewSize, previewScale = _this$props.previewScale; var context = _this.previewCanvas.getContext('2d'); var canvasSize = Math.round(previewSize / previewScale); var offsetPreviewSize = Math.round(canvasSize / 2); var accuracyBuffer = 0.5; // For non-2x resolution displays context.drawImage(_this.state.canvas, x - offsetPreviewSize + accuracyBuffer, y - offsetPreviewSize + accuracyBuffer, canvasSize, canvasSize, 0, 0, canvasSize, canvasSize); }, _this.getColorPreviewStyles = function () { var _this$state = _this.state, color = _this$state.color, isInPreviewMode = _this$state.isInPreviewMode, mouseX = _this$state.mouseX, mouseY = _this$state.mouseY; return { boxShadow: '\n 0 0 0 3px ' + color + ',\n 0 0 0 4px white,\n 0 2px 4px rgba(0, 0, 0, 0.1),\n 0 0px 12px 3px rgba(0, 0, 0, 0.3),\n 0 8px 20px rgba(0, 0, 0, 0.2)\n ', display: isInPreviewMode ? 'block' : 'none', transform: 'translate(' + (mouseX - 50) + 'px,' + (mouseY - 50) + 'px)' }; }, _this.setPreviewNodeRef = function (node) { return _this.previewCanvas = node; }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(Eyedropper, [{ key: 'componentDidMount', value: function componentDidMount() { this._isMounted = true; window.addEventListener('click', this.handleOnClick); window.addEventListener('mousemove', this.colorPreview); window.addEventListener('keyup', this.handleOnKeyUp); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this._isMounted = false; window.removeEventListener('click', this.handleOnClick); window.removeEventListener('mousemove', this.colorPreview); window.removeEventListener('keyup', this.handleOnKeyUp); this.closePreview(); } }, { key: 'render', value: function render() { var _props = this.props, previewSize = _props.previewSize, previewScale = _props.previewScale; var color = this.state.color; var previewNodeSize = Math.round(previewSize / previewScale); return _react2.default.createElement( ColorPreviewUI, { style: this.getColorPreviewStyles(), previewSize: previewSize }, _react2.default.createElement(GridUI, null), _react2.default.createElement(PreviewCanvasUI, { ref: 'previewCanvas', innerRef: this.setPreviewNodeRef, width: previewNodeSize, height: previewNodeSize, previewSize: previewSize, previewScale: previewScale }), _react2.default.createElement(CrosshairUI, null), _react2.default.createElement( LabelUI, null, color ) ); } }]); return Eyedropper; }(_react2.default.Component); Eyedropper.defaultProps = { __debug: false, isActive: true, onPickColor: _utils.noop, onStart: _utils.noop, onReady: _utils.noop, onStop: _utils.noop, previewSize: 100, previewScale: 5 }; function getColorFromCanvas(canvas, x, y) { var croppedCanvas = document.createElement('canvas'); var croppedCanvasContext = croppedCanvas.getContext('2d'); croppedCanvas.width = 1; croppedCanvas.height = 1; croppedCanvasContext.drawImage(canvas, x, y, 1, 1, 0, 0, 1, 1); var colorRawValues = croppedCanvasContext.getImageData(0, 0, 1, 1).data; var hexColor = getHexFromRawCanvasColor(colorRawValues); return hexColor; } function rgbToHex(r, g, b) { if (r > 255 || g > 255 || b > 255) return; return (r << 16 | g << 8 | b).toString(16); } function getHexFromRawCanvasColor(rawCanvasColor) { return '#' + ('000000' + rgbToHex(rawCanvasColor[0], rawCanvasColor[1], rawCanvasColor[2])).slice(-6); } var ColorPreviewUI = (0, _fancy2.default)('div')(_templateObject, function (_ref2) { var previewSize = _ref2.previewSize; return '\n height: ' + previewSize + 'px;\n width: ' + previewSize + 'px;\n '; }); var CrosshairUI = (0, _fancy2.default)('div')(_templateObject2); var LabelUI = (0, _fancy2.default)('div')(_templateObject3); var PreviewCanvasUI = (0, _fancy2.default)('canvas')(_templateObject4, function (_ref3) { var previewSize = _ref3.previewSize, previewScale = _ref3.previewScale; var canvasSize = Math.round(previewSize / previewScale); return '\n height: ' + canvasSize + 'px;\n width: ' + canvasSize + 'px;\n transform: translate(-50%, -50%) scale(' + previewScale + ');\n '; }); var GridUI = (0, _fancy2.default)('div')(_templateObject5, GRID_PATTERN); exports.default = Eyedropper;