@ldelia/react-media 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,12 +10,25 @@ const OverlayCanvas = styled.canvas `
10
10
  height: 100%;
11
11
  color: cadetblue;
12
12
  cursor: pointer;
13
+ z-index: 2; // Ensure this canvas is on top of the TimeLineValue, otherwise we won't be able to change the range until the current TimelineValue position
13
14
  `;
15
+ var DragMode;
16
+ (function (DragMode) {
17
+ DragMode[DragMode["NONE"] = 0] = "NONE";
18
+ DragMode[DragMode["CREATE"] = 1] = "CREATE";
19
+ DragMode[DragMode["RESIZE_START"] = 2] = "RESIZE_START";
20
+ DragMode[DragMode["RESIZE_END"] = 3] = "RESIZE_END";
21
+ })(DragMode || (DragMode = {}));
22
+ const RESIZE_HANDLE_WIDTH = 10; // Width in pixels for the resize handle detection zone
14
23
  const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
15
24
  const canvasRef = useRef(null);
16
25
  const zoomContextValue = useContext(ZoomContext);
17
- const [selection, setSelection] = useState({ start: null, end: null });
18
- const [isDragging, setIsDragging] = useState(false);
26
+ const [selection, setSelection] = useState({
27
+ start: null,
28
+ end: null,
29
+ });
30
+ const [dragMode, setDragMode] = useState(DragMode.NONE);
31
+ const [cursorStyle, setCursorStyle] = useState('pointer');
19
32
  const getMousePointerPixelPosition = (e) => {
20
33
  const canvas = canvasRef.current;
21
34
  let rect = canvas.getBoundingClientRect();
@@ -32,66 +45,130 @@ const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
32
45
  context.fillRect(pixelX0, 0, pixelX1 - pixelX0, context.canvas.height);
33
46
  context.globalAlpha = 1.0;
34
47
  };
35
- // Handle mouse down (start of selection)
48
+ // Check if mouse is near the start or end edge of the selection
49
+ const isNearSelectionEdge = (pixel) => {
50
+ if (selectedRange.length !== 2)
51
+ return { isNear: false, edge: null };
52
+ const startPixel = secondsToPixel(zoomContextValue, selectedRange[0]);
53
+ const endPixel = secondsToPixel(zoomContextValue, selectedRange[1]);
54
+ if (Math.abs(pixel - startPixel) <= RESIZE_HANDLE_WIDTH) {
55
+ return { isNear: true, edge: 'start' };
56
+ }
57
+ else if (Math.abs(pixel - endPixel) <= RESIZE_HANDLE_WIDTH) {
58
+ return { isNear: true, edge: 'end' };
59
+ }
60
+ return { isNear: false, edge: null };
61
+ };
62
+ // Handle mouse move for cursor style when not dragging
63
+ const handleMouseOver = (event) => {
64
+ const pixel = getMousePointerPixelPosition(event);
65
+ const { isNear } = isNearSelectionEdge(pixel);
66
+ if (isNear) {
67
+ setCursorStyle('col-resize');
68
+ }
69
+ else {
70
+ setCursorStyle('pointer');
71
+ }
72
+ };
73
+ // Handle mouse down (start of selection or resize)
36
74
  const handleMouseDown = (event) => {
37
75
  const canvas = canvasRef.current;
38
76
  if (!canvas)
39
77
  return;
40
78
  const pixel = getMousePointerPixelPosition(event);
41
79
  const second = pixelToSeconds(zoomContextValue, pixel);
42
- setSelection({ start: second, end: null });
43
- setIsDragging(true);
80
+ const { isNear, edge } = isNearSelectionEdge(pixel);
81
+ if (isNear && edge === 'start') {
82
+ setDragMode(DragMode.RESIZE_START);
83
+ setSelection({ start: selectedRange[0], end: selectedRange[1] });
84
+ }
85
+ else if (isNear && edge === 'end') {
86
+ setDragMode(DragMode.RESIZE_END);
87
+ setSelection({ start: selectedRange[0], end: selectedRange[1] });
88
+ }
89
+ else {
90
+ setDragMode(DragMode.CREATE);
91
+ setSelection({ start: second, end: null });
92
+ }
44
93
  };
