1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-02 03:25:53 +01:00

Support transparent background + inline picker (#325)

Unfortunately, react-color has a bug where transparent color doesn't trigger onChange. I've been annoyed by the huge dependency anyway so decided to take the generated html (which is awesome) and reimplement a specific component for it.

I also made sure that we don't actually render anything when the background is transparent on rough (I looked at the generated path and made sure it didn't have the commands for the background)
This commit is contained in:
Christopher Chedeau 2020-01-11 19:10:41 -08:00 committed by GitHub
parent 157f0eae0c
commit 8785bef523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 50 deletions

37
package-lock.json generated

@ -1034,11 +1034,6 @@
"@hapi/hoek": "^8.3.0"
}
},
"@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
},
"@jest/console": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
@ -1492,6 +1487,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/nanoid/-/nanoid-2.1.0.tgz",
"integrity": "sha512-xdkn/oRTA0GSNPLIKZgHWqDTWZsVrieKomxJBOQUK9YDD+zfSgmwD5t4WJYra5S7XyhTw7tfvwznW+pFexaepQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
@ -9400,11 +9396,6 @@
"object-visit": "^1.0.0"
}
},
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -12135,19 +12126,6 @@
"whatwg-fetch": "^3.0.0"
}
},
"react-color": {
"version": "2.17.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.17.3.tgz",
"integrity": "sha512-1dtO8LqAVotPIChlmo6kLtFS1FP89ll8/OiA8EcFRDR+ntcK+0ukJgByuIQHRtzvigf26dV5HklnxDIvhON9VQ==",
"requires": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.11",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
}
},
"react-dev-utils": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.0.0.tgz",
@ -12369,14 +12347,6 @@
"workbox-webpack-plugin": "4.3.1"
}
},
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"requires": {
"lodash": "^4.0.1"
}
},
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@ -14459,11 +14429,6 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"tinycolor2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
"integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",

@ -8,7 +8,6 @@
"dependencies": {
"nanoid": "^2.1.9",
"react": "16.12.0",
"react-color": "^2.17.3",
"react-dom": "16.12.0",
"react-scripts": "3.3.0",
"roughjs": "3.1.0"

@ -0,0 +1,89 @@
.color-picker {
width: 205px;
background: rgb(255, 255, 255);
border: 0px solid rgba(0, 0, 0, 0.25);
box-shadow: rgba(0, 0, 0, 0.25) 0px 1px 4px;
border-radius: 4px;
position: relative;
}
.color-picker-triangle-shadow {
width: 0px;
height: 0px;
border-style: solid;
border-width: 0px 9px 10px;
border-color: transparent transparent rgba(0, 0, 0, 0.1);
position: absolute;
top: -11px;
left: 12px;
}
.color-picker-triangle {
width: 0px;
height: 0px;
border-style: solid;
border-width: 0px 9px 10px;
border-color: transparent transparent rgb(255, 255, 255);
position: absolute;
top: -10px;
left: 12px;
}
.color-picker-content {
padding: 15px 9px 9px 15px;
}
.color-picker-swatch {
height: 30px;
width: 30px;
cursor: pointer;
position: relative;
outline: none;
float: left;
border-radius: 4px;
margin: 0px 6px 6px 0px;
}
.color-picker-swatch:focus {
/* Note: in the original react-color it uses the color of the element,
but it's too annoying to set from JavaScript without a css lib... */
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
}
.color-picker-transparent {
border-radius: 4px;
box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px inset;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==")
left center;
}
.color-picker-hash {
background: rgb(240, 240, 240);
height: 30px;
width: 30px;
border-radius: 4px 0px 0px 4px;
float: left;
color: rgb(152, 161, 164);
display: flex;
align-items: center;
justify-content: center;
}
.color-picker-input {
width: 100px;
font-size: 14px;
color: rgb(102, 102, 102);
border: 0px;
outline: none;
height: 28px;
box-shadow: rgb(240, 240, 240) 0px 0px 0px 1px inset;
box-sizing: content-box;
border-radius: 0px 4px 4px 0px;
float: left;
padding-left: 8px;
}

@ -1,11 +1,66 @@
import React, { lazy } from "react";
import React from "react";
import { Popover } from "./Popover";
const TwitterPicker = lazy(() =>
import(
/* webpackPrefetch: true */ "react-color/lib/components/twitter/Twitter"
)
);
import "./ColorPicker.css";
// This is a narrow reimplementation of the awesome react-color Twitter component
// https://github.com/casesandberg/react-color/blob/master/src/components/twitter/Twitter.js
const Picker = function({
colors,
color,
onChange
}: {
colors: string[];
color: string | undefined;
onChange: (color: string) => void;
}) {
const [innerValue, setInnerValue] = React.useState(color);
React.useEffect(() => {
setInnerValue(color);
}, [color]);
return (
<div className="color-picker">
<div className="color-picker-triangle-shadow"></div>
<div className="color-picker-triangle"></div>
<div className="color-picker-content">
{colors.map(color => (
<div
className="color-picker-swatch"
onClick={() => {
onChange(color);
}}
title={color}
tabIndex={0}
style={{ backgroundColor: color }}
>
{color === "transparent" ? (
<div className="color-picker-transparent"></div>
) : (
undefined
)}
</div>
))}
<div className="color-picker-hash">#</div>
<div style={{ position: "relative" }}>
<input
spellCheck={false}
className="color-picker-input"
onChange={e => {
const value = e.target.value;
if (value.match(/^([0-9a-f]{3}|[0-9a-f]{6}|transparent)$/)) {
onChange(value === "transparent" ? "transparent" : "#" + value);
}
setInnerValue(value);
}}
value={(innerValue || "").replace(/^#/, "")}
/>
</div>
<div style={{ clear: "both" }}></div>
</div>
</div>
);
};
export function ColorPicker({
type,
@ -27,12 +82,11 @@ export function ColorPicker({
<React.Suspense fallback="">
{isActive ? (
<Popover onCloseRequest={() => setActive(false)}>
<TwitterPicker
<Picker
colors={colors[type]}
width="205px"
color={color || undefined}
onChange={changedColor => {
onChange(changedColor.hex);
onChange(changedColor);
}}
/>
</Popover>
@ -74,7 +128,7 @@ const colors = {
"#FF9DA7",
"#9C755F",
"#BAB0AB",
"#FFFFFF"
"transparent"
],
elementStroke: [
"#324E6B",

@ -22,7 +22,10 @@ export function renderElement(
element.shape = withCustomMathRandom(element.seed, () => {
return generator.rectangle(0, 0, element.width, element.height, {
stroke: element.strokeColor,
fill: element.backgroundColor,
fill:
element.backgroundColor === "transparent"
? undefined
: element.backgroundColor,
fillStyle: element.fillStyle,
strokeWidth: element.strokeWidth,
roughness: element.roughness
@ -55,7 +58,10 @@ export function renderElement(
],
{
stroke: element.strokeColor,
fill: element.backgroundColor,
fill:
element.backgroundColor === "transparent"
? undefined
: element.backgroundColor,
fillStyle: element.fillStyle,
strokeWidth: element.strokeWidth,
roughness: element.roughness
@ -77,7 +83,10 @@ export function renderElement(
element.height,
{
stroke: element.strokeColor,
fill: element.backgroundColor,
fill:
element.backgroundColor === "transparent"
? undefined
: element.backgroundColor,
fillStyle: element.fillStyle,
strokeWidth: element.strokeWidth,
roughness: element.roughness