@folklore/hooks 0.0.31 → 0.0.33

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.
Files changed (3) hide show
  1. package/dist/cjs.js +388 -527
  2. package/dist/es.js +389 -528
  3. package/package.json +4 -3
package/dist/es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import raf from 'raf';
2
2
  import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
3
- import { loadDailymotion, loadYouTube, loadVimeo } from '@folklore/services';
3
+ import { loadDailymotion, loadVimeo, loadYouTube } from '@folklore/services';
4
4
  import createDebug from 'debug';
5
5
  import EventsManager from '@folklore/events';
6
6
  import { cancelable } from 'cancelable-promise';
@@ -19,32 +19,26 @@ function useCounter(desiredValue, _ref) {
19
19
  let canceled = false;
20
20
  const startValue = currentValue;
21
21
  const delta = desiredValue - startValue;
22
-
23
22
  function loop() {
24
23
  if (canceled) {
25
24
  return;
26
25
  }
27
-
28
26
  const currentTime = Date.now();
29
27
  const elapsedTime = currentTime - startTime;
30
28
  const progress = Math.min(elapsedTime / duration, 1);
31
29
  const newValue = Math.round(startValue + progress * delta);
32
30
  setCurrentValue(newValue);
33
-
34
31
  if (newValue !== desiredValue) {
35
32
  animationFrame = raf(loop);
36
33
  }
37
34
  }
38
-
39
35
  if (delta !== 0) {
40
36
  duration = Math.min(maxDuration, Math.abs(delta) * speed * 1000);
41
37
  startTime = Date.now();
42
38
  animationFrame = raf(loop);
43
39
  }
44
-
45
40
  return () => {
46
41
  canceled = true;
47
-
48
42
  if (animationFrame !== null) {
49
43
  raf.cancel(animationFrame);
50
44
  }
@@ -65,36 +59,29 @@ function usePlayerCurrentTime(player) {
65
59
  const realCurrentTime = useRef(currentTime);
66
60
  const lastIdRef = useRef(id);
67
61
  const idChanged = lastIdRef.current !== id;
68
-
69
62
  if (idChanged) {
70
63
  realCurrentTime.current = 0;
71
64
  lastIdRef.current = id;
72
- } // Check time update
73
-
65
+ }
74
66
 
67
+ // Check time update
75
68
  useEffect(() => {
76
69
  if (disabled || player === null) {
77
70
  return () => {};
78
71
  }
79
-
80
72
  let canceled = false;
81
-
82
73
  const updateTime = time => {
83
74
  if (canceled) {
84
75
  return;
85
76
  }
86
-
87
77
  realCurrentTime.current = time;
88
78
  setCurrentTime(time);
89
-
90
79
  if (customOnUpdate !== null) {
91
80
  customOnUpdate(time);
92
81
  }
93
82
  };
94
-
95
83
  const interval = setInterval(() => {
96
84
  const time = getCurrentTime(player);
97
-
98
85
  if (typeof time.then !== 'undefined') {
99
86
  time.then(updateTime);
100
87
  } else {
@@ -109,10 +96,8 @@ function usePlayerCurrentTime(player) {
109
96
  return realCurrentTime.current;
110
97
  }
111
98
 
112
- const noPlayerError$1 = new Error('No player');
113
- const debug$3 = createDebug('folklore:video:dailymotion');
114
-
115
- const useDailymotionPlayer = function () {
99
+ const NO_PLAYER_ERROR$3 = new Error('No player');
100
+ function useDailymotionPlayer() {
116
101
  let id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
117
102
  let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
118
103
  const {
@@ -134,15 +119,15 @@ const useDailymotionPlayer = function () {
134
119
  if (url === null || url.match(/^https?:/) === null) {
135
120
  return url;
136
121
  }
137
-
138
122
  const match = url.match(/\/video\/([^/?]+)/);
139
123
  return match !== null ? match[1] : null;
140
124
  }
141
125
  } = params;
142
- const [apiLoaded, setApiLoaded] = useState(typeof window.DM !== 'undefined');
126
+ const debug = useMemo(() => createDebug('folklore:video:dailymotion'), []);
127
+ const [apiLoaded, setApiLoaded] = useState(typeof window !== 'undefined' && typeof window.DM !== 'undefined');
143
128
  const [playerReady, setPlayerReady] = useState(false);
144
129
  const [loaded, setLoaded] = useState(false);
145
- const apiRef = useRef(typeof window.DM !== 'undefined' ? window.DM : null);
130
+ const apiRef = useRef(typeof window !== 'undefined' && typeof window.DM !== 'undefined' ? window.DM : null);
146
131
  const ready = apiLoaded && playerReady;
147
132
  const videoId = useMemo(() => getVideoId(id), [id]);
148
133
  const elementRef = useRef(null);
@@ -162,27 +147,27 @@ const useDailymotionPlayer = function () {
162
147
  width,
163
148
  height,
164
149
  duration
165
- }); // Load SDK
150
+ });
166
151
 
152
+ // Load SDK
167
153
  useEffect(() => {
168
154
  let canceled = false;
169
-
170
155
  if (!apiLoaded && videoId !== null) {
171
- debug$3('Load API');
156
+ debug('Load API');
172
157
  loadDailymotion().then(api => {
173
158
  if (!canceled) {
174
159
  apiRef.current = api;
175
160
  setApiLoaded(true);
176
- debug$3('API Loaded');
161
+ debug('API Loaded');
177
162
  }
178
163
  });
179
164
  }
180
-
181
165
  return () => {
182
166
  canceled = true;
183
167
  };
184
- }, [videoId, apiLoaded, setApiLoaded]); // Create or update player
168
+ }, [videoId, apiLoaded, setApiLoaded]);
185
169
 
170
+ // Create or update player
186
171
  useEffect(() => {
187
172
  const {
188
173
  current: DM = null
@@ -193,11 +178,9 @@ const useDailymotionPlayer = function () {
193
178
  const {
194
179
  current: element = null
195
180
  } = elementRef;
196
-
197
181
  if (!apiLoaded || videoId === null || element === null) {
198
182
  return;
199
183
  }
200
-
201
184
  const playerParams = {
202
185
  'autoplay-d': autoplay,
203
186
  // muted,
@@ -210,12 +193,11 @@ const useDailymotionPlayer = function () {
210
193
  'ui-start-screen-info': uiStartScreenInfo
211
194
  };
212
195
  let player = currentPlayer;
213
-
214
196
  if (player !== null) {
215
197
  player.load(videoId, {
216
198
  params: playerParams
217
199
  });
218
- debug$3('Load video [ID: %s]', videoId);
200
+ debug('Load video [ID: %s]', videoId);
219
201
  } else {
220
202
  player = DM.player(element, {
221
203
  video: videoId,
@@ -223,13 +205,11 @@ const useDailymotionPlayer = function () {
223
205
  height,
224
206
  params: playerParams
225
207
  });
226
- debug$3('Create player [ID: %s]', videoId);
208
+ debug('Create player [ID: %s]', videoId);
227
209
  }
228
-
229
210
  if (!playerReady) {
230
211
  setPlayerReady(true);
231
212
  }
232
-
233
213
  playerRef.current = player;
234
214
  playerElementRef.current = element;
235
215
  }, [apiLoaded, elementHasChanged, videoId, width, height, autoplay, muted, start, controls, queueAutoplayNext, queueEnable, sharingEnable, uiLogo, uiStartScreenInfo]);
@@ -237,103 +217,98 @@ const useDailymotionPlayer = function () {
237
217
  const {
238
218
  current: player = null
239
219
  } = playerRef;
240
-
241
220
  if (player === null) {
242
221
  return () => {};
243
222
  }
244
-
245
223
  let currentPlayState = playState;
246
224
  let currentMetadata = metadata;
247
-
248
225
  function onPlaybackReady() {
249
226
  setLoaded(true);
250
- debug$3('onPlaybackReady [ID: %s]', videoId);
227
+ debug('onPlaybackReady [ID: %s]', videoId);
251
228
  }
252
-
253
229
  function onLoadedMetadata() {
254
- currentMetadata = { ...currentMetadata,
230
+ currentMetadata = {
231
+ ...currentMetadata,
255
232
  duration: player.duration
256
233
  };
257
234
  setMetadata(currentMetadata);
258
- debug$3('onLoadedMetadata [ID: %s]', videoId);
235
+ debug('onLoadedMetadata [ID: %s]', videoId);
259
236
  }
260
-
261
237
  function onDurationChange() {
262
- currentMetadata = { ...currentMetadata,
238
+ currentMetadata = {
239
+ ...currentMetadata,
263
240
  duration: player.duration
264
241
  };
265
242
  setMetadata(currentMetadata);
266
- debug$3('onDurationChange [ID: %s]', videoId);
243
+ debug('onDurationChange [ID: %s]', videoId);
267
244
  }
268
-
269
245
  function onVolumeChange() {
270
246
  setMuted(player.muted);
271
247
  setVolumeState(player.volume);
272
- debug$3('onVolumeChange [ID: %s]', videoId);
248
+ debug('onVolumeChange [ID: %s]', videoId);
273
249
  }
274
-
275
250
  function onPlay() {
276
- currentPlayState = { ...currentPlayState,
251
+ currentPlayState = {
252
+ ...currentPlayState,
277
253
  playing: true,
278
254
  paused: false,
279
255
  ended: false
280
256
  };
281
257
  setPlayState(currentPlayState);
282
- debug$3('onPlay [ID: %s]', videoId);
258
+ debug('onPlay [ID: %s]', videoId);
283
259
  }
284
-
285
260
  function onPause() {
286
- currentPlayState = { ...currentPlayState,
261
+ currentPlayState = {
262
+ ...currentPlayState,
287
263
  playing: false,
288
264
  paused: true,
289
265
  ended: false
290
266
  };
291
267
  setPlayState(currentPlayState);
292
- debug$3('onPause [ID: %s]', videoId);
268
+ debug('onPause [ID: %s]', videoId);
293
269
  }
294
-
295
270
  function onEnd() {
296
- currentPlayState = { ...currentPlayState,
271
+ currentPlayState = {
272
+ ...currentPlayState,
297
273
  playing: false,
298
274
  paused: false,
299
275
  ended: true
300
276
  };
301
277
  setPlayState(currentPlayState);
302
- debug$3('onEnd [ID: %s]', videoId);
278
+ debug('onEnd [ID: %s]', videoId);
303
279
  }
304
-
305
280
  function onPlaying() {
306
- currentPlayState = { ...currentPlayState,
281
+ currentPlayState = {
282
+ ...currentPlayState,
307
283
  buffering: false
308
284
  };
309
285
  setPlayState(currentPlayState);
310
- debug$3('onPlaying [ID: %s]', videoId);
286
+ debug('onPlaying [ID: %s]', videoId);
311
287
  }
312
-
313
288
  function onWaiting() {
314
- currentPlayState = { ...currentPlayState,
289
+ currentPlayState = {
290
+ ...currentPlayState,
315
291
  buffering: true
316
292
  };
317
293
  setPlayState(currentPlayState);
318
- debug$3('onWaiting [ID: %s]', videoId);
294
+ debug('onWaiting [ID: %s]', videoId);
319
295
  }
320
-
321
296
  function onAdStart() {
322
- currentPlayState = { ...currentPlayState,
297
+ currentPlayState = {
298
+ ...currentPlayState,
323
299
  adPlaying: true
324
300
  };
325
301
  setPlayState(currentPlayState);
326
- debug$3('onAdStart [ID: %s]', videoId);
302
+ debug('onAdStart [ID: %s]', videoId);
327
303
  }
328
-
329
304
  function onAdEnd() {
330
- currentPlayState = { ...currentPlayState,
305
+ currentPlayState = {
306
+ ...currentPlayState,
331
307
  adPlaying: false
332
308
  };
333
309
  setPlayState(currentPlayState);
334
- debug$3('onAdEnd [ID: %s]', videoId);
310
+ debug('onAdEnd [ID: %s]', videoId);
335
311
  }
336
-
337
312
  player.addEventListener('playback_ready', onPlaybackReady);
338
313
  player.addEventListener('loadedmetadata', onLoadedMetadata);
339
314
  player.addEventListener('durationchange', onDurationChange);
@@ -363,37 +338,37 @@ const useDailymotionPlayer = function () {
363
338
  const {
364
339
  current: player
365
340
  } = playerRef;
366
- return player !== null ? player.play() : Promise.reject(noPlayerError$1);
341
+ return player !== null ? player.play() : Promise.reject(NO_PLAYER_ERROR$3);
367
342
  }, []);
368
343
  const pause = useCallback(() => {
369
344
  const {
370
345
  current: player
371
346
  } = playerRef;
372
- return player !== null ? player.pause() : Promise.reject(noPlayerError$1);
347
+ return player !== null ? player.pause() : Promise.reject(NO_PLAYER_ERROR$3);
373
348
  }, []);
374
349
  const setVolume = useCallback(newVolume => {
375
350
  const {
376
351
  current: player
377
352
  } = playerRef;
378
- return player !== null ? player.setVolume(newVolume) : Promise.reject(noPlayerError$1);
353
+ return player !== null ? player.setVolume(newVolume) : Promise.reject(NO_PLAYER_ERROR$3);
379
354
  }, []);
380
355
  const mute = useCallback(() => {
381
356
  const {
382
357
  current: player
383
358
  } = playerRef;
384
- return player !== null ? player.setMute(true) : Promise.reject(noPlayerError$1);
359
+ return player !== null ? player.setMute(true) : Promise.reject(NO_PLAYER_ERROR$3);
385
360
  }, []);
386
361
  const unmute = useCallback(() => {
387
362
  const {
388
363
  current: player
389
364
  } = playerRef;
390
- return player !== null ? player.setMute(false) : Promise.reject(noPlayerError$1);
365
+ return player !== null ? player.setMute(false) : Promise.reject(NO_PLAYER_ERROR$3);
391
366
  }, []);
392
367
  const seek = useCallback(time => {
393
368
  const {
394
369
  current: player
395
370
  } = playerRef;
396
- return player !== null ? player.seek(time) : Promise.reject(noPlayerError$1);
371
+ return player !== null ? player.seek(time) : Promise.reject(NO_PLAYER_ERROR$3);
397
372
  }, []);
398
373
  const {
399
374
  playing
@@ -421,39 +396,35 @@ const useDailymotionPlayer = function () {
421
396
  ...metadata,
422
397
  ...playState
423
398
  };
424
- };
399
+ }
425
400
 
426
401
  const eventsManager$1 = typeof document !== 'undefined' ? new EventsManager(document) : null;
427
-
428
- const useDocumentEvent = (event, callback) => {
402
+ function useDocumentEvent(event, callback) {
429
403
  useEffect(() => {
430
404
  if (eventsManager$1 !== null && callback !== null) {
431
405
  eventsManager$1.subscribe(event, callback);
432
406
  }
433
-
434
407
  return () => {
435
408
  if (eventsManager$1 !== null && callback !== null) {
436
409
  eventsManager$1.unsubscribe(event, callback);
437
410
  }
438
411
  };
439
412
  }, [event, callback]);
440
- };
413
+ }
441
414
 
442
415
  const eventsManager = typeof window !== 'undefined' ? new EventsManager(window) : null;
443
-
444
- const useWindowEvent = (event, callback) => {
416
+ function useWindowEvent(event, callback) {
445
417
  useEffect(() => {
446
418
  if (eventsManager !== null && callback !== null) {
447
419
  eventsManager.subscribe(event, callback);
448
420
  }
449
-
450
421
  return () => {
451
422
  if (eventsManager !== null && callback !== null) {
452
423
  eventsManager.unsubscribe(event, callback);
453
424
  }
454
425
  };
455
426
  }, [event, callback]);
456
- };
427
+ }
457
428
 
458
429
  function useKeyboard() {
459
430
  let keyMap = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
@@ -462,13 +433,11 @@ function useKeyboard() {
462
433
  key
463
434
  } = event;
464
435
  let callback = null;
465
-
466
436
  if (typeof keyMap === 'function') {
467
437
  callback = keyMap;
468
438
  } else if (typeof keyMap[key] !== 'undefined') {
469
439
  callback = typeof keyMap[key] === 'function' ? keyMap[key] : (keyMap[key] || {}).down || null;
470
440
  }
471
-
472
441
  if (callback !== null) {
473
442
  callback(event);
474
443
  }
@@ -478,13 +447,11 @@ function useKeyboard() {
478
447
  key
479
448
  } = event;
480
449
  let callback = null;
481
-
482
450
  if (typeof keyMap === 'function') {
483
451
  callback = keyMap;
484
452
  } else if (typeof keyMap[key] !== 'undefined') {
485
453
  callback = typeof keyMap[key] === 'function' ? keyMap[key] : (keyMap[key] || {}).up || null;
486
454
  }
487
-
488
455
  if (callback !== null) {
489
456
  callback(event);
490
457
  }
@@ -550,15 +517,13 @@ const useItemsPaginated = function (loader) {
550
517
  } = _ref4;
551
518
  return pagesItems.concat(pageItems);
552
519
  }, []) : null;
553
-
554
- const updateState = update => setState({ ...state,
520
+ const updateState = update => setState({
521
+ ...state,
555
522
  ...update
556
523
  });
557
-
558
524
  const updateFromResponse = function (response) {
559
525
  let error = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
560
526
  let reset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
561
-
562
527
  if (error !== null) {
563
528
  updateState({
564
529
  loaded: false,
@@ -566,7 +531,6 @@ const useItemsPaginated = function (loader) {
566
531
  });
567
532
  throw error;
568
533
  }
569
-
570
534
  const newPage = getPageFromResponse(response);
571
535
  const currentPages = currentPagesRef.current || [];
572
536
  const newPages = (reset ? [newPage] : [...currentPages.filter(it => it.page !== newPage.page), newPage]).sort((a, b) => {
@@ -577,23 +541,18 @@ const useItemsPaginated = function (loader) {
577
541
  page: bPage = null
578
542
  } = b;
579
543
  const hasObject = aPage !== null && bPage !== null;
580
-
581
544
  if (hasObject) {
582
545
  if (aPage === bPage) {
583
546
  return 0;
584
547
  }
585
-
586
548
  return aPage > bPage ? 1 : -1;
587
549
  }
588
-
589
550
  if (isNumber(a) && isNumber(b)) {
590
551
  if (a === b) {
591
552
  return 0;
592
553
  }
593
-
594
554
  return a > b ? 1 : -1;
595
555
  }
596
-
597
556
  return 0;
598
557
  });
599
558
  currentPagesRef.current = newPages;
@@ -606,7 +565,6 @@ const useItemsPaginated = function (loader) {
606
565
  });
607
566
  return newPage;
608
567
  };
609
-
610
568
  const getNextPage = () => {
611
569
  const allPages = lastPage !== -1 ? Array.call(null, ...Array(lastPage)).map((it, index) => index + 1) : [];
612
570
  const currentPages = currentPagesRef.current || [];
@@ -614,7 +572,6 @@ const useItemsPaginated = function (loader) {
614
572
  const firstItem = remainingPages.length > 0 ? remainingPages.shift() : null;
615
573
  return firstItem !== null ? firstItem : null;
616
574
  };
617
-
618
575
  const loadItems = requestPage => {
619
576
  updateState({
620
577
  loading: true
@@ -623,7 +580,6 @@ const useItemsPaginated = function (loader) {
623
580
  if (onLoaded !== null) {
624
581
  onLoaded(response);
625
582
  }
626
-
627
583
  return response;
628
584
  }).catch(error => {
629
585
  if (onError !== null) {
@@ -631,35 +587,28 @@ const useItemsPaginated = function (loader) {
631
587
  }
632
588
  });
633
589
  };
634
-
635
590
  const loadPage = pageToLoad => {
636
591
  if (loading) {
637
592
  return Promise.reject();
638
593
  }
639
-
640
594
  const currentPages = currentPagesRef.current || [];
641
595
  const foundPage = currentPages.find(it => it.page === pageToLoad) || null;
642
-
643
596
  if (foundPage !== null) {
644
597
  return Promise.resolve(foundPage);
645
598
  }
646
-
647
599
  return loadItems(pageToLoad);
648
600
  };
649
-
650
601
  const loadNextPage = () => {
651
602
  if (loading) {
652
603
  return Promise.reject();
653
604
  }
654
-
655
605
  const nextPage = getNextPage();
656
606
  return nextPage !== null ? loadItems(nextPage) : Promise.resolve();
657
- }; // Reset all on query change
658
-
607
+ };
659
608
 
609
+ // Reset all on query change
660
610
  useEffect(() => {
661
611
  const hadState = lastState.current !== null;
662
-
663
612
  if (hadState) {
664
613
  currentPagesRef.current = null;
665
614
  updateState({
@@ -674,7 +623,6 @@ const useItemsPaginated = function (loader) {
674
623
  useEffect(() => {
675
624
  const hadState = lastState.current !== null;
676
625
  lastState.current = initialState;
677
-
678
626
  if (hadState) {
679
627
  currentPagesRef.current = initialState.pages;
680
628
  setState(initialState);
@@ -684,14 +632,11 @@ const useItemsPaginated = function (loader) {
684
632
  if (loader === null) {
685
633
  return () => {};
686
634
  }
687
-
688
635
  let loadPromise = null;
689
636
  const pageToLoad = initialPages === null && page === null ? 1 : page;
690
-
691
637
  if (pageToLoad !== null) {
692
638
  loadPromise = loadItems(pageToLoad);
693
639
  }
694
-
695
640
  return () => {
696
641
  if (loadPromise !== null) {
697
642
  loadPromise.cancel();
@@ -719,10 +664,8 @@ const useItemsPaginated = function (loader) {
719
664
  };
720
665
  };
721
666
 
722
- const debug$2 = createDebug('folklore:video:native');
723
- const noPlayerError = new Error('No player');
724
-
725
- const useNativeVideoPlayer = function (url) {
667
+ const NO_PLAYER_ERROR$2 = new Error('No player');
668
+ function useNativeVideoPlayer(url) {
726
669
  let {
727
670
  width = 0,
728
671
  height = 0,
@@ -731,6 +674,7 @@ const useNativeVideoPlayer = function (url) {
731
674
  timeUpdateInterval = 1000,
732
675
  onTimeUpdate: customOnTimeUpdate = null
733
676
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
677
+ const debug = useMemo(() => createDebug('folklore:video:native'), []);
734
678
  const elementRef = useRef(null);
735
679
  const [loaded, setLoaded] = useState(false);
736
680
  const [volume, setVolumeState] = useState(initialMuted ? 0 : 1);
@@ -749,89 +693,77 @@ const useNativeVideoPlayer = function (url) {
749
693
  const {
750
694
  current: player
751
695
  } = elementRef;
752
- return player !== null ? player.play() : Promise.reject(noPlayerError);
696
+ return player !== null ? player.play() : Promise.reject(NO_PLAYER_ERROR$2);
753
697
  }, []);
754
698
  const pause = useCallback(() => {
755
699
  const {
756
700
  current: player
757
701
  } = elementRef;
758
- return player !== null ? player.pause() : Promise.reject(noPlayerError);
702
+ return player !== null ? player.pause() : Promise.reject(NO_PLAYER_ERROR$2);
759
703
  }, []);
760
704
  const setVolume = useCallback(newVolume => {
761
705
  const {
762
706
  current: player
763
707
  } = elementRef;
764
-
765
708
  if (player !== null) {
766
709
  player.volume = newVolume;
767
710
  return Promise.resolve(newVolume);
768
711
  }
769
-
770
- return Promise.reject(noPlayerError);
712
+ return Promise.reject(NO_PLAYER_ERROR$2);
771
713
  }, []);
772
714
  const mute = useCallback(() => {
773
715
  const {
774
716
  current: player
775
717
  } = elementRef;
776
-
777
718
  if (player !== null) {
778
719
  player.muted = true;
779
720
  return Promise.resolve(true);
780
721
  }
781
-
782
- return Promise.reject(noPlayerError);
722
+ return Promise.reject(NO_PLAYER_ERROR$2);
783
723
  }, []);
784
724
  const unmute = useCallback(() => {
785
725
  const {
786
726
  current: player
787
727
  } = elementRef;
788
-
789
728
  if (player !== null) {
790
729
  player.muted = false;
791
730
  return Promise.resolve(false);
792
731
  }
793
-
794
- return Promise.reject(noPlayerError);
732
+ return Promise.reject(NO_PLAYER_ERROR$2);
795
733
  }, []);
796
734
  const seek = useCallback(newTime => {
797
735
  const {
798
736
  current: player
799
737
  } = elementRef;
800
-
801
738
  if (player !== null) {
802
739
  player.currentTime = newTime;
803
740
  return Promise.resolve(newTime);
804
741
  }
805
-
806
- return Promise.reject(noPlayerError);
742
+ return Promise.reject(NO_PLAYER_ERROR$2);
807
743
  }, []);
808
744
  const setLoop = useCallback(newLoop => {
809
745
  const {
810
746
  current: player
811
747
  } = elementRef;
812
-
813
748
  if (player !== null) {
814
749
  player.loop = newLoop;
815
750
  return Promise.resolve(newLoop);
816
751
  }
752
+ return Promise.reject(NO_PLAYER_ERROR$2);
753
+ }, []);
817
754
 
818
- return Promise.reject(noPlayerError);
819
- }, []); // Bind player events
820
-
755
+ // Bind player events
821
756
  useEffect(() => {
822
757
  const {
823
758
  current: player
824
759
  } = elementRef;
825
-
826
760
  if (player === null) {
827
761
  return () => {};
828
762
  }
829
-
830
763
  const onCanPlay = () => {
831
764
  setLoaded(true);
832
- debug$2('onCanPlay [URL: %s]', url);
765
+ debug('onCanPlay [URL: %s]', url);
833
766
  };
834
-
835
767
  const onMetadataLoaded = () => {
836
768
  const newMetadata = {
837
769
  duration: player.duration,
@@ -839,9 +771,8 @@ const useNativeVideoPlayer = function (url) {
839
771
  height: player.videoHeight
840
772
  };
841
773
  setMetadata(newMetadata);
842
- debug$2('onMetadataLoaded [URL: %s]', url);
774
+ debug('onMetadataLoaded [URL: %s]', url);
843
775
  };
844
-
845
776
  const onPlay = () => {
846
777
  setPlayState({
847
778
  playing: true,
@@ -849,9 +780,8 @@ const useNativeVideoPlayer = function (url) {
849
780
  ended: false,
850
781
  buffering: false
851
782
  });
852
- debug$2('onPlay [URL: %s]', url);
783
+ debug('onPlay [URL: %s]', url);
853
784
  };
854
-
855
785
  const onPause = () => {
856
786
  setPlayState({
857
787
  playing: false,
@@ -859,9 +789,8 @@ const useNativeVideoPlayer = function (url) {
859
789
  ended: false,
860
790
  buffering: false
861
791
  });
862
- debug$2('onPause [URL: %s]', url);
792
+ debug('onPause [URL: %s]', url);
863
793
  };
864
-
865
794
  const onEnded = () => {
866
795
  setPlayState({
867
796
  playing: false,
@@ -869,17 +798,16 @@ const useNativeVideoPlayer = function (url) {
869
798
  ended: true,
870
799
  buffering: false
871
800
  });
872
- debug$2('onEnded [URL: %s]', url);
801
+ debug('onEnded [URL: %s]', url);
873
802
  };
874
-
875
- debug$2('Bind events [URL: %s]', url);
803
+ debug('Bind events [URL: %s]', url);
876
804
  player.addEventListener('canplay', onCanPlay);
877
805
  player.addEventListener('metadataloaded', onMetadataLoaded);
878
806
  player.addEventListener('play', onPlay);
879
807
  player.addEventListener('pause', onPause);
880
808
  player.addEventListener('ended', onEnded);
881
809
  return () => {
882
- debug$2('Unbind events [URL: %s]', url);
810
+ debug('Unbind events [URL: %s]', url);
883
811
  player.removeEventListener('canplay', onCanPlay);
884
812
  player.removeEventListener('metadataloaded', onMetadataLoaded);
885
813
  player.removeEventListener('play', onPlay);
@@ -914,42 +842,37 @@ const useNativeVideoPlayer = function (url) {
914
842
  ...metadata,
915
843
  ...playState
916
844
  };
917
- };
845
+ }
918
846
 
919
847
  const observersCache = new Map();
920
-
921
- const getOptionsKey = _ref => {
848
+ function getOptionsKey(_ref) {
922
849
  let {
923
850
  root = null,
924
851
  rootMargin,
925
852
  threshold = null
926
853
  } = _ref;
927
- return "root_".concat(root, "_rootMargin_").concat(rootMargin || null, "_threshold_").concat(threshold);
928
- };
929
-
930
- const createObserver = function (Observer) {
854
+ return `root_${root}_rootMargin_${rootMargin || null}_threshold_${threshold}`;
855
+ }
856
+ function createObserver(Observer) {
931
857
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
932
858
  let subscribers = [];
933
-
934
859
  const addSubscriber = (element, callback) => {
935
860
  const currentSubscriber = subscribers.find(it => it.element === element) || null;
936
-
937
861
  if (currentSubscriber !== null) {
938
- return subscribers.map(it => it.element === element && it.callbacks.indexOf(callback) === -1 ? { ...it,
862
+ return subscribers.map(it => it.element === element && it.callbacks.indexOf(callback) === -1 ? {
863
+ ...it,
939
864
  callbacks: [...it.callbacks, callback]
940
865
  } : it).filter(it => it.callbacks.length > 0);
941
866
  }
942
-
943
867
  return [...subscribers, {
944
868
  element,
945
869
  callbacks: [callback]
946
870
  }];
947
871
  };
948
-
949
- const removeSubscriber = (element, callback) => subscribers.map(it => it.element === element ? { ...it,
872
+ const removeSubscriber = (element, callback) => subscribers.map(it => it.element === element ? {
873
+ ...it,
950
874
  callbacks: it.callbacks.filter(subCallback => subCallback !== callback)
951
875
  } : it).filter(it => it.callbacks.length > 0);
952
-
953
876
  const onUpdate = entries => {
954
877
  entries.forEach(entry => {
955
878
  subscribers.forEach(_ref2 => {
@@ -957,7 +880,6 @@ const createObserver = function (Observer) {
957
880
  element,
958
881
  callbacks
959
882
  } = _ref2;
960
-
961
883
  if (element === entry.target) {
962
884
  callbacks.forEach(callback => {
963
885
  callback(entry);
@@ -966,13 +888,10 @@ const createObserver = function (Observer) {
966
888
  });
967
889
  });
968
890
  };
969
-
970
891
  const observer = new Observer(onUpdate, options);
971
-
972
892
  const unsubscribe = function (element) {
973
893
  let callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
974
894
  subscribers = removeSubscriber(element, callback);
975
-
976
895
  if (typeof observer.unobserve === 'undefined') {
977
896
  observer.disconnect();
978
897
  subscribers.forEach(subscriber => {
@@ -980,48 +899,46 @@ const createObserver = function (Observer) {
980
899
  });
981
900
  return;
982
901
  }
983
-
984
902
  const currentSubscriber = subscribers.find(it => it.element === element) || null;
985
-
986
903
  if (currentSubscriber === null) {
987
904
  observer.unobserve(element);
988
905
  }
989
906
  };
990
-
991
907
  const subscribe = (element, callback) => {
992
908
  const currentSubscriber = subscribers.find(it => it.element === element) || null;
993
909
  subscribers = addSubscriber(element, callback);
994
-
995
910
  if (currentSubscriber === null) {
996
911
  observer.observe(element);
997
912
  }
998
913
  };
999
-
1000
914
  return {
1001
915
  subscribe,
1002
916
  unsubscribe,
1003
917
  observer
1004
918
  };
1005
- };
1006
-
1007
- const getObserver = function (Observer) {
919
+ }
920
+ function getObserver() {
921
+ let Observer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
1008
922
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
923
+ if (Observer === null) {
924
+ return {
925
+ observer: null,
926
+ subscribe: () => {},
927
+ unsubscribe: () => {}
928
+ };
929
+ }
1009
930
  const observerKey = getOptionsKey(options);
1010
-
1011
931
  if (!observersCache.has(Observer)) {
1012
932
  observersCache.set(Observer, {});
1013
933
  }
1014
-
1015
934
  const observers = observersCache.get(Observer);
1016
-
1017
935
  if (typeof observers[observerKey] === 'undefined') {
1018
936
  observers[observerKey] = createObserver(Observer, options);
1019
937
  observersCache.set(Observer, observers);
1020
938
  }
1021
-
1022
939
  return observers[observerKey];
1023
- };
1024
- const useObserver = function (Observer) {
940
+ }
941
+ function useObserver(Observer) {
1025
942
  let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1026
943
  let initialEntry = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1027
944
  const {
@@ -1039,26 +956,19 @@ const useObserver = function (Observer) {
1039
956
  const {
1040
957
  current: nodeElement
1041
958
  } = nodeRef;
1042
-
1043
959
  const callback = newEntry => setEntry(newEntry);
1044
-
1045
960
  let unsubscribe = null;
1046
-
1047
961
  if (nodeElement !== null) {
1048
962
  const newOpts = {};
1049
-
1050
963
  if (root !== null) {
1051
964
  newOpts.root = root;
1052
965
  }
1053
-
1054
966
  if (rootMargin !== null) {
1055
967
  newOpts.rootMargin = rootMargin;
1056
968
  }
1057
-
1058
969
  if (threshold !== null) {
1059
970
  newOpts.threshold = threshold;
1060
971
  }
1061
-
1062
972
  const {
1063
973
  subscribe,
1064
974
  unsubscribe: localUnsubscribe
@@ -1066,7 +976,6 @@ const useObserver = function (Observer) {
1066
976
  unsubscribe = localUnsubscribe;
1067
977
  subscribe(nodeElement, callback);
1068
978
  }
1069
-
1070
979
  currentElement.current = nodeElement;
1071
980
  return () => {
1072
981
  if (unsubscribe !== null) {
@@ -1078,11 +987,11 @@ const useObserver = function (Observer) {
1078
987
  ref: nodeRef,
1079
988
  entry
1080
989
  };
1081
- };
990
+ }
991
+
1082
992
  /**
1083
993
  * Intersection Observer
1084
994
  */
1085
-
1086
995
  const defaultThreshold = [0, 1.0];
1087
996
  const intersectionObserverInitialEntry = {
1088
997
  target: null,
@@ -1094,72 +1003,71 @@ const intersectionObserverInitialEntry = {
1094
1003
  boundingClientRect: null,
1095
1004
  rootBounds: null
1096
1005
  };
1097
- const useIntersectionObserver = function () {
1006
+ function useIntersectionObserver() {
1098
1007
  let {
1099
1008
  root = null,
1100
1009
  rootMargin = '0px',
1101
1010
  threshold = defaultThreshold,
1102
1011
  disabled = false
1103
1012
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1104
- return useObserver(IntersectionObserver, {
1013
+ return useObserver(typeof IntersectionObserver !== 'undefined' ? IntersectionObserver : null, {
1105
1014
  root,
1106
1015
  rootMargin,
1107
1016
  threshold,
1108
1017
  disabled
1109
1018
  }, intersectionObserverInitialEntry);
1110
- };
1019
+ }
1020
+
1111
1021
  /**
1112
1022
  * Resize Observer
1113
1023
  */
1114
-
1115
1024
  const resizeObserverInitialEntry = {
1116
1025
  target: null,
1117
1026
  contentRect: null,
1118
1027
  contentBoxSize: null,
1119
1028
  borderBoxSize: null
1120
1029
  };
1121
- const useResizeObserver = function () {
1030
+ function useResizeObserver() {
1122
1031
  let {
1123
1032
  disabled = false
1124
1033
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1125
- return useObserver(ResizeObserver, {
1034
+ return useObserver(typeof ResizeObserver !== 'undefined' ? ResizeObserver : null, {
1126
1035
  disabled
1127
1036
  }, resizeObserverInitialEntry);
1128
- };
1037
+ }
1129
1038
 
1130
1039
  const NO_PLAYER_ERROR$1 = new Error('No player');
1131
- const debug$1 = createDebug('folklore:video:youtube');
1132
-
1133
- function useYouTubePlayer(id) {
1040
+ function useVimeoPlayer(id) {
1134
1041
  let {
1135
1042
  width = 0,
1136
1043
  height = 0,
1137
1044
  duration = 0,
1138
1045
  autoplay = false,
1139
- controls = true,
1046
+ autopause = true,
1047
+ byline = false,
1048
+ controls = false,
1049
+ initialMuted = false,
1140
1050
  timeUpdateInterval = 1000,
1141
- muted: initialMuted = false,
1142
- onVolumeChange: customOnVolumeChange = null,
1143
1051
  onTimeUpdate: customOnTimeUpdate = null,
1144
1052
  getVideoId = url => {
1145
- if (url === null || url.match(/^https?:/) === null) {
1053
+ if (url === null || url.match(/^[0-9]+$/) !== null) {
1146
1054
  return url;
1147
1055
  }
1148
-
1149
- const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
1150
- const match = url.match(regExp);
1151
- return match && match[7].length === 11 ? match[7] : null;
1056
+ const match = url.match(/\/[0-9]+/);
1057
+ return match !== null ? match[1] : null;
1152
1058
  }
1153
1059
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1154
- const [apiLoaded, setApiLoaded] = useState(typeof window.YT !== 'undefined');
1155
- const apiRef = useRef(typeof window.YT !== 'undefined' ? window.YT : null);
1060
+ const debug = useMemo(() => createDebug('folklore:video:vimeo'), []);
1061
+ const [apiLoaded, setApiLoaded] = useState(false);
1062
+ const apiRef = useRef(null);
1156
1063
  const elementRef = useRef(null);
1157
1064
  const playerRef = useRef(null);
1158
1065
  const playerElementRef = useRef(elementRef.current);
1159
1066
  const elementHasChanged = elementRef.current !== playerElementRef.current;
1160
1067
  const videoId = useMemo(() => getVideoId(id), [id]);
1161
1068
  const [ready, setReady] = useState(false);
1162
- const [muted, setMuted] = useState(initialMuted);
1069
+ const [loaded, setLoaded] = useState(false);
1070
+ const [volume, setVolumeState] = useState(initialMuted ? 0 : 1);
1163
1071
  const [playState, setPlayState] = useState({
1164
1072
  playing: false,
1165
1073
  paused: false,
@@ -1171,93 +1079,93 @@ function useYouTubePlayer(id) {
1171
1079
  height,
1172
1080
  duration
1173
1081
  });
1082
+
1083
+ // Load SDK
1174
1084
  useEffect(() => {
1175
1085
  let canceled = false;
1176
-
1177
- if (!apiLoaded && videoId !== null) {
1178
- debug$1('Load API');
1179
- loadYouTube().then(api => {
1086
+ if (!apiLoaded && id !== null) {
1087
+ debug('Load API');
1088
+ loadVimeo().then(api => {
1180
1089
  if (!canceled) {
1181
1090
  apiRef.current = api;
1182
1091
  setApiLoaded(true);
1183
- debug$1('API Loaded');
1092
+ debug('API Loaded');
1184
1093
  }
1185
1094
  });
1186
1095
  }
1187
-
1188
1096
  return () => {
1189
1097
  canceled = true;
1190
1098
  };
1191
- }, [apiLoaded, videoId, setApiLoaded]);
1099
+ }, [id]);
1192
1100
  const play = useCallback(() => {
1193
1101
  const {
1194
1102
  current: player
1195
1103
  } = playerRef;
1196
- return player !== null && typeof player.playVideo !== 'undefined' ? Promise.resolve(player.playVideo()) : Promise.reject(NO_PLAYER_ERROR$1);
1104
+ return player !== null ? player.play() : Promise.reject(NO_PLAYER_ERROR$1);
1197
1105
  }, []);
1198
1106
  const pause = useCallback(() => {
1199
1107
  const {
1200
1108
  current: player
1201
1109
  } = playerRef;
1202
- return player !== null && typeof player.pauseVideo !== 'undefined' ? Promise.resolve(player.pauseVideo()) : Promise.reject(NO_PLAYER_ERROR$1);
1110
+ return player !== null ? player.pause() : Promise.reject(NO_PLAYER_ERROR$1);
1203
1111
  }, []);
1204
- const setVolume = useCallback(volume => {
1112
+ const setVolume = useCallback(newVolume => {
1205
1113
  const {
1206
1114
  current: player
1207
1115
  } = playerRef;
1208
- const promise = player !== null && typeof player.setVolume !== 'undefined' ? Promise.resolve(player.setVolume(volume * 100)) : Promise.reject(NO_PLAYER_ERROR$1);
1209
-
1210
- if (customOnVolumeChange) {
1211
- customOnVolumeChange(volume);
1212
- }
1213
-
1214
- return promise;
1215
- }, [customOnVolumeChange]);
1116
+ return player !== null ? player.setVolume(newVolume) : Promise.reject(NO_PLAYER_ERROR$1);
1117
+ }, []);
1216
1118
  const mute = useCallback(() => {
1217
1119
  const {
1218
1120
  current: player
1219
1121
  } = playerRef;
1220
- return (player !== null && typeof player.mute !== 'undefined' ? Promise.resolve(player.mute()) : Promise.reject(NO_PLAYER_ERROR$1)).then(() => setMuted(true));
1221
- }, [setMuted]);
1122
+ return player !== null ? player.setVolume(0) : Promise.reject(NO_PLAYER_ERROR$1);
1123
+ }, []);
1222
1124
  const unmute = useCallback(() => {
1223
1125
  const {
1224
1126
  current: player
1225
1127
  } = playerRef;
1226
- return (player !== null && typeof player.unMute !== 'undefined' ? Promise.resolve(player.unMute()) : Promise.reject(NO_PLAYER_ERROR$1)).then(() => setMuted(false));
1128
+ return player !== null ? player.setVolume(1) : Promise.reject(NO_PLAYER_ERROR$1);
1227
1129
  }, []);
1228
1130
  const seek = useCallback(time => {
1229
1131
  const {
1230
1132
  current: player
1231
1133
  } = playerRef;
1232
- return player !== null && typeof player.seekTo !== 'undefined' ? Promise.resolve(player.seekTo(time)) : Promise.reject(NO_PLAYER_ERROR$1);
1134
+ return player !== null ? player.setCurrentTime(time) : Promise.reject(NO_PLAYER_ERROR$1);
1233
1135
  }, []);
1234
1136
  const setLoop = useCallback(loop => {
1235
1137
  const {
1236
1138
  current: player
1237
1139
  } = playerRef;
1238
- return player !== null && typeof player.setLoop !== 'undefined' ? Promise.resolve(player.setLoop(loop)) : Promise.reject(NO_PLAYER_ERROR$1);
1140
+ return player !== null ? player.setLoop(loop) : Promise.reject(NO_PLAYER_ERROR$1);
1239
1141
  }, []);
1240
- const destroyPlayer = useCallback(() => {
1241
- if (playerRef.current !== null) {
1242
- debug$1('Unset player');
1142
+ const destroyVideo = useCallback(() => {
1143
+ const {
1144
+ current: player
1145
+ } = playerRef;
1146
+ if (player !== null) {
1147
+ debug('Unload video');
1148
+ player.unload();
1149
+ }
1150
+ if (player !== null) {
1151
+ debug('Unset video');
1243
1152
  playerRef.current = null;
1244
1153
  }
1245
- }, []); // Detect iframe switch and destroy player
1246
-
1154
+ }, []);
1247
1155
  useEffect(() => {
1248
1156
  const {
1249
1157
  current: currentPlayer
1250
1158
  } = playerRef;
1251
-
1252
1159
  if (playerElementRef.current !== elementRef.current && currentPlayer !== null) {
1253
- debug$1('iFrame switched');
1254
- destroyPlayer();
1160
+ debug('iFrame switched');
1161
+ destroyVideo();
1255
1162
  }
1256
- }, [elementHasChanged]); // Create player
1163
+ }, [elementHasChanged]);
1257
1164
 
1165
+ // Create player
1258
1166
  useEffect(() => {
1259
1167
  const {
1260
- current: YT = null
1168
+ current: Player = null
1261
1169
  } = apiRef;
1262
1170
  const {
1263
1171
  current: currentPlayer = null
@@ -1265,89 +1173,140 @@ function useYouTubePlayer(id) {
1265
1173
  const {
1266
1174
  current: element = null
1267
1175
  } = elementRef;
1268
-
1269
1176
  if (!apiLoaded || videoId === null || element === null) {
1270
- destroyPlayer();
1177
+ destroyVideo();
1271
1178
  return;
1272
1179
  }
1273
-
1274
1180
  let player = currentPlayer;
1275
-
1276
- if (player !== null && typeof player.loadVideoById !== 'undefined') {
1277
- debug$1('Switch video [ID: %s]', videoId);
1278
- player.loadVideoById(videoId);
1181
+ if (player === null) {
1182
+ debug('Create player [ID: %s]', videoId);
1183
+ player = new Player(element, {
1184
+ id: videoId,
1185
+ autoplay,
1186
+ autopause,
1187
+ byline,
1188
+ controls,
1189
+ muted: initialMuted,
1190
+ background: !controls
1191
+ });
1192
+ player.ready().then(() => setReady(true)).catch(e => {
1193
+ debug('ERROR: %o', e);
1194
+ });
1279
1195
  } else {
1280
- debug$1('Create player [ID: %s]', videoId);
1281
-
1282
- const onReady = _ref => {
1283
- let {
1284
- target
1285
- } = _ref;
1286
- player = target;
1287
- playerRef.current = target;
1288
- setReady(true);
1289
- const newDuration = target.getDuration();
1196
+ debug('Load video [ID: %s]', videoId);
1197
+ player.loadVideo(videoId).catch(e => {
1198
+ debug('ERROR: %o', e);
1199
+ });
1200
+ }
1201
+ playerRef.current = player;
1202
+ playerElementRef.current = element;
1203
+ }, [apiLoaded, videoId, elementHasChanged, setReady, destroyVideo, setLoaded]);
1290
1204
 
1291
- if (newDuration !== metadata.duration) {
1292
- setMetadata({ ...metadata,
1293
- duration: newDuration
1294
- });
1205
+ // Bind player events
1206
+ useEffect(() => {
1207
+ const {
1208
+ current: player
1209
+ } = playerRef;
1210
+ if (player === null) {
1211
+ return () => {};
1212
+ }
1213
+ let canceled = false;
1214
+ const onLoaded = () => {
1215
+ Promise.all([player.getDuration(), player.getVideoWidth(), player.getVideoHeight(), player.getMuted()]).then(_ref => {
1216
+ let [newDuration, newWidth, newHeight, newMuted] = _ref;
1217
+ if (canceled) {
1218
+ return;
1295
1219
  }
1296
-
1297
- debug$1('onReady [ID: %s]', videoId);
1298
- };
1299
-
1300
- const onStateChange = _ref2 => {
1301
- let {
1302
- data: state
1303
- } = _ref2;
1304
- const newState = {
1305
- playing: state === YT.PlayerState.PLAYING,
1306
- paused: state === YT.PlayerState.PAUSED,
1307
- ended: state === YT.PlayerState.ENDED,
1308
- buffering: state === YT.PlayerState.BUFFERING
1220
+ const newMetadata = {
1221
+ duration: newDuration,
1222
+ width: newWidth,
1223
+ height: newHeight
1309
1224
  };
1310
- setPlayState(newState);
1311
- let stateLabel = null;
1312
-
1313
- if (newState.playing) {
1314
- stateLabel = 'playing';
1315
- } else if (newState.paused) {
1316
- stateLabel = 'paused';
1317
- } else if (newState.ended) {
1318
- stateLabel = 'ended';
1319
- } else if (newState.buffering) {
1320
- stateLabel = 'buffering';
1321
- } else if (state === -1) {
1322
- stateLabel = 'not started';
1323
- } else if (state === 0) {
1324
- stateLabel = 'stopped';
1225
+ setMetadata(newMetadata);
1226
+ if (newMuted) {
1227
+ setVolumeState(0);
1325
1228
  }
1326
-
1327
- debug$1('onStateChange %s [ID: %s]', stateLabel, videoId);
1328
- };
1329
-
1330
- player = new YT.Player(element, {
1331
- videoId,
1332
- playerVars: {
1333
- controls,
1334
- autoplay: autoplay ? 1 : 0,
1335
- mute: initialMuted,
1336
- playsinline: true,
1337
- rel: 0,
1338
- showinfo: 0,
1339
- modestbranding: 1
1340
- },
1341
- events: {
1342
- onReady,
1343
- onStateChange
1229
+ setLoaded(true);
1230
+ });
1231
+ debug('onLoaded [ID: %s]', videoId);
1232
+ };
1233
+ const onPlay = () => {
1234
+ setPlayState({
1235
+ playing: true,
1236
+ paused: false,
1237
+ ended: false,
1238
+ buffering: false
1239
+ });
1240
+ debug('onPlay [ID: %s]', videoId);
1241
+ player.getMuted().then(newMuted => {
1242
+ if (!canceled && newMuted) {
1243
+ setVolumeState(0);
1344
1244
  }
1245
+ }).catch(() => {});
1246
+ };
1247
+ const onPause = () => {
1248
+ setPlayState({
1249
+ playing: false,
1250
+ paused: true,
1251
+ ended: false,
1252
+ buffering: false
1345
1253
  });
1346
- }
1347
-
1348
- playerRef.current = player;
1349
- playerElementRef.current = element;
1350
- }, [apiLoaded, videoId, elementHasChanged, setPlayState, setReady, setMetadata, destroyPlayer]);
1254
+ debug('onPause [ID: %s]', videoId);
1255
+ };
1256
+ const onVolumeChange = _ref2 => {
1257
+ let {
1258
+ volume: newVolume
1259
+ } = _ref2;
1260
+ setVolumeState(newVolume);
1261
+ debug('onVolumeChange [ID: %s]', videoId);
1262
+ };
1263
+ const onEnded = () => {
1264
+ setPlayState({
1265
+ playing: false,
1266
+ paused: false,
1267
+ ended: true,
1268
+ buffering: false
1269
+ });
1270
+ debug('onEnded [ID: %s]', videoId);
1271
+ };
1272
+ const onBufferStart = () => {
1273
+ setPlayState({
1274
+ playing: true,
1275
+ paused: false,
1276
+ ended: false,
1277
+ buffering: true
1278
+ });
1279
+ debug('onBufferStart [ID: %s]', videoId);
1280
+ };
1281
+ const onBufferEnded = () => {
1282
+ setPlayState({
1283
+ playing: true,
1284
+ paused: false,
1285
+ ended: false,
1286
+ buffering: false
1287
+ });
1288
+ debug('onBufferStart [ID: %s]', videoId);
1289
+ };
1290
+ debug('Bind events [ID: %s]', videoId);
1291
+ player.on('loaded', onLoaded);
1292
+ player.on('play', onPlay);
1293
+ player.on('pause', onPause);
1294
+ player.on('volumechange', onVolumeChange);
1295
+ player.on('ended', onEnded);
1296
+ player.on('bufferstart', onBufferStart);
1297
+ player.on('bufferend', onBufferEnded);
1298
+ return () => {
1299
+ canceled = true;
1300
+ debug('Unbind events [ID: %s]', videoId);
1301
+ player.off('loaded', onLoaded);
1302
+ player.off('play', onPlay);
1303
+ player.off('pause', onPause);
1304
+ player.off('volumechange', onVolumeChange);
1305
+ player.off('ended', onEnded);
1306
+ player.off('bufferstart', onBufferStart);
1307
+ player.off('bufferend', onBufferEnded);
1308
+ };
1309
+ }, [videoId, playerRef.current, setPlayState, setMetadata, setVolumeState, setLoaded]);
1351
1310
  const {
1352
1311
  playing
1353
1312
  } = playState;
@@ -1371,47 +1330,45 @@ function useYouTubePlayer(id) {
1371
1330
  setLoop,
1372
1331
  ready,
1373
1332
  currentTime,
1374
- muted,
1375
- loaded: ready,
1333
+ loaded,
1334
+ muted: volume === 0,
1335
+ volume,
1376
1336
  ...metadata,
1377
1337
  ...playState
1378
1338
  };
1379
1339
  }
1380
1340
 
1381
- const debug = createDebug('folklore:video:vimeo');
1382
1341
  const NO_PLAYER_ERROR = new Error('No player');
1383
-
1384
- const useVimeoPlayer = function (id) {
1342
+ function useYouTubePlayer(id) {
1385
1343
  let {
1386
1344
  width = 0,
1387
1345
  height = 0,
1388
1346
  duration = 0,
1389
1347
  autoplay = false,
1390
- autopause = true,
1391
- byline = false,
1392
- controls = false,
1393
- initialMuted = false,
1348
+ controls = true,
1394
1349
  timeUpdateInterval = 1000,
1350
+ muted: initialMuted = false,
1351
+ onVolumeChange: customOnVolumeChange = null,
1395
1352
  onTimeUpdate: customOnTimeUpdate = null,
1396
1353
  getVideoId = url => {
1397
- if (url === null || url.match(/^[0-9]+$/) !== null) {
1354
+ if (url === null || url.match(/^https?:/) === null) {
1398
1355
  return url;
1399
1356
  }
1400
-
1401
- const match = url.match(/\/[0-9]+/);
1402
- return match !== null ? match[1] : null;
1357
+ const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
1358
+ const match = url.match(regExp);
1359
+ return match && match[7].length === 11 ? match[7] : null;
1403
1360
  }
1404
1361
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1405
- const [apiLoaded, setApiLoaded] = useState(false);
1406
- const apiRef = useRef(null);
1362
+ const debug = useMemo(() => createDebug('folklore:video:youtube'), []);
1363
+ const [apiLoaded, setApiLoaded] = useState(typeof window !== 'undefined' && typeof window.YT !== 'undefined');
1364
+ const apiRef = useRef(typeof window !== 'undefined' && typeof window.YT !== 'undefined' ? window.YT : null);
1407
1365
  const elementRef = useRef(null);
1408
1366
  const playerRef = useRef(null);
1409
1367
  const playerElementRef = useRef(elementRef.current);
1410
1368
  const elementHasChanged = elementRef.current !== playerElementRef.current;
1411
1369
  const videoId = useMemo(() => getVideoId(id), [id]);
1412
1370
  const [ready, setReady] = useState(false);
1413
- const [loaded, setLoaded] = useState(false);
1414
- const [volume, setVolumeState] = useState(initialMuted ? 0 : 1);
1371
+ const [muted, setMuted] = useState(initialMuted);
1415
1372
  const [playState, setPlayState] = useState({
1416
1373
  playing: false,
1417
1374
  paused: false,
@@ -1422,14 +1379,12 @@ const useVimeoPlayer = function (id) {
1422
1379
  width,
1423
1380
  height,
1424
1381
  duration
1425
- }); // Load SDK
1426
-
1382
+ });
1427
1383
  useEffect(() => {
1428
1384
  let canceled = false;
1429
-
1430
- if (!apiLoaded && id !== null) {
1385
+ if (!apiLoaded && videoId !== null) {
1431
1386
  debug('Load API');
1432
- loadVimeo().then(api => {
1387
+ loadYouTube().then(api => {
1433
1388
  if (!canceled) {
1434
1389
  apiRef.current = api;
1435
1390
  setApiLoaded(true);
@@ -1437,82 +1392,79 @@ const useVimeoPlayer = function (id) {
1437
1392
  }
1438
1393
  });
1439
1394
  }
1440
-
1441
1395
  return () => {
1442
1396
  canceled = true;
1443
1397
  };
1444
- }, [id]);
1398
+ }, [apiLoaded, videoId, setApiLoaded]);
1445
1399
  const play = useCallback(() => {
1446
1400
  const {
1447
1401
  current: player
1448
1402
  } = playerRef;
1449
- return player !== null ? player.play() : Promise.reject(NO_PLAYER_ERROR);
1403
+ return player !== null && typeof player.playVideo !== 'undefined' ? Promise.resolve(player.playVideo()) : Promise.reject(NO_PLAYER_ERROR);
1450
1404
  }, []);
1451
1405
  const pause = useCallback(() => {
1452
1406
  const {
1453
1407
  current: player
1454
1408
  } = playerRef;
1455
- return player !== null ? player.pause() : Promise.reject(NO_PLAYER_ERROR);
1409
+ return player !== null && typeof player.pauseVideo !== 'undefined' ? Promise.resolve(player.pauseVideo()) : Promise.reject(NO_PLAYER_ERROR);
1456
1410
  }, []);
1457
- const setVolume = useCallback(newVolume => {
1411
+ const setVolume = useCallback(volume => {
1458
1412
  const {
1459
1413
  current: player
1460
1414
  } = playerRef;
1461
- return player !== null ? player.setVolume(newVolume) : Promise.reject(NO_PLAYER_ERROR);
1462
- }, []);
1415
+ const promise = player !== null && typeof player.setVolume !== 'undefined' ? Promise.resolve(player.setVolume(volume * 100)) : Promise.reject(NO_PLAYER_ERROR);
1416
+ if (customOnVolumeChange) {
1417
+ customOnVolumeChange(volume);
1418
+ }
1419
+ return promise;
1420
+ }, [customOnVolumeChange]);
1463
1421
  const mute = useCallback(() => {
1464
1422
  const {
1465
1423
  current: player
1466
1424
  } = playerRef;
1467
- return player !== null ? player.setVolume(0) : Promise.reject(NO_PLAYER_ERROR);
1468
- }, []);
1425
+ return (player !== null && typeof player.mute !== 'undefined' ? Promise.resolve(player.mute()) : Promise.reject(NO_PLAYER_ERROR)).then(() => setMuted(true));
1426
+ }, [setMuted]);
1469
1427
  const unmute = useCallback(() => {
1470
1428
  const {
1471
1429
  current: player
1472
1430
  } = playerRef;
1473
- return player !== null ? player.setVolume(1) : Promise.reject(NO_PLAYER_ERROR);
1431
+ return (player !== null && typeof player.unMute !== 'undefined' ? Promise.resolve(player.unMute()) : Promise.reject(NO_PLAYER_ERROR)).then(() => setMuted(false));
1474
1432
  }, []);
1475
1433
  const seek = useCallback(time => {
1476
1434
  const {
1477
1435
  current: player
1478
1436
  } = playerRef;
1479
- return player !== null ? player.setCurrentTime(time) : Promise.reject(NO_PLAYER_ERROR);
1437
+ return player !== null && typeof player.seekTo !== 'undefined' ? Promise.resolve(player.seekTo(time)) : Promise.reject(NO_PLAYER_ERROR);
1480
1438
  }, []);
1481
1439
  const setLoop = useCallback(loop => {
1482
1440
  const {
1483
1441
  current: player
1484
1442
  } = playerRef;
1485
- return player !== null ? player.setLoop(loop) : Promise.reject(NO_PLAYER_ERROR);
1443
+ return player !== null && typeof player.setLoop !== 'undefined' ? Promise.resolve(player.setLoop(loop)) : Promise.reject(NO_PLAYER_ERROR);
1486
1444
  }, []);
1487
- const destroyVideo = useCallback(() => {
1488
- const {
1489
- current: player
1490
- } = playerRef;
1491
-
1492
- if (player !== null) {
1493
- debug('Unload video');
1494
- player.unload();
1495
- }
1496
-
1497
- if (player !== null) {
1498
- debug('Unset video');
1445
+ const destroyPlayer = useCallback(() => {
1446
+ if (playerRef.current !== null) {
1447
+ debug('Unset player');
1499
1448
  playerRef.current = null;
1500
1449
  }
1501
1450
  }, []);
1451
+
1452
+ // Detect iframe switch and destroy player
1453
+
1502
1454
  useEffect(() => {
1503
1455
  const {
1504
1456
  current: currentPlayer
1505
1457
  } = playerRef;
1506
-
1507
1458
  if (playerElementRef.current !== elementRef.current && currentPlayer !== null) {
1508
1459
  debug('iFrame switched');
1509
- destroyVideo();
1460
+ destroyPlayer();
1510
1461
  }
1511
- }, [elementHasChanged]); // Create player
1462
+ }, [elementHasChanged]);
1512
1463
 
1464
+ // Create player
1513
1465
  useEffect(() => {
1514
1466
  const {
1515
- current: Player = null
1467
+ current: YT = null
1516
1468
  } = apiRef;
1517
1469
  const {
1518
1470
  current: currentPlayer = null
@@ -1520,157 +1472,79 @@ const useVimeoPlayer = function (id) {
1520
1472
  const {
1521
1473
  current: element = null
1522
1474
  } = elementRef;
1523
-
1524
1475
  if (!apiLoaded || videoId === null || element === null) {
1525
- destroyVideo();
1476
+ destroyPlayer();
1526
1477
  return;
1527
1478
  }
1528
-
1529
1479
  let player = currentPlayer;
1530
-
1531
- if (player === null) {
1532
- debug('Create player [ID: %s]', videoId);
1533
- player = new Player(element, {
1534
- id: videoId,
1535
- autoplay,
1536
- autopause,
1537
- byline,
1538
- controls,
1539
- muted: initialMuted,
1540
- background: !controls
1541
- });
1542
- player.ready().then(() => setReady(true)).catch(e => {
1543
- debug('ERROR: %o', e);
1544
- });
1480
+ if (player !== null && typeof player.loadVideoById !== 'undefined') {
1481
+ debug('Switch video [ID: %s]', videoId);
1482
+ player.loadVideoById(videoId);
1545
1483
  } else {
1546
- debug('Load video [ID: %s]', videoId);
1547
- player.loadVideo(videoId).catch(e => {
1548
- debug('ERROR: %o', e);
1549
- });
1550
- }
1551
-
1552
- playerRef.current = player;
1553
- playerElementRef.current = element;
1554
- }, [apiLoaded, videoId, elementHasChanged, setReady, destroyVideo, setLoaded]); // Bind player events
1555
-
1556
- useEffect(() => {
1557
- const {
1558
- current: player
1559
- } = playerRef;
1560
-
1561
- if (player === null) {
1562
- return () => {};
1563
- }
1564
-
1565
- let canceled = false;
1566
-
1567
- const onLoaded = () => {
1568
- Promise.all([player.getDuration(), player.getVideoWidth(), player.getVideoHeight(), player.getMuted()]).then(_ref => {
1569
- let [newDuration, newWidth, newHeight, newMuted] = _ref;
1570
-
1571
- if (canceled) {
1572
- return;
1484
+ debug('Create player [ID: %s]', videoId);
1485
+ const onReady = _ref => {
1486
+ let {
1487
+ target
1488
+ } = _ref;
1489
+ player = target;
1490
+ playerRef.current = target;
1491
+ setReady(true);
1492
+ const newDuration = target.getDuration();
1493
+ if (newDuration !== metadata.duration) {
1494
+ setMetadata({
1495
+ ...metadata,
1496
+ duration: newDuration
1497
+ });
1573
1498
  }
1574
-
1575
- const newMetadata = {
1576
- duration: newDuration,
1577
- width: newWidth,
1578
- height: newHeight
1499
+ debug('onReady [ID: %s]', videoId);
1500
+ };
1501
+ const onStateChange = _ref2 => {
1502
+ let {
1503
+ data: state
1504
+ } = _ref2;
1505
+ const newState = {
1506
+ playing: state === YT.PlayerState.PLAYING,
1507
+ paused: state === YT.PlayerState.PAUSED,
1508
+ ended: state === YT.PlayerState.ENDED,
1509
+ buffering: state === YT.PlayerState.BUFFERING
1579
1510
  };
1580
- setMetadata(newMetadata);
1581
-
1582
- if (newMuted) {
1583
- setVolumeState(0);
1511
+ setPlayState(newState);
1512
+ let stateLabel = null;
1513
+ if (newState.playing) {
1514
+ stateLabel = 'playing';
1515
+ } else if (newState.paused) {
1516
+ stateLabel = 'paused';
1517
+ } else if (newState.ended) {
1518
+ stateLabel = 'ended';
1519
+ } else if (newState.buffering) {
1520
+ stateLabel = 'buffering';
1521
+ } else if (state === -1) {
1522
+ stateLabel = 'not started';
1523
+ } else if (state === 0) {
1524
+ stateLabel = 'stopped';
1584
1525
  }
1585
-
1586
- setLoaded(true);
1587
- });
1588
- debug('onLoaded [ID: %s]', videoId);
1589
- };
1590
-
1591
- const onPlay = () => {
1592
- setPlayState({
1593
- playing: true,
1594
- paused: false,
1595
- ended: false,
1596
- buffering: false
1597
- });
1598
- debug('onPlay [ID: %s]', videoId);
1599
- player.getMuted().then(newMuted => {
1600
- if (!canceled && newMuted) {
1601
- setVolumeState(0);
1526
+ debug('onStateChange %s [ID: %s]', stateLabel, videoId);
1527
+ };
1528
+ player = new YT.Player(element, {
1529
+ videoId,
1530
+ playerVars: {
1531
+ controls,
1532
+ autoplay: autoplay ? 1 : 0,
1533
+ mute: initialMuted,
1534
+ playsinline: true,
1535
+ rel: 0,
1536
+ showinfo: 0,
1537
+ modestbranding: 1
1538
+ },
1539
+ events: {
1540
+ onReady,
1541
+ onStateChange
1602
1542
  }
1603
- }).catch(() => {});
1604
- };
1605
-
1606
- const onPause = () => {
1607
- setPlayState({
1608
- playing: false,
1609
- paused: true,
1610
- ended: false,
1611
- buffering: false
1612
1543
  });
1613
- debug('onPause [ID: %s]', videoId);
1614
- };
1615
-
1616
- const onVolumeChange = _ref2 => {
1617
- let {
1618
- volume: newVolume
1619
- } = _ref2;
1620
- setVolumeState(newVolume);
1621
- debug('onVolumeChange [ID: %s]', videoId);
1622
- };
1623
-
1624
- const onEnded = () => {
1625
- setPlayState({
1626
- playing: false,
1627
- paused: false,
1628
- ended: true,
1629
- buffering: false
1630
- });
1631
- debug('onEnded [ID: %s]', videoId);
1632
- };
1633
-
1634
- const onBufferStart = () => {
1635
- setPlayState({
1636
- playing: true,
1637
- paused: false,
1638
- ended: false,
1639
- buffering: true
1640
- });
1641
- debug('onBufferStart [ID: %s]', videoId);
1642
- };
1643
-
1644
- const onBufferEnded = () => {
1645
- setPlayState({
1646
- playing: true,
1647
- paused: false,
1648
- ended: false,
1649
- buffering: false
1650
- });
1651
- debug('onBufferStart [ID: %s]', videoId);
1652
- };
1653
-
1654
- debug('Bind events [ID: %s]', videoId);
1655
- player.on('loaded', onLoaded);
1656
- player.on('play', onPlay);
1657
- player.on('pause', onPause);
1658
- player.on('volumechange', onVolumeChange);
1659
- player.on('ended', onEnded);
1660
- player.on('bufferstart', onBufferStart);
1661
- player.on('bufferend', onBufferEnded);
1662
- return () => {
1663
- canceled = true;
1664
- debug('Unbind events [ID: %s]', videoId);
1665
- player.off('loaded', onLoaded);
1666
- player.off('play', onPlay);
1667
- player.off('pause', onPause);
1668
- player.off('volumechange', onVolumeChange);
1669
- player.off('ended', onEnded);
1670
- player.off('bufferstart', onBufferStart);
1671
- player.off('bufferend', onBufferEnded);
1672
- };
1673
- }, [videoId, playerRef.current, setPlayState, setMetadata, setVolumeState, setLoaded]);
1544
+ }
1545
+ playerRef.current = player;
1546
+ playerElementRef.current = element;
1547
+ }, [apiLoaded, videoId, elementHasChanged, setPlayState, setReady, setMetadata, destroyPlayer]);
1674
1548
  const {
1675
1549
  playing
1676
1550
  } = playState;
@@ -1694,13 +1568,12 @@ const useVimeoPlayer = function (id) {
1694
1568
  setLoop,
1695
1569
  ready,
1696
1570
  currentTime,
1697
- loaded,
1698
- muted: volume === 0,
1699
- volume,
1571
+ muted,
1572
+ loaded: ready,
1700
1573
  ...metadata,
1701
1574
  ...playState
1702
1575
  };
1703
- };
1576
+ }
1704
1577
 
1705
1578
  function useVideoPlayer(params) {
1706
1579
  const {
@@ -1720,7 +1593,6 @@ function useVideoPlayer(params) {
1720
1593
  const vimeoPlayer = useVimeoPlayer(service === 'vimeo' ? videoId || url : null, params);
1721
1594
  const nativePlayer = useNativeVideoPlayer(url, params);
1722
1595
  let player = null;
1723
-
1724
1596
  if (service === 'dailymotion') {
1725
1597
  player = dailymotionPlayer;
1726
1598
  } else if (service === 'youtube') {
@@ -1730,7 +1602,6 @@ function useVideoPlayer(params) {
1730
1602
  } else {
1731
1603
  player = nativePlayer;
1732
1604
  }
1733
-
1734
1605
  const {
1735
1606
  playing = false,
1736
1607
  paused = false,
@@ -1770,7 +1641,6 @@ function useVideoPlayer(params) {
1770
1641
  }, [ended, customOnEnd]);
1771
1642
  useEffect(() => {
1772
1643
  const hasMetadata = metaWidth !== null || metaHeight !== null || metaDuration !== null;
1773
-
1774
1644
  if (hasMetadata && customOnMetadataChange !== null) {
1775
1645
  customOnMetadataChange({
1776
1646
  width: metaWidth,
@@ -1786,10 +1656,8 @@ const getWindowScroll = () => ({
1786
1656
  x: typeof window !== 'undefined' ? window.scrollX || 0 : 0,
1787
1657
  y: typeof window !== 'undefined' ? window.scrollY || 0 : 0
1788
1658
  });
1789
-
1790
1659
  const currentScroll = getWindowScroll();
1791
-
1792
- const useWindowScroll = function () {
1660
+ function useWindowScroll() {
1793
1661
  let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1794
1662
  const {
1795
1663
  onChange = null
@@ -1797,19 +1665,16 @@ const useWindowScroll = function () {
1797
1665
  const [scroll, setScroll] = useState(currentScroll);
1798
1666
  const updateScroll = useCallback(() => {
1799
1667
  const newScroll = getWindowScroll();
1800
-
1801
1668
  if (currentScroll.x !== newScroll.x || currentScroll.y !== newScroll.y) {
1802
1669
  currentScroll.x = newScroll.x;
1803
1670
  currentScroll.y = newScroll.y;
1804
1671
  setScroll(newScroll);
1805
1672
  return newScroll;
1806
1673
  }
1807
-
1808
1674
  return null;
1809
1675
  }, [setScroll]);
1810
1676
  const onScroll = useCallback(() => {
1811
1677
  const newScroll = updateScroll();
1812
-
1813
1678
  if (newScroll !== null && onChange !== null) {
1814
1679
  onChange(newScroll);
1815
1680
  }
@@ -1819,14 +1684,13 @@ const useWindowScroll = function () {
1819
1684
  onScroll();
1820
1685
  }, []);
1821
1686
  return scroll;
1822
- };
1687
+ }
1823
1688
 
1824
1689
  const getWindowSize = () => ({
1825
1690
  width: typeof window !== 'undefined' ? window.innerWidth || 0 : 0,
1826
1691
  height: typeof window !== 'undefined' ? window.innerHeight || 0 : 0
1827
1692
  });
1828
1693
  let currentSize = getWindowSize();
1829
-
1830
1694
  function useWindowSize() {
1831
1695
  let {
1832
1696
  onChange = null
@@ -1834,18 +1698,15 @@ function useWindowSize() {
1834
1698
  const [size, setSize] = useState(currentSize);
1835
1699
  const updateSize = useCallback(() => {
1836
1700
  const newSize = getWindowSize();
1837
-
1838
1701
  if (currentSize.width !== newSize.width || currentSize.height !== newSize.height) {
1839
1702
  currentSize = newSize;
1840
1703
  setSize(newSize);
1841
1704
  return newSize;
1842
1705
  }
1843
-
1844
1706
  return null;
1845
1707
  }, [setSize]);
1846
1708
  const onResize = useCallback(() => {
1847
1709
  const newSize = updateSize();
1848
-
1849
1710
  if (newSize !== null && onChange !== null) {
1850
1711
  onChange(newSize);
1851
1712
  }