@helpscout/artboard
Version:
A tool kit for React UI development and design
296 lines (233 loc) • 13.2 kB
JavaScript
;
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;