mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Add ColorInput component (#455)
* Add ColorInput component * Use valid color on input blur * Darken input text and add labels
This commit is contained in:
parent
7f6e1f420e
commit
7ae52f1164
2 changed files with 96 additions and 58 deletions
|
@ -15,71 +15,105 @@ const Picker = function({
|
|||
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 }}
|
||||
key={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 className="colors-gallery">
|
||||
{colors.map(color => (
|
||||
<div
|
||||
className="color-picker-swatch"
|
||||
onClick={() => {
|
||||
onChange(color);
|
||||
}}
|
||||
title={color}
|
||||
tabIndex={0}
|
||||
style={{ backgroundColor: color }}
|
||||
key={color}
|
||||
>
|
||||
{color === "transparent" ? (
|
||||
<div className="color-picker-transparent"></div>
|
||||
) : (
|
||||
undefined
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ clear: "both" }}></div>
|
||||
<ColorInput
|
||||
color={color}
|
||||
onChange={color => {
|
||||
onChange(color);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function ColorInput({
|
||||
color,
|
||||
onChange
|
||||
}: {
|
||||
color: string | undefined;
|
||||
onChange: (color: string) => void;
|
||||
}) {
|
||||
const colorRegex = /^([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8}|transparent)$/;
|
||||
const [innerValue, setInnerValue] = React.useState(color);
|
||||
|
||||
React.useEffect(() => {
|
||||
setInnerValue(color);
|
||||
}, [color]);
|
||||
|
||||
return (
|
||||
<div className="color-input-container">
|
||||
<div className="color-picker-hash">#</div>
|
||||
<input
|
||||
spellCheck={false}
|
||||
className="color-picker-input"
|
||||
aria-label="Hex color code"
|
||||
onChange={e => {
|
||||
const value = e.target.value;
|
||||
if (value.match(colorRegex)) {
|
||||
onChange(value === "transparent" ? "transparent" : "#" + value);
|
||||
}
|
||||
setInnerValue(value);
|
||||
}}
|
||||
value={(innerValue || "").replace(/^#/, "")}
|
||||
onPaste={e => onChange(e.clipboardData.getData("text"))}
|
||||
onBlur={() => setInnerValue(color)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ColorPicker({
|
||||
type,
|
||||
color,
|
||||
onChange
|
||||
}: {
|
||||
type: "canvasBackground" | "elementBackground" | "elementStroke";
|
||||
color: string | null;
|
||||
color: string | undefined;
|
||||
onChange: (color: string) => void;
|
||||
}) {
|
||||
const [isActive, setActive] = React.useState(false);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button
|
||||
className="color-picker-label-swatch"
|
||||
style={color ? { backgroundColor: color } : undefined}
|
||||
onClick={() => setActive(!isActive)}
|
||||
/>
|
||||
<div className="color-picker-control-container">
|
||||
<button
|
||||
className="color-picker-label-swatch"
|
||||
aria-label="Change color"
|
||||
style={color ? { backgroundColor: color } : undefined}
|
||||
onClick={() => setActive(!isActive)}
|
||||
/>
|
||||
<ColorInput
|
||||
color={color}
|
||||
onChange={color => {
|
||||
onChange(color);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<React.Suspense fallback="">
|
||||
{isActive ? (
|
||||
<Popover onCloseRequest={() => setActive(false)}>
|
||||
|
@ -93,13 +127,6 @@ export function ColorPicker({
|
|||
</Popover>
|
||||
) : null}
|
||||
</React.Suspense>
|
||||
<input
|
||||
type="text"
|
||||
className="color-picker-swatch-input"
|
||||
value={color || ""}
|
||||
onPaste={e => onChange(e.clipboardData.getData("text"))}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue