Skip to content

Commit 59d61cd

Browse files
committedSep 27, 2024·
pass props when a thumb is selected on the radix slider
1 parent f62fdca commit 59d61cd

File tree

2 files changed

+59
-13
lines changed

2 files changed

+59
-13
lines changed
 

‎apps/builder/app/builder/features/style-panel/sections/backgrounds/gradient-control.stories.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const GradientWithoutAngle = () => {
2222
onChange={(value) => {
2323
setGradient(reconstructLinearGradient(value));
2424
}}
25+
onThumbSelected={() => {}}
2526
/>
2627
<Text>{gradient}</Text>
2728
</Flex>
@@ -40,6 +41,7 @@ export const GradientWithAngleAndHints = () => {
4041
onChange={(value) => {
4142
setGradient(reconstructLinearGradient(value));
4243
}}
44+
onThumbSelected={() => {}}
4345
/>
4446
<Text>{gradient}</Text>
4547
</Flex>
@@ -58,6 +60,7 @@ export const GradientWithSideOrCorner = () => {
5860
onChange={(value) => {
5961
setGradient(reconstructLinearGradient(value));
6062
}}
63+
onThumbSelected={() => {}}
6164
/>
6265
<Text>{gradient}</Text>
6366
</Flex>

‎apps/builder/app/builder/features/style-panel/sections/backgrounds/gradient-control.tsx

+56-13
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extend([mixPlugin]);
1616
type GradientControlProps = {
1717
gradient: ParsedGradient;
1818
onChange: (value: ParsedGradient) => void;
19+
onThumbSelected: (index: number, stop: GradientStop) => void;
1920
};
2021

2122
const defaultAngle: UnitValue = {
@@ -27,6 +28,7 @@ const defaultAngle: UnitValue = {
2728
export const GradientControl = (props: GradientControlProps) => {
2829
const [stops, setStops] = useState<Array<GradientStop>>(props.gradient.stops);
2930
const [selectedStop, setSelectedStop] = useState<number | undefined>();
31+
const [isHoveredOnStop, setIsHoveredOnStop] = useState<boolean>(false);
3032
const positions = stops
3133
.map((stop) => stop.position?.value)
3234
.filter((item) => item !== undefined);
@@ -80,24 +82,36 @@ export const GradientControl = (props: GradientControlProps) => {
8082
[stops, selectedStop]
8183
);
8284

83-
const handlePointerDown = useCallback(
84-
(event: React.MouseEvent<HTMLSpanElement>) => {
85-
if (event.target === undefined || event.target === null) {
86-
return;
87-
}
88-
89-
// radix-slider automatically brings the closest thumb to the clicked position.
90-
// But, we want it be prevented. So, we can add a new color-stop where the user is cliked.
91-
// And handle the even for scrubing when the user is dragging the thumb.
85+
const isStopExistsAtPosition = useCallback(
86+
(
87+
event: React.MouseEvent<HTMLSpanElement>
88+
): { isStopExistingAtPosition: boolean; newPosition: number } => {
9289
const sliderWidth = event.currentTarget.offsetWidth;
9390
const clickedPosition =
9491
event.clientX - event.currentTarget.getBoundingClientRect().left;
9592
const newPosition = Math.ceil((clickedPosition / sliderWidth) * 100);
96-
const isExistingPosition = positions.some(
93+
// 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.
94+
const isStopExistingAtPosition = positions.some(
9795
(position) => Math.abs(newPosition - position) <= 8
9896
);
9997

100-
if (isExistingPosition === true) {
98+
return { isStopExistingAtPosition, newPosition };
99+
},
100+
[positions]
101+
);
102+
103+
const handlePointerDown = useCallback(
104+
(event: React.MouseEvent<HTMLSpanElement>) => {
105+
if (event.target === undefined || event.target === null) {
106+
return;
107+
}
108+
109+
// radix-slider automatically brings the closest thumb to the clicked position.
110+
// But, we want it be prevented. For adding a new color-stop where the user clicked.
111+
// And handle the change in values only even for scrubing when the user is dragging the thumb.
112+
const { isStopExistingAtPosition, newPosition } =
113+
isStopExistsAtPosition(event);
114+
if (isStopExistingAtPosition === true) {
101115
return;
102116
}
103117

@@ -131,11 +145,23 @@ export const GradientControl = (props: GradientControlProps) => {
131145
},
132146
...stops.slice(index),
133147
];
148+
134149
setStops(newStops);
150+
setIsHoveredOnStop(true);
151+
props.onChange({
152+
angle: props.gradient.angle,
153+
stops: newStops,
154+
sideOrCorner: props.gradient.sideOrCorner,
155+
});
135156
},
136-
[stops, positions]
157+
[stops, positions, isStopExistsAtPosition, props]
137158
);
138159

160+
const handleMouseEnter = (event: React.MouseEvent<HTMLSpanElement>) => {
161+
const { isStopExistingAtPosition } = isStopExistsAtPosition(event);
162+
setIsHoveredOnStop(isStopExistingAtPosition);
163+
};
164+
139165
if (isEveryStopHasAPosition === false) {
140166
return;
141167
}
@@ -156,15 +182,22 @@ export const GradientControl = (props: GradientControlProps) => {
156182
onValueChange={handleValueChange}
157183
onKeyDown={handleKeyDown}
158184
onPointerDown={handlePointerDown}
185+
isHoveredOnStop={isHoveredOnStop}
186+
onMouseEnter={handleMouseEnter}
187+
onMouseMove={handleMouseEnter}
188+
onMouseLeave={() => {
189+
setIsHoveredOnStop(false);
190+
}}
159191
>
160192
<Track>
161-
<SliderRange css={{ cursor: "copy" }} />
193+
<SliderRange />
162194
</Track>
163195
{stops.map((stop, index) => (
164196
<SliderThumb
165197
key={index}
166198
onClick={() => {
167199
setSelectedStop(index);
200+
props.onThumbSelected(index, stop);
168201
}}
169202
style={{
170203
background: toValue(stop.color),
@@ -211,6 +244,16 @@ const SliderRoot = styled(Root, {
211244
borderRadius: theme.borderRadius[3],
212245
touchAction: "none",
213246
userSelect: "none",
247+
variants: {
248+
isHoveredOnStop: {
249+
true: {
250+
cursor: "default",
251+
},
252+
false: {
253+
cursor: "copy",
254+
},
255+
},
256+
},
214257
});
215258

216259
const SliderRange = styled(Range, {

0 commit comments

Comments
 (0)