Skip to content

Commit

Permalink
Cursor starts working properly
Browse files Browse the repository at this point in the history
  • Loading branch information
arcatdmz committed Jul 5, 2020
1 parent 9ce5893 commit a26f514
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 17 deletions.
21 changes: 20 additions & 1 deletion docs/components/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { FC, useState } from "react";
import { ColorPanel } from "./ColorPanel";

export const Body: FC = () => {
const [color, setColor] = useState<tinycolor.Instance>(null);

return (
<div className="demo body">
<style jsx>{`
Expand All @@ -13,9 +15,26 @@ export const Body: FC = () => {
border-radius: 5px;
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15);
}
p {
margin-top: 1em;
}
span {
display: inline-block;
width: 1em;
height: 1em;
margin-bottom: -0.1em;
border: 1px solid rgba(34, 36, 38, 0.15);
}
`}</style>
<div className="panel-wrapper">
<ColorPanel />
<ColorPanel onColorUpdate={setColor} />
{color && (
<p>
Selected color:{" "}
<span style={{ backgroundColor: color.toHexString() }} />{" "}
<code>{color.toHexString()}</code>
</p>
)}
</div>
</div>
);
Expand Down
14 changes: 6 additions & 8 deletions docs/components/BrightnessSaturationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FC, MutableRefObject, useEffect, useState, useMemo } from "react";
import styled from "styled-components";
import tinycolor from "tinycolor2";

import { useResize } from "./utils";
import { useResize, Size } from "./utils";
import { Cursor } from "./Cursor";

const Panel = styled.div`
Expand Down Expand Up @@ -33,24 +33,22 @@ interface BrightnessSaturationPanelProps {
brightness: number;
saturation: number;
hue: number;
onSizeUpdate?(size: Size): void;
}

export const BrightnessSaturationPanel: FC<BrightnessSaturationPanelProps> = ({
brightness,
saturation,
hue,
onSizeUpdate,
}) => {
const [size, ref] = useResize();
const [height, setHeight] = useState<string>("0px");

useEffect(() => {
setHeight(`${size.width}px`);
}, [size]);

useEffect(() => {
ref.current.addEventListener("mousedown", () => {});
ref.current.addEventListener("touchstart", () => {});
}, [ref]);
onSizeUpdate && onSizeUpdate({ ...size, height: size.width });
}, [size, onSizeUpdate]);

const hueColor = useMemo(
() =>
Expand All @@ -70,7 +68,7 @@ export const BrightnessSaturationPanel: FC<BrightnessSaturationPanelProps> = ({
style={{ height: height, backgroundColor: hueColor }}
ref={ref as MutableRefObject<HTMLDivElement>}
>
<Cursor x={brightness} y={saturation} />
<Cursor x={saturation} y={1 - brightness} />
<div className="brightness"></div>
<div className="saturation"></div>
</Panel>
Expand Down
132 changes: 124 additions & 8 deletions docs/components/ColorPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,156 @@
import { FC, useState, useCallback } from "react";
import React, {
FC,
useState,
useCallback,
useRef,
useMemo,
useEffect,
} from "react";
import styled from "styled-components";
import tinycolor from "tinycolor2";

import { HueSlider } from "./HueSlider";
import { BrightnessSaturationPanel } from "./BrightnessSaturationPanel";
import { Size } from "./utils";

const Panel = styled.div`
margin-bottom: 5px;
user-select: none;
`;

export interface ColorPanelResultIface {
color: string;
}

export interface ColorPanelProps {
width?: string;
onColorUpdate?(color: tinycolor.Instance): void;
}

export const ColorPanel: FC<ColorPanelProps> = ({ width }) => {
interface CursorPosition {
x: number;
y: number;
}

export const ColorPanel: FC<ColorPanelProps> = ({ width, onColorUpdate }) => {
const ref = useRef<HTMLDivElement>(null);
const [hue, setHue] = useState<number>(0);
const [cursorPosition, setCursorPosition] = useState<CursorPosition>({
x: 0,
y: 0,
});
const [panelSize, setPanelSize] = useState<Size>(null);

const updateCursorPosition = useCallback(
({ x, y }: CursorPosition) => {
if (!ref.current) {
return;
}
const rect = ref.current.getBoundingClientRect();
setCursorPosition({
x: x - rect.left,
y: y - rect.top,
});
},
[ref.current]
);

const handleMouseMove = useCallback(
(ev: MouseEvent | React.MouseEvent) => {
const { buttons } = ev;
if (buttons !== 1) {
return;
}
updateCursorPosition({ x: ev.clientX, y: ev.clientY });
},
[updateCursorPosition]
);

const handleMouseDown = useCallback(
(ev: MouseEvent | React.MouseEvent) => {
handleMouseMove(ev);
const handleMouseUp = (ev: MouseEvent) => {
handleMouseMove(ev);
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
};
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
},
[handleMouseMove]
);

const handleTouchMove = useCallback(
(ev: TouchEvent | React.TouchEvent) => {
const { targetTouches } = ev;
if (targetTouches.length <= 0) {
return;
}
ev.preventDefault();
updateCursorPosition({
x: targetTouches[0].clientX,
y: targetTouches[0].clientY,
});
},
[updateCursorPosition]
);

const handleTouchStart = useCallback(
(ev: TouchEvent | React.TouchEvent) => {
handleTouchMove(ev);
const handleTouchEnd = (ev: TouchEvent) => {
handleTouchMove(ev);
window.removeEventListener("touchmove", handleTouchMove);
window.removeEventListener("touchend", handleTouchEnd);
};
window.addEventListener("touchmove", handleTouchMove, { passive: false });
window.addEventListener("touchend", handleTouchEnd);
},
[handleTouchMove]
);

const handleHueChange = useCallback((h) => {
setHue(h);
}, []);

const brightness = useMemo(
() =>
Math.max(
0,
Math.min(1, 1 - (panelSize ? cursorPosition.y / panelSize.height : 0))
),
[panelSize, cursorPosition]
);
const saturation = useMemo(
() =>
Math.max(
0,
Math.min(1, panelSize ? cursorPosition.x / panelSize.width : 0)
),
[panelSize, cursorPosition]
);

useEffect(() => {
const color = tinycolor.fromRatio({
h: hue / 360,
s: saturation,
v: brightness,
});
onColorUpdate && onColorUpdate(color);
}, [brightness, saturation, hue, onColorUpdate]);

return (
<div
className="color-panel"
style={{
width: width || "100%",
}}
onMouseDown={handleMouseDown}
onTouchStart={handleTouchStart}
ref={ref}
>
<Panel>
<BrightnessSaturationPanel
brightness={0.5}
saturation={0.5}
brightness={brightness}
saturation={saturation}
hue={hue}
onSizeUpdate={setPanelSize}
/>
</Panel>
<HueSlider hue={hue} onHueChange={handleHueChange} />
Expand Down

0 comments on commit a26f514

Please sign in to comment.