@ldelia/react-media 0.6.1 → 0.6.2

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