Skip to content

Commit

Permalink
pass props when a thumb is selected on the radix slider
Browse files Browse the repository at this point in the history
  • Loading branch information
JayaKrishnaNamburu committed Sep 27, 2024
1 parent f62fdca commit 59d61cd
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const GradientWithoutAngle = () => {
onChange={(value) => {
setGradient(reconstructLinearGradient(value));
}}
onThumbSelected={() => {}}
/>
<Text>{gradient}</Text>
</Flex>
Expand All @@ -40,6 +41,7 @@ export const GradientWithAngleAndHints = () => {
onChange={(value) => {
setGradient(reconstructLinearGradient(value));
}}
onThumbSelected={() => {}}
/>
<Text>{gradient}</Text>
</Flex>
Expand All @@ -58,6 +60,7 @@ export const GradientWithSideOrCorner = () => {
onChange={(value) => {
setGradient(reconstructLinearGradient(value));
}}
onThumbSelected={() => {}}
/>
<Text>{gradient}</Text>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extend([mixPlugin]);
type GradientControlProps = {
gradient: ParsedGradient;
onChange: (value: ParsedGradient) => void;
onThumbSelected: (index: number, stop: GradientStop) => void;
};

const defaultAngle: UnitValue = {
Expand All @@ -27,6 +28,7 @@ const defaultAngle: UnitValue = {
export const GradientControl = (props: GradientControlProps) => {
const [stops, setStops] = useState<Array<GradientStop>>(props.gradient.stops);
const [selectedStop, setSelectedStop] = useState<number | undefined>();
const [isHoveredOnStop, setIsHoveredOnStop] = useState<boolean>(false);
const positions = stops
.map((stop) => stop.position?.value)
.filter((item) => item !== undefined);
Expand Down Expand Up @@ -80,24 +82,36 @@ export const GradientControl = (props: GradientControlProps) => {
[stops, selectedStop]
);

const handlePointerDown = useCallback(
(event: React.MouseEvent<HTMLSpanElement>) => {
if (event.target === undefined || event.target === null) {
return;
}

// radix-slider automatically brings the closest thumb to the clicked position.
// But, we want it be prevented. So, we can add a new color-stop where the user is cliked.
// And handle the even for scrubing when the user is dragging the thumb.
const isStopExistsAtPosition = useCallback(
(
event: React.MouseEvent<HTMLSpanElement>
): { isStopExistingAtPosition: boolean; newPosition: number } => {
const sliderWidth = event.currentTarget.offsetWidth;
const clickedPosition =
event.clientX - event.currentTarget.getBoundingClientRect().left;
const newPosition = Math.ceil((clickedPosition / sliderWidth) * 100);
const isExistingPosition = positions.some(
// The 8px buffer here is the width of the thumb. We don't want to add a new stop if the user clicks on the thumb.
const isStopExistingAtPosition = positions.some(
(position) => Math.abs(newPosition - position) <= 8
);

if (isExistingPosition === true) {
return { isStopExistingAtPosition, newPosition };
},
[positions]
);

const handlePointerDown = useCallback(
(event: React.MouseEvent<HTMLSpanElement>) => {
if (event.target === undefined || event.target === null) {
return;
}

// radix-slider automatically brings the closest thumb to the clicked position.
// But, we want it be prevented. For adding a new color-stop where the user clicked.
// And handle the change in values only even for scrubing when the user is dragging the thumb.
const { isStopExistingAtPosition, newPosition } =
isStopExistsAtPosition(event);
if (isStopExistingAtPosition === true) {
return;
}

Expand Down Expand Up @@ -131,11 +145,23 @@ export const GradientControl = (props: GradientControlProps) => {
},
...stops.slice(index),
];

setStops(newStops);
setIsHoveredOnStop(true);
props.onChange({
angle: props.gradient.angle,
stops: newStops,
sideOrCorner: props.gradient.sideOrCorner,
});
},
[stops, positions]
[stops, positions, isStopExistsAtPosition, props]
);

const handleMouseEnter = (event: React.MouseEvent<HTMLSpanElement>) => {
const { isStopExistingAtPosition } = isStopExistsAtPosition(event);
setIsHoveredOnStop(isStopExistingAtPosition);
};

if (isEveryStopHasAPosition === false) {
return;
}
Expand All @@ -156,15 +182,22 @@ export const GradientControl = (props: GradientControlProps) => {
onValueChange={handleValueChange}
onKeyDown={handleKeyDown}
onPointerDown={handlePointerDown}
isHoveredOnStop={isHoveredOnStop}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseEnter}
onMouseLeave={() => {
setIsHoveredOnStop(false);
}}
>
<Track>
<SliderRange css={{ cursor: "copy" }} />
<SliderRange />
</Track>
{stops.map((stop, index) => (
<SliderThumb
key={index}
onClick={() => {
setSelectedStop(index);
props.onThumbSelected(index, stop);
}}
style={{
background: toValue(stop.color),
Expand Down Expand Up @@ -211,6 +244,16 @@ const SliderRoot = styled(Root, {
borderRadius: theme.borderRadius[3],
touchAction: "none",
userSelect: "none",
variants: {
isHoveredOnStop: {
true: {
cursor: "default",
},
false: {
cursor: "copy",
},
},
},
});

const SliderRange = styled(Range, {
Expand Down

0 comments on commit 59d61cd

Please sign in to comment.