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