@ldelia/react-media 0.6.2 → 0.7.0
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.
- package/dist/components/reproduction-widget/ReproductionWidget.d.ts +3 -1
- package/dist/components/reproduction-widget/ReproductionWidget.js +2 -1
- package/dist/components/reproduction-widget/models/Player/PlayAlongPlayer.d.ts +3 -2
- package/dist/components/reproduction-widget/models/Player/PlayAlongPlayer.js +7 -6
- package/dist/components/reproduction-widget/models/Player/YouTubePlayer.d.ts +2 -1
- package/dist/components/reproduction-widget/models/Player/YouTubePlayer.js +10 -7
- package/dist/components/reproduction-widget/models/Reproduction.d.ts +6 -3
- package/dist/components/reproduction-widget/models/Reproduction.js +45 -30
- package/dist/components/reproduction-widget/models/ReproductionBuilder.d.ts +2 -0
- package/dist/components/reproduction-widget/models/ReproductionBuilder.js +6 -1
- package/dist/components/timeline/RangeSelectorCanvas/RangeSelectorCanvas.js +20 -14
- package/dist/stories/reproduction-widget.stories.d.ts +5 -4
- package/dist/stories/reproduction-widget.stories.js +13 -1
- package/dist/stories/timeline.stories.d.ts +7 -7
- package/package.json +9 -16
|
@@ -10,14 +10,16 @@ interface TrainingProps extends BaseProps {
|
|
|
10
10
|
trainingMode: true;
|
|
11
11
|
duration?: never;
|
|
12
12
|
videoId: string;
|
|
13
|
+
initialVolume?: number;
|
|
13
14
|
onVideoUnavailable: () => void;
|
|
14
15
|
}
|
|
15
16
|
interface NonTrainingProps extends BaseProps {
|
|
16
17
|
trainingMode: false;
|
|
17
18
|
duration: number;
|
|
18
19
|
videoId?: never;
|
|
20
|
+
initialVolume?: never;
|
|
19
21
|
onVideoUnavailable?: never;
|
|
20
22
|
}
|
|
21
23
|
export type ReproductionWidgetProps = TrainingProps | NonTrainingProps;
|
|
22
|
-
export declare const ReproductionWidget: ({ trainingMode, duration, videoId, withCountingIn, songTempo, onInit, onVideoUnavailable, }: ReproductionWidgetProps) => React.JSX.Element;
|
|
24
|
+
export declare const ReproductionWidget: ({ trainingMode, duration, videoId, initialVolume, withCountingIn, songTempo, onInit, onVideoUnavailable, }: ReproductionWidgetProps) => React.JSX.Element;
|
|
23
25
|
export {};
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { YouTubeInnerPlayer } from './inner-players/YouTubeInnerPlayer';
|
|
3
3
|
import { PlayAlongInnerPlayer } from './inner-players/PlayAlongInnerPlayer';
|
|
4
4
|
import { Reproduction } from './models/Reproduction';
|
|
5
|
-
export const ReproductionWidget = ({ trainingMode, duration, videoId, withCountingIn = true, songTempo = 0, onInit, onVideoUnavailable, }) => {
|
|
5
|
+
export const ReproductionWidget = ({ trainingMode, duration, videoId, initialVolume = 50, withCountingIn = true, songTempo = 0, onInit, onVideoUnavailable, }) => {
|
|
6
6
|
function onPlayAlongInnerPlayerReadyHandler(event) {
|
|
7
7
|
let newReproduction = Reproduction.newBuilder()
|
|
8
8
|
.withTrainingMode(false)
|
|
@@ -19,6 +19,7 @@ export const ReproductionWidget = ({ trainingMode, duration, videoId, withCounti
|
|
|
19
19
|
.withSongTempo(songTempo)
|
|
20
20
|
.withCountingIn(withCountingIn && songTempo > 0)
|
|
21
21
|
.withInnerPlayer(event.target)
|
|
22
|
+
.withVolume(initialVolume)
|
|
22
23
|
.createReproduction();
|
|
23
24
|
onInit(newReproduction);
|
|
24
25
|
}
|
|
@@ -9,16 +9,16 @@ export declare class PlayAlongPlayer {
|
|
|
9
9
|
private interval;
|
|
10
10
|
private [dispatchOnReadyHandlers];
|
|
11
11
|
private [dispatchOnFinishHandlers];
|
|
12
|
+
constructor(duration: number, innerPlayer: string);
|
|
12
13
|
static get EVENTS(): {
|
|
13
14
|
readonly READY: "READY";
|
|
14
15
|
readonly FINISH: "FINISH";
|
|
15
16
|
};
|
|
16
|
-
constructor(duration: number, innerPlayer: string);
|
|
17
|
-
private setInnerPlayer;
|
|
18
17
|
play(): void;
|
|
19
18
|
pause(): void;
|
|
20
19
|
stop(): void;
|
|
21
20
|
seekTo(seconds: number): void;
|
|
21
|
+
setVolume(volume: number): void;
|
|
22
22
|
getCurrentTime(): number;
|
|
23
23
|
getDuration(): number;
|
|
24
24
|
isAvailable(): boolean;
|
|
@@ -26,5 +26,6 @@ export declare class PlayAlongPlayer {
|
|
|
26
26
|
setPlaybackRate(playbackRate: number): void;
|
|
27
27
|
on(eventName: keyof typeof PlayAlongPlayer.EVENTS, handler: () => void): number | undefined;
|
|
28
28
|
dispatch(eventName: keyof typeof PlayAlongPlayer.EVENTS): void;
|
|
29
|
+
private setInnerPlayer;
|
|
29
30
|
}
|
|
30
31
|
export {};
|
|
@@ -2,9 +2,6 @@ import { PLAYER_EVENTS } from './PlayerEvents';
|
|
|
2
2
|
const dispatchOnReadyHandlers = Symbol();
|
|
3
3
|
const dispatchOnFinishHandlers = Symbol();
|
|
4
4
|
export class PlayAlongPlayer {
|
|
5
|
-
static get EVENTS() {
|
|
6
|
-
return PLAYER_EVENTS;
|
|
7
|
-
}
|
|
8
5
|
constructor(duration, innerPlayer) {
|
|
9
6
|
this.interval = null;
|
|
10
7
|
this.interval = null;
|
|
@@ -17,9 +14,8 @@ export class PlayAlongPlayer {
|
|
|
17
14
|
this[dispatchOnReadyHandlers] = [];
|
|
18
15
|
this.setInnerPlayer(innerPlayer);
|
|
19
16
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.dispatch(PlayAlongPlayer.EVENTS.READY);
|
|
17
|
+
static get EVENTS() {
|
|
18
|
+
return PLAYER_EVENTS;
|
|
23
19
|
}
|
|
24
20
|
play() {
|
|
25
21
|
this.isRunning = true;
|
|
@@ -48,6 +44,7 @@ export class PlayAlongPlayer {
|
|
|
48
44
|
seekTo(seconds) {
|
|
49
45
|
this.currentTime = seconds;
|
|
50
46
|
}
|
|
47
|
+
setVolume(volume) { }
|
|
51
48
|
getCurrentTime() {
|
|
52
49
|
return this.currentTime;
|
|
53
50
|
}
|
|
@@ -94,4 +91,8 @@ export class PlayAlongPlayer {
|
|
|
94
91
|
handler();
|
|
95
92
|
}
|
|
96
93
|
}
|
|
94
|
+
setInnerPlayer(innerPlayer) {
|
|
95
|
+
this.innerPlayer = innerPlayer;
|
|
96
|
+
this.dispatch(PlayAlongPlayer.EVENTS.READY);
|
|
97
|
+
}
|
|
97
98
|
}
|
|
@@ -9,16 +9,17 @@ export declare class YouTubePlayer {
|
|
|
9
9
|
private innerPlayer;
|
|
10
10
|
private [dispatchOnReadyHandlers];
|
|
11
11
|
private [dispatchOnFinishHandlers];
|
|
12
|
+
constructor(innerPlayer: InnerYouTubePlayerInterface);
|
|
12
13
|
static get EVENTS(): {
|
|
13
14
|
readonly READY: "READY";
|
|
14
15
|
readonly FINISH: "FINISH";
|
|
15
16
|
};
|
|
16
|
-
constructor(innerPlayer: InnerYouTubePlayerInterface);
|
|
17
17
|
getInnerPlayer(): YT.Player;
|
|
18
18
|
play(): void;
|
|
19
19
|
pause(): void;
|
|
20
20
|
stop(): void;
|
|
21
21
|
seekTo(seconds: number): void;
|
|
22
|
+
setVolume(volume: number): void;
|
|
22
23
|
getCurrentTime(): number;
|
|
23
24
|
getDuration(): number | undefined;
|
|
24
25
|
getAvailablePlaybackRates(): number[];
|
|
@@ -3,9 +3,6 @@ import { PLAYER_EVENTS } from './PlayerEvents';
|
|
|
3
3
|
const dispatchOnReadyHandlers = Symbol();
|
|
4
4
|
const dispatchOnFinishHandlers = Symbol();
|
|
5
5
|
export class YouTubePlayer {
|
|
6
|
-
static get EVENTS() {
|
|
7
|
-
return PLAYER_EVENTS;
|
|
8
|
-
}
|
|
9
6
|
constructor(innerPlayer) {
|
|
10
7
|
this[dispatchOnFinishHandlers] = [];
|
|
11
8
|
this[dispatchOnReadyHandlers] = [];
|
|
@@ -14,8 +11,8 @@ export class YouTubePlayer {
|
|
|
14
11
|
this.innerPlayer = innerPlayer;
|
|
15
12
|
this.innerPlayer = innerPlayer;
|
|
16
13
|
this.dispatch(YouTubePlayer.EVENTS.READY);
|
|
17
|
-
//
|
|
18
|
-
// When a video is in this state, when user
|
|
14
|
+
// This is necessary for avoiding the state video cued.
|
|
15
|
+
// When a video is in this state, when the user seeks to X, the song is played
|
|
19
16
|
this.innerPlayer.playVideo();
|
|
20
17
|
this.innerPlayer.pauseVideo();
|
|
21
18
|
this.innerPlayer.addEventListener('onStateChange', (videoState) => {
|
|
@@ -30,6 +27,9 @@ export class YouTubePlayer {
|
|
|
30
27
|
}
|
|
31
28
|
});
|
|
32
29
|
}
|
|
30
|
+
static get EVENTS() {
|
|
31
|
+
return PLAYER_EVENTS;
|
|
32
|
+
}
|
|
33
33
|
getInnerPlayer() {
|
|
34
34
|
return this.innerPlayer;
|
|
35
35
|
}
|
|
@@ -46,8 +46,8 @@ export class YouTubePlayer {
|
|
|
46
46
|
stop() {
|
|
47
47
|
this.isRunning = false;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* There's an issue when calling getDuration on the video after resuming a paused song (it always returns 0)
|
|
50
|
+
* To prevent losing this information and having to reload it, we simulate a stop by pausing and seeking to the start
|
|
51
51
|
* videoPlayer.stopVideo();
|
|
52
52
|
*/
|
|
53
53
|
this.getInnerPlayer().pauseVideo();
|
|
@@ -61,6 +61,9 @@ export class YouTubePlayer {
|
|
|
61
61
|
this.play();
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
setVolume(volume) {
|
|
65
|
+
this.getInnerPlayer().setVolume(volume);
|
|
66
|
+
}
|
|
64
67
|
getCurrentTime() {
|
|
65
68
|
return this.isRunning
|
|
66
69
|
? this.getInnerPlayer().getCurrentTime()
|
|
@@ -18,6 +18,7 @@ export declare class Reproduction {
|
|
|
18
18
|
private ready;
|
|
19
19
|
private interval;
|
|
20
20
|
private countingInCounter;
|
|
21
|
+
private volume;
|
|
21
22
|
private [dispatchOnReadyHandlers];
|
|
22
23
|
private [dispatchOnSongStartHandlers];
|
|
23
24
|
private [dispatchOnCountingInHandlers];
|
|
@@ -25,6 +26,7 @@ export declare class Reproduction {
|
|
|
25
26
|
private [dispatchOnPlayingHandlers];
|
|
26
27
|
private [dispatchOnPausedHandlers];
|
|
27
28
|
private [dispatchOnFinishHandlers];
|
|
29
|
+
constructor(player: Player, requiresCountingIn: boolean, songTempo: number, volume: number);
|
|
28
30
|
static get EVENTS(): {
|
|
29
31
|
readonly READY: "READY";
|
|
30
32
|
readonly START: "START";
|
|
@@ -40,10 +42,9 @@ export declare class Reproduction {
|
|
|
40
42
|
PLAYING: number;
|
|
41
43
|
PAUSED: number;
|
|
42
44
|
};
|
|
43
|
-
|
|
45
|
+
static newBuilder(): ReproductionBuilder;
|
|
44
46
|
on(eventName: keyof typeof Reproduction.EVENTS, handler: Handler): number | undefined;
|
|
45
47
|
dispatch(eventName: keyof typeof Reproduction.EVENTS, args?: {}): void;
|
|
46
|
-
private countInAndPlay;
|
|
47
48
|
start(): void;
|
|
48
49
|
play(): void;
|
|
49
50
|
pause(): void;
|
|
@@ -58,10 +59,12 @@ export declare class Reproduction {
|
|
|
58
59
|
getCurrentTime(): number;
|
|
59
60
|
getDuration(): number | undefined;
|
|
60
61
|
seekTo(seconds: number): void;
|
|
62
|
+
getVolume(): number;
|
|
63
|
+
setVolume(volume: number): void;
|
|
61
64
|
getAvailablePlaybackRates(): number[];
|
|
62
65
|
setPlaybackRate(playbackRate: number): void;
|
|
63
66
|
isAvailable(): boolean;
|
|
64
67
|
getBPMInterval(): number;
|
|
65
|
-
|
|
68
|
+
private countInAndPlay;
|
|
66
69
|
}
|
|
67
70
|
export {};
|
|
@@ -23,13 +23,8 @@ const dispatchOnPlayingHandlers = Symbol();
|
|
|
23
23
|
const dispatchOnPausedHandlers = Symbol();
|
|
24
24
|
const dispatchOnFinishHandlers = Symbol();
|
|
25
25
|
export class Reproduction {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
static get STATES() {
|
|
30
|
-
return STATES;
|
|
31
|
-
}
|
|
32
|
-
constructor(player, requiresCountingIn, songTempo) {
|
|
26
|
+
constructor(player, requiresCountingIn, songTempo, volume) {
|
|
27
|
+
this.volume = 50; // between 0 and 100
|
|
33
28
|
this[dispatchOnReadyHandlers] = [];
|
|
34
29
|
this[dispatchOnSongStartHandlers] = [];
|
|
35
30
|
this[dispatchOnCountingInHandlers] = [];
|
|
@@ -44,6 +39,7 @@ export class Reproduction {
|
|
|
44
39
|
this.interval = null;
|
|
45
40
|
this.requiresCountingIn = requiresCountingIn;
|
|
46
41
|
this.countingInCounter = 0;
|
|
42
|
+
this.setVolume(volume);
|
|
47
43
|
this.player.on(PLAYER_EVENTS.READY, () => {
|
|
48
44
|
this.ready = true;
|
|
49
45
|
this.dispatch(Reproduction.EVENTS.READY);
|
|
@@ -54,6 +50,15 @@ export class Reproduction {
|
|
|
54
50
|
this.dispatch(Reproduction.EVENTS.FINISH);
|
|
55
51
|
});
|
|
56
52
|
}
|
|
53
|
+
static get EVENTS() {
|
|
54
|
+
return EVENTS;
|
|
55
|
+
}
|
|
56
|
+
static get STATES() {
|
|
57
|
+
return STATES;
|
|
58
|
+
}
|
|
59
|
+
static newBuilder() {
|
|
60
|
+
return new ReproductionBuilder();
|
|
61
|
+
}
|
|
57
62
|
on(eventName, handler) {
|
|
58
63
|
switch (eventName) {
|
|
59
64
|
case Reproduction.EVENTS.READY:
|
|
@@ -108,27 +113,6 @@ export class Reproduction {
|
|
|
108
113
|
// setTimeout(handler, 0);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
|
-
countInAndPlay(timeout, limit) {
|
|
112
|
-
// the initial count starts instantly, no need to wait
|
|
113
|
-
this.countingInCounter++;
|
|
114
|
-
this.dispatch(Reproduction.EVENTS.COUNTING_IN, { countingInCounter: this.countingInCounter });
|
|
115
|
-
const interval = setInterval(() => {
|
|
116
|
-
this.countingInCounter++;
|
|
117
|
-
if (this.countingInCounter === limit) {
|
|
118
|
-
clearInterval(interval);
|
|
119
|
-
this.countingInCounter = 0;
|
|
120
|
-
if (limit !== 5) {
|
|
121
|
-
this.countInAndPlay(this.getBPMInterval(), 5);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
this.play();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
this.dispatch(Reproduction.EVENTS.COUNTING_IN, { countingInCounter: this.countingInCounter });
|
|
129
|
-
}
|
|
130
|
-
}, timeout);
|
|
131
|
-
}
|
|
132
116
|
start() {
|
|
133
117
|
if (this.state === Reproduction.STATES.STOPPED) {
|
|
134
118
|
this.dispatch(Reproduction.EVENTS.START);
|
|
@@ -196,6 +180,19 @@ export class Reproduction {
|
|
|
196
180
|
seekTo(seconds) {
|
|
197
181
|
this.player.seekTo(seconds);
|
|
198
182
|
}
|
|
183
|
+
getVolume() {
|
|
184
|
+
return this.volume;
|
|
185
|
+
}
|
|
186
|
+
setVolume(volume) {
|
|
187
|
+
if (volume < 0) {
|
|
188
|
+
volume = 0;
|
|
189
|
+
}
|
|
190
|
+
else if (volume > 100) {
|
|
191
|
+
volume = 100;
|
|
192
|
+
}
|
|
193
|
+
this.volume = volume;
|
|
194
|
+
this.player.setVolume(volume);
|
|
195
|
+
}
|
|
199
196
|
getAvailablePlaybackRates() {
|
|
200
197
|
return this.player.getAvailablePlaybackRates();
|
|
201
198
|
}
|
|
@@ -208,7 +205,25 @@ export class Reproduction {
|
|
|
208
205
|
getBPMInterval() {
|
|
209
206
|
return 60000 / this.getTempo();
|
|
210
207
|
}
|
|
211
|
-
|
|
212
|
-
|
|
208
|
+
countInAndPlay(timeout, limit) {
|
|
209
|
+
// the initial count starts instantly, no need to wait
|
|
210
|
+
this.countingInCounter++;
|
|
211
|
+
this.dispatch(Reproduction.EVENTS.COUNTING_IN, { countingInCounter: this.countingInCounter });
|
|
212
|
+
const interval = setInterval(() => {
|
|
213
|
+
this.countingInCounter++;
|
|
214
|
+
if (this.countingInCounter === limit) {
|
|
215
|
+
clearInterval(interval);
|
|
216
|
+
this.countingInCounter = 0;
|
|
217
|
+
if (limit !== 5) {
|
|
218
|
+
this.countInAndPlay(this.getBPMInterval(), 5);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.play();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
this.dispatch(Reproduction.EVENTS.COUNTING_IN, { countingInCounter: this.countingInCounter });
|
|
226
|
+
}
|
|
227
|
+
}, timeout);
|
|
213
228
|
}
|
|
214
229
|
}
|
|
@@ -5,6 +5,7 @@ export declare class ReproductionBuilder {
|
|
|
5
5
|
private requiresCountingIn;
|
|
6
6
|
private songDuration;
|
|
7
7
|
private songTempo;
|
|
8
|
+
private volume;
|
|
8
9
|
private innerPlayer;
|
|
9
10
|
constructor();
|
|
10
11
|
withSongDuration(songDuration: number): this;
|
|
@@ -12,5 +13,6 @@ export declare class ReproductionBuilder {
|
|
|
12
13
|
withTrainingMode(trainingMode: boolean): this;
|
|
13
14
|
withCountingIn(requiresCountingIn: boolean): this;
|
|
14
15
|
withInnerPlayer(innerPlayer: InnerYouTubePlayerInterface | string): this;
|
|
16
|
+
withVolume(volume: number): this;
|
|
15
17
|
createReproduction(): Reproduction;
|
|
16
18
|
}
|
|
@@ -7,6 +7,7 @@ export class ReproductionBuilder {
|
|
|
7
7
|
this.requiresCountingIn = false;
|
|
8
8
|
this.songDuration = null;
|
|
9
9
|
this.songTempo = null;
|
|
10
|
+
this.volume = 50;
|
|
10
11
|
this.innerPlayer = null;
|
|
11
12
|
}
|
|
12
13
|
withSongDuration(songDuration) {
|
|
@@ -29,6 +30,10 @@ export class ReproductionBuilder {
|
|
|
29
30
|
this.innerPlayer = innerPlayer;
|
|
30
31
|
return this;
|
|
31
32
|
}
|
|
33
|
+
withVolume(volume) {
|
|
34
|
+
this.volume = volume;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
32
37
|
createReproduction() {
|
|
33
38
|
if (this.requiresCountingIn && this.songTempo === null) {
|
|
34
39
|
throw new Error('The song tempo is mandatory');
|
|
@@ -46,6 +51,6 @@ export class ReproductionBuilder {
|
|
|
46
51
|
}
|
|
47
52
|
player = new PlayAlongPlayer(this.songDuration, this.innerPlayer);
|
|
48
53
|
}
|
|
49
|
-
return new Reproduction(player, this.requiresCountingIn, this.songTempo || 0);
|
|
54
|
+
return new Reproduction(player, this.requiresCountingIn, this.songTempo || 0, this.volume);
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -3,13 +3,14 @@ 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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
position: absolute;
|
|
7
|
+
top: 0;
|
|
8
|
+
left: 0;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
color: cadetblue;
|
|
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
|
`;
|
|
14
15
|
var DragMode;
|
|
15
16
|
(function (DragMode) {
|
|
@@ -22,7 +23,10 @@ const RESIZE_HANDLE_WIDTH = 10; // Width in pixels for the resize handle detecti
|
|
|
22
23
|
const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
|
|
23
24
|
const canvasRef = useRef(null);
|
|
24
25
|
const zoomContextValue = useContext(ZoomContext);
|
|
25
|
-
const [selection, setSelection] = useState({
|
|
26
|
+
const [selection, setSelection] = useState({
|
|
27
|
+
start: null,
|
|
28
|
+
end: null,
|
|
29
|
+
});
|
|
26
30
|
const [dragMode, setDragMode] = useState(DragMode.NONE);
|
|
27
31
|
const [cursorStyle, setCursorStyle] = useState('pointer');
|
|
28
32
|
const getMousePointerPixelPosition = (e) => {
|
|
@@ -112,12 +116,13 @@ const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
|
|
|
112
116
|
});
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
|
-
else if (dragMode === DragMode.RESIZE_START ||
|
|
119
|
+
else if (dragMode === DragMode.RESIZE_START ||
|
|
120
|
+
dragMode === DragMode.RESIZE_END) {
|
|
116
121
|
// Resizing completed
|
|
117
122
|
if (selection.start !== null && selection.end !== null) {
|
|
118
123
|
const curatedSelection = [
|
|
119
124
|
Math.min(selection.start, selection.end),
|
|
120
|
-
Math.max(selection.start, selection.end)
|
|
125
|
+
Math.max(selection.start, selection.end),
|
|
121
126
|
];
|
|
122
127
|
onRangeChange(curatedSelection);
|
|
123
128
|
}
|
|
@@ -136,19 +141,19 @@ const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
|
|
|
136
141
|
const pixel = getMousePointerPixelPosition(event);
|
|
137
142
|
const seconds = pixelToSeconds(zoomContextValue, pixel);
|
|
138
143
|
if (dragMode === DragMode.CREATE) {
|
|
139
|
-
setSelection(prevSelection => ({
|
|
144
|
+
setSelection((prevSelection) => ({
|
|
140
145
|
start: prevSelection.start,
|
|
141
146
|
end: seconds,
|
|
142
147
|
}));
|
|
143
148
|
}
|
|
144
149
|
else if (dragMode === DragMode.RESIZE_START) {
|
|
145
|
-
setSelection(prevSelection => ({
|
|
150
|
+
setSelection((prevSelection) => ({
|
|
146
151
|
start: seconds,
|
|
147
152
|
end: prevSelection.end,
|
|
148
153
|
}));
|
|
149
154
|
}
|
|
150
155
|
else if (dragMode === DragMode.RESIZE_END) {
|
|
151
|
-
setSelection(prevSelection => ({
|
|
156
|
+
setSelection((prevSelection) => ({
|
|
152
157
|
start: prevSelection.start,
|
|
153
158
|
end: seconds,
|
|
154
159
|
}));
|
|
@@ -159,7 +164,8 @@ const RangeSelectorCanvas = ({ selectedRange, onChange, onRangeChange, }) => {
|
|
|
159
164
|
// https://stackoverflow.com/questions/8696631/canvas-drawings-like-lines-are-blurry
|
|
160
165
|
canvas.width = canvas.offsetWidth;
|
|
161
166
|
canvas.height = canvas.offsetHeight;
|
|
162
|
-
if (selectedRange.length !== 2 ||
|
|
167
|
+
if (selectedRange.length !== 2 ||
|
|
168
|
+
zoomContextValue.timelineWrapperWidth === 0)
|
|
163
169
|
return;
|
|
164
170
|
drawRect(secondsToPixel(zoomContextValue, selectedRange[0]), secondsToPixel(zoomContextValue, selectedRange[1]));
|
|
165
171
|
}, [selectedRange, zoomContextValue]);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReproductionWidgetProps } from '../components/reproduction-widget';
|
|
2
|
-
declare const _default: import("
|
|
2
|
+
declare const _default: import("storybook/internal/csf").ComponentAnnotations<import("@storybook/react/dist/types-7abe74eb").R, import("storybook/internal/csf").Args>;
|
|
3
3
|
export default _default;
|
|
4
|
-
export declare const Default: import("
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
4
|
+
export declare const Default: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, ReproductionWidgetProps>;
|
|
5
|
+
export declare const WhisperingVideo: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, ReproductionWidgetProps>;
|
|
6
|
+
export declare const PlayAlong: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, ReproductionWidgetProps>;
|
|
7
|
+
export declare const InvalidVideo: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, ReproductionWidgetProps>;
|
|
@@ -43,7 +43,12 @@ const Template = (args) => {
|
|
|
43
43
|
React.createElement("button", { onClick: handleResume, disabled: !reproduction || reproduction.isPlaying() }, "Resume"),
|
|
44
44
|
reproduction && (React.createElement("div", null,
|
|
45
45
|
"Current time: ", reproduction === null || reproduction === void 0 ? void 0 :
|
|
46
|
-
reproduction.getCurrentTime()))
|
|
46
|
+
reproduction.getCurrentTime())),
|
|
47
|
+
reproduction && (React.createElement("div", null,
|
|
48
|
+
"Volume: ", reproduction === null || reproduction === void 0 ? void 0 :
|
|
49
|
+
reproduction.getVolume())),
|
|
50
|
+
React.createElement("button", { onClick: () => reproduction === null || reproduction === void 0 ? void 0 : reproduction.setVolume(reproduction.getVolume() - 10), disabled: !reproduction || reproduction.getVolume() <= 10 }, "Volume -10"),
|
|
51
|
+
React.createElement("button", { onClick: () => reproduction === null || reproduction === void 0 ? void 0 : reproduction.setVolume(reproduction.getVolume() + 10), disabled: !reproduction || reproduction.getVolume() >= 100 }, "Volume +10"))));
|
|
47
52
|
};
|
|
48
53
|
export const Default = Template.bind({});
|
|
49
54
|
Default.args = {
|
|
@@ -51,6 +56,13 @@ Default.args = {
|
|
|
51
56
|
videoId: 'jFI-RBqXzhU',
|
|
52
57
|
songTempo: 180,
|
|
53
58
|
};
|
|
59
|
+
export const WhisperingVideo = Template.bind({});
|
|
60
|
+
WhisperingVideo.args = {
|
|
61
|
+
trainingMode: true,
|
|
62
|
+
videoId: 'jFI-RBqXzhU',
|
|
63
|
+
songTempo: 180,
|
|
64
|
+
initialVolume: 10,
|
|
65
|
+
};
|
|
54
66
|
export const PlayAlong = Template.bind({});
|
|
55
67
|
PlayAlong.args = {
|
|
56
68
|
trainingMode: false,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { TimelineProps } from '../components/timeline';
|
|
2
2
|
import './timeline.stories.custom.css';
|
|
3
|
-
declare const _default: import("
|
|
3
|
+
declare const _default: import("storybook/internal/csf").ComponentAnnotations<import("@storybook/react/dist/types-7abe74eb").R, import("storybook/internal/csf").Args>;
|
|
4
4
|
export default _default;
|
|
5
|
-
export declare const Default: import("
|
|
6
|
-
export declare const WithSelectedRange: import("
|
|
7
|
-
export declare const WithCustomClassName: import("
|
|
8
|
-
export declare const WithoutTimeBlocks: import("
|
|
9
|
-
export declare const Minimalist: import("
|
|
10
|
-
export declare const WithSelectedRangeAndMarkers: import("
|
|
5
|
+
export declare const Default: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
|
6
|
+
export declare const WithSelectedRange: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
|
7
|
+
export declare const WithCustomClassName: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
|
8
|
+
export declare const WithoutTimeBlocks: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
|
9
|
+
export declare const Minimalist: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
|
10
|
+
export declare const WithSelectedRangeAndMarkers: import("storybook/internal/csf").AnnotatedStoryFn<import("@storybook/react/dist/types-7abe74eb").R, TimelineProps>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ldelia/react-media",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A React components collection for media-related features.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"keywords": [
|
|
@@ -114,20 +114,12 @@
|
|
|
114
114
|
"@babel/preset-env": "^7.24.8",
|
|
115
115
|
"@babel/preset-react": "^7.24.7",
|
|
116
116
|
"@babel/preset-typescript": "^7.24.7",
|
|
117
|
-
"@chromatic-com/storybook": "^
|
|
118
|
-
"@storybook/addon-
|
|
119
|
-
"@storybook/addon-
|
|
120
|
-
"@storybook/addon-
|
|
121
|
-
"@storybook/addon-interactions": "^8.6.12",
|
|
122
|
-
"@storybook/addon-knobs": "^8.0.1",
|
|
123
|
-
"@storybook/addon-links": "^8.6.12",
|
|
124
|
-
"@storybook/addon-onboarding": "^8.6.12",
|
|
125
|
-
"@storybook/blocks": "^8.6.12",
|
|
126
|
-
"@storybook/node-logger": "^8.6.12",
|
|
127
|
-
"@storybook/react": "^8.6.12",
|
|
117
|
+
"@chromatic-com/storybook": "^4.1.1",
|
|
118
|
+
"@storybook/addon-docs": "^9.1.10",
|
|
119
|
+
"@storybook/addon-links": "^9.1.10",
|
|
120
|
+
"@storybook/addon-onboarding": "^9.1.10",
|
|
128
121
|
"@storybook/react-docgen-typescript-plugin": "^1.0.6--canary.9.0c3f3b7.0",
|
|
129
|
-
"@storybook/react-webpack5": "^
|
|
130
|
-
"@storybook/test": "^8.6.12",
|
|
122
|
+
"@storybook/react-webpack5": "^9.1.10",
|
|
131
123
|
"@testing-library/jest-dom": "^6.4.6",
|
|
132
124
|
"@testing-library/react": "^16.0.0",
|
|
133
125
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -140,14 +132,15 @@
|
|
|
140
132
|
"babel-loader": "^9.1.3",
|
|
141
133
|
"eslint-config-prettier": "^9.1.0",
|
|
142
134
|
"eslint-plugin-prettier": "^5.1.3",
|
|
143
|
-
"eslint-plugin-storybook": "^
|
|
135
|
+
"eslint-plugin-storybook": "^9.1.10",
|
|
136
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
144
137
|
"postcss-flexbugs-fixes": "^5.0.2",
|
|
145
138
|
"postcss-normalize": "^10.0.1",
|
|
146
139
|
"postcss-preset-env": "^9.5.14",
|
|
147
140
|
"prettier": "^3.3.2",
|
|
148
141
|
"prop-types": "^15.8.1",
|
|
149
142
|
"react-docgen-typescript-plugin": "^1.0.8",
|
|
150
|
-
"storybook": "^
|
|
143
|
+
"storybook": "^9.1.10",
|
|
151
144
|
"ts-loader": "^9.5.1",
|
|
152
145
|
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
|
153
146
|
"webpack": "^5.92.0"
|