45
- // Handle mouse up (end of selection or single click)
94
+ // Handle mouse up (end of selection/resize or single click)
46
95
  const handleMouseUp = (event) => {
47
96
  const canvas = canvasRef.current;
48
97
  if (!canvas)
49
98
  return;
50
99
  const pixel = getMousePointerPixelPosition(event);
51
100
  const seconds = pixelToSeconds(zoomContextValue, pixel);
52
- if (isDragging) {
53
- setSelection(prevSelection => {
54
- if (prevSelection.start === seconds) {
55
- onChange(seconds);
56
- return { start: null, end: null };
57
- }
58
- else {
59
- const curatedSelection = seconds < prevSelection.start ? [seconds, prevSelection.start] : [prevSelection.start, seconds];
60
- onRangeChange(curatedSelection);
61
- return {
62
- start: curatedSelection[0],
63
- end: curatedSelection[1],
64
- };
65
- }
66
- });
101
+ if (dragMode === DragMode.CREATE) {
102
+ if (selection.start === seconds) {
103
+ // Single click
104
+ onChange(seconds);
105
+ setSelection({ start: null, end: null });
106
+ }
107
+ else {
108
+ // Created a new selection
109
+ const curatedSelection = seconds < selection.start
110
+ ? [seconds, selection.start]
111
+ : [selection.start, seconds];
112
+ onRangeChange(curatedSelection);
113
+ setSelection({
114
+ start: curatedSelection[0],
115
+ end: curatedSelection[1],
116
+ });
117
+ }
118
+ }
119
+ else if (dragMode === DragMode.RESIZE_START ||
120
+ dragMode === DragMode.RESIZE_END) {
121
+ // Resizing completed
122
+ if (selection.start !== null && selection.end !== null) {
123
+ const curatedSelection = [
124
+ Math.min(selection.start, selection.end),
125
+ Math.max(selection.start, selection.end),
126
+ ];
127
+ onRangeChange(curatedSelection);
128
+ }
67
129
  }
68
- setIsDragging(false);
130
+ setDragMode(DragMode.NONE);
69
131
  };
70
132
  // Handle mouse move (for dragging)
71
133
  const handleMouseMove = (event) => {
72
- if (!isDragging)
73
- return; // the mouse is moving over the canvas but the user has not clicked yet
134
+ // Update cursor first (always check this regardless of drag state)
135
+ handleMouseOver(event);
136
+ if (dragMode === DragMode.NONE)
137
+ return;
74
138
  const canvas = canvasRef.current;
75
139
  if (!canvas)
76
140
  return;
77
141
  const pixel = getMousePointerPixelPosition(event);
78
142
  const seconds = pixelToSeconds(zoomContextValue, pixel);
79
- setSelection(prevSelection => {
80
- return {
143
+ if (dragMode === DragMode.CREATE) {
144
+ setSelection((prevSelection) => ({
145
+ start: prevSelection.start,
146
+ end: seconds,
147
+ }));
148
+ }
149
+ else if (dragMode === DragMode.RESIZE_START) {
150
+ setSelection((prevSelection) => ({
151
+ start: seconds,
152
+ end: prevSelection.end,
153
+ }));
154
+ }
155
+ else if (dragMode === DragMode.RESIZE_END) {
156
+ setSelection((prevSelection) => ({
81
157
  start: prevSelection.start,
82
158
  end: seconds,
83
- };
84
- });
159
+ }));
160
+ }
85
161
  };
86
162
  useEffect(() => {
87
163
  const canvas = canvasRef.current;
88
164
  // https://stackoverflow.com/questions/8696631/canvas-drawings-like-lines-are-blurry
89
165
  canvas.width = canvas.offsetWidth;
90
166
  canvas.height = canvas.offsetHeight;
91
- if (selectedRange.length !== 2 || zoomContextValue.timelineWrapperWidth === 0)
167
+ if (selectedRange.length !== 2 ||
168
+ zoomContextValue.timelineWrapperWidth === 0)
92
169
  return;
93
170
  drawRect(secondsToPixel(zoomContextValue, selectedRange[0]), secondsToPixel(zoomContextValue, selectedRange[1]));
94
- }, [selectedRange]);
171
+ }, [selectedRange, zoomContextValue]);
95
172
  useEffect(() => {
96
173
  const canvas = canvasRef.current;
97
174
  // https://stackoverflow.com/questions/8696631/canvas-drawings-like-lines-are-blurry
@@ -101,6 +178,6 @@ const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
101
178
  return;
102
179
  drawRect(secondsToPixel(zoomContextValue, selection.start), secondsToPixel(zoomContextValue, selection.end));
103
180
  }, [selection, zoomContextValue]);
104
- return (React.createElement(OverlayCanvas, { ref: canvasRef, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, className: 'media-timeline-range-selector-canvas' }));
181
+ return (React.createElement(OverlayCanvas, { ref: canvasRef, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, style: { cursor: cursorStyle }, className: 'media-timeline-range-selector-canvas' }));
105
182
  };
106
183
  export default React.memo(RangeSelectorCanvas);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ldelia/react-media",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "A React components collection for media-related features.",
5
5
  "private": false,
6
6
  "keywords": [