@applicaster/zapp-react-dom-app 13.0.0-alpha.2635505531 → 13.0.0-alpha.2833001702
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/App/InteractionManager/index.tsx +182 -120
- package/App/Loader/__tests__/__snapshots__/loadDomPlugins.test.js.snap +6 -6
- package/App/Loader/loadLocale.js +2 -2
- package/App/Loader/utils/platform.js +46 -26
- package/Polyfills/Storage/__tests__/__snapshots__/storage.test.js.snap +4 -4
- package/index.js +0 -7
- package/package.json +22 -13
- package/App/Router/index.js +0 -17
- package/App/Splash/Spinner.js +0 -30
- package/App/Splash/spinner-styles.css +0 -81
|
@@ -23,8 +23,6 @@ import {
|
|
|
23
23
|
|
|
24
24
|
import { showConfirmationDialog } from "@applicaster/zapp-react-native-utils/alertUtils";
|
|
25
25
|
|
|
26
|
-
import { withUseSeek } from "@applicaster/zapp-react-native-utils/reactHooks/player";
|
|
27
|
-
|
|
28
26
|
import {
|
|
29
27
|
DISPLAY_STATES,
|
|
30
28
|
DisplayStateContext,
|
|
@@ -33,7 +31,10 @@ import {
|
|
|
33
31
|
import { PlayerContentContext } from "@applicaster/zapp-react-dom-ui-components/Contexts";
|
|
34
32
|
|
|
35
33
|
import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator";
|
|
36
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
getXray,
|
|
36
|
+
createLogger,
|
|
37
|
+
} from "@applicaster/zapp-react-native-utils/logger";
|
|
37
38
|
|
|
38
39
|
import {
|
|
39
40
|
confirmationDialogStore,
|
|
@@ -48,10 +49,16 @@ import {
|
|
|
48
49
|
|
|
49
50
|
import { OnScreenKeyboard } from "@applicaster/zapp-react-dom-ui-components/Components/OnScreenKeyboard";
|
|
50
51
|
import { KeyboardLongPressManager } from "@applicaster/zapp-react-dom-ui-components/Utils/KeyboardLongPressManager";
|
|
52
|
+
import { KeyInputHandler } from "@applicaster/zapp-react-native-utils/appUtils/keyInputHandler/KeyInputHandler";
|
|
51
53
|
|
|
52
54
|
const { withXray } = getXray();
|
|
53
55
|
const globalAny: any = global;
|
|
54
56
|
|
|
57
|
+
const { log_debug, log_warning } = createLogger({
|
|
58
|
+
category: "InteractionManager",
|
|
59
|
+
subsystem: "zapp-react-dom-app",
|
|
60
|
+
});
|
|
61
|
+
|
|
55
62
|
const shouldUseOnScreenKeyboard = () =>
|
|
56
63
|
isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
|
|
57
64
|
|
|
@@ -62,14 +69,6 @@ type Props = {
|
|
|
62
69
|
navigator: QuickBrickAppNavigator;
|
|
63
70
|
rivers: {};
|
|
64
71
|
xray: XRayContext;
|
|
65
|
-
seekMethods: {
|
|
66
|
-
onRewindPress: () => void;
|
|
67
|
-
onRewindLongPress: () => void;
|
|
68
|
-
onForwardPress: () => void;
|
|
69
|
-
onForwardLongPress: () => void;
|
|
70
|
-
onRewindPressOut: () => void;
|
|
71
|
-
onForwardPressOut: () => void;
|
|
72
|
-
};
|
|
73
72
|
confirmDialog: typeof confirmationDialogStore;
|
|
74
73
|
};
|
|
75
74
|
|
|
@@ -149,13 +148,16 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
149
148
|
this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
|
|
150
149
|
this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
|
|
151
150
|
|
|
151
|
+
this.handlePhysicalKeyboardDismiss =
|
|
152
|
+
this.handlePhysicalKeyboardDismiss.bind(this);
|
|
153
|
+
|
|
152
154
|
this.confirmDialog.setConfirmAction(this.performExit);
|
|
153
155
|
this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
|
|
154
156
|
this.longPressDetector = new KeyboardLongPressManager();
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
componentDidMount() {
|
|
158
|
-
window.addEventListener("keydown", this.onKeyDownListener);
|
|
160
|
+
window.addEventListener("keydown", this.onKeyDownListener, true);
|
|
159
161
|
window.addEventListener("keyup", this.onKeyUp);
|
|
160
162
|
window.addEventListener("mousemove", this.onMouseMoveListener);
|
|
161
163
|
|
|
@@ -190,6 +192,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
190
192
|
"onLongPressRelease",
|
|
191
193
|
this.handleLongPressRelease.bind(this)
|
|
192
194
|
);
|
|
195
|
+
|
|
196
|
+
document.addEventListener(
|
|
197
|
+
"keyboardDismissedByPhysicalKeypress",
|
|
198
|
+
this.handlePhysicalKeyboardDismiss
|
|
199
|
+
);
|
|
193
200
|
}
|
|
194
201
|
|
|
195
202
|
componentWillUnmount() {
|
|
@@ -218,6 +225,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
218
225
|
"onLongPressRelease",
|
|
219
226
|
this.handleLongPressRelease
|
|
220
227
|
);
|
|
228
|
+
|
|
229
|
+
document.removeEventListener(
|
|
230
|
+
"keyboardDismissedByPhysicalKeypress",
|
|
231
|
+
this.handlePhysicalKeyboardDismiss
|
|
232
|
+
);
|
|
221
233
|
}
|
|
222
234
|
|
|
223
235
|
performExit() {
|
|
@@ -279,8 +291,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
279
291
|
this.handleWebOsBack();
|
|
280
292
|
}
|
|
281
293
|
} catch (e) {
|
|
282
|
-
|
|
283
|
-
console.warn("Failed to execute platformBack", e);
|
|
294
|
+
log_warning("Failed to execute platformBack", e);
|
|
284
295
|
}
|
|
285
296
|
}
|
|
286
297
|
|
|
@@ -344,36 +355,139 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
344
355
|
}
|
|
345
356
|
|
|
346
357
|
onKeyUp(event: KeyboardEvent) {
|
|
358
|
+
const { setDisplayState } = this.props;
|
|
359
|
+
|
|
347
360
|
if (this.keySupportsLongPress(event)) {
|
|
348
361
|
this.longPressDetector.endKeyPressMonitoring(event.code);
|
|
349
362
|
}
|
|
363
|
+
|
|
364
|
+
if (
|
|
365
|
+
keyCode(event).matches(KEYS.Enter) ||
|
|
366
|
+
(__DEV__ && keyCode(event).matches(KEYS.X))
|
|
367
|
+
) {
|
|
368
|
+
focusManager.pressOut();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (
|
|
372
|
+
keyCode(event).matches(KEYS.Forward) ||
|
|
373
|
+
(__DEV__ && keyCode(event).matches(KEYS.C))
|
|
374
|
+
) {
|
|
375
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
376
|
+
KeyInputHandler.getInstance().onForwardPressOut();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (
|
|
380
|
+
keyCode(event).matches(KEYS.Rewind) ||
|
|
381
|
+
(__DEV__ && keyCode(event).matches(KEYS.Z))
|
|
382
|
+
) {
|
|
383
|
+
setDisplayState(DISPLAY_STATES.HUD);
|
|
384
|
+
KeyInputHandler.getInstance().onRewindPressOut();
|
|
385
|
+
}
|
|
350
386
|
}
|
|
351
387
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
388
|
+
/**
|
|
389
|
+
When pressing escape or the Native "Back" button:
|
|
390
|
+
if on the transport controls: we show the player
|
|
391
|
+
if on the player : we show the UI
|
|
392
|
+
if on the UI : we exit the app
|
|
393
|
+
note: backspace affects the keyboard input, so it behaves differently
|
|
394
|
+
*/
|
|
395
|
+
onBackPress(event) {
|
|
355
396
|
const { displayState, setDisplayState, navigator } = this.props;
|
|
397
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
356
398
|
const { isKeyboardVisible } = this.state;
|
|
357
399
|
|
|
358
|
-
|
|
400
|
+
log_debug("onBackPress", {
|
|
401
|
+
eventCode: event.code,
|
|
402
|
+
displayState,
|
|
403
|
+
isDialogVisible,
|
|
404
|
+
isKeyboardVisible,
|
|
405
|
+
});
|
|
359
406
|
|
|
360
407
|
if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
|
|
361
|
-
|
|
362
|
-
this.handleKeyboardDismiss();
|
|
363
|
-
}
|
|
364
|
-
|
|
408
|
+
this.handleKeyboardDismiss();
|
|
365
409
|
event.preventDefault();
|
|
366
410
|
event.stopPropagation();
|
|
367
411
|
|
|
368
412
|
return;
|
|
369
413
|
}
|
|
370
414
|
|
|
415
|
+
switch (displayState) {
|
|
416
|
+
case DISPLAY_STATES.DEFAULT:
|
|
417
|
+
case DISPLAY_STATES.PLAYER:
|
|
418
|
+
if (isDialogVisible) {
|
|
419
|
+
this.onConfirmDialogClose();
|
|
420
|
+
} else if (navigator.canGoBack()) {
|
|
421
|
+
navigator.goBack();
|
|
422
|
+
} else if (this.isHomeScreen()) {
|
|
423
|
+
this.platformBack();
|
|
424
|
+
} else if (navigator.currentRoute.includes("hook")) {
|
|
425
|
+
// If code reaches this block navigator cant go back, it is not home,
|
|
426
|
+
// and this is a login plugin that was pushed on top of the home
|
|
427
|
+
// Treat it like a home screen and run platformBack()
|
|
428
|
+
const entryData = navigator?.data?.entry;
|
|
429
|
+
const isHookInHomescreen = entryData?.payload?.home;
|
|
430
|
+
|
|
431
|
+
const isHookFlowBlocker =
|
|
432
|
+
typeof entryData?.hookPlugin?.module?.isFlowBlocker === "function"
|
|
433
|
+
? entryData?.hookPlugin?.module?.isFlowBlocker()
|
|
434
|
+
: entryData?.hookPlugin?.module?.isFlowBlocker;
|
|
435
|
+
|
|
436
|
+
if (isHookInHomescreen && isHookFlowBlocker) {
|
|
437
|
+
this.platformBack();
|
|
438
|
+
} else {
|
|
439
|
+
navigator.goBack(false, true);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
this.goToHome();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
break;
|
|
446
|
+
case DISPLAY_STATES.HUD:
|
|
447
|
+
// IF transport controls are open, close them instead of closing player
|
|
448
|
+
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
449
|
+
break;
|
|
450
|
+
default:
|
|
451
|
+
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
onBackspacePress(event) {
|
|
457
|
+
const isInputFocused =
|
|
458
|
+
document.activeElement instanceof HTMLInputElement ||
|
|
459
|
+
document.activeElement instanceof HTMLTextAreaElement;
|
|
460
|
+
|
|
461
|
+
// Don't handle backspace if input is focused
|
|
462
|
+
if (isInputFocused) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
this.onBackPress(event);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
onKeyDown(event) {
|
|
470
|
+
const { displayState, setDisplayState, navigator } = this.props;
|
|
471
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
472
|
+
|
|
473
|
+
if (keyCode(event).matches("Backspace")) {
|
|
474
|
+
this.onBackspacePress(event);
|
|
475
|
+
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (keyCode(event).matchesAny(KEYS.Back, KEYS.Escape, KEYS.EscapeDevice)) {
|
|
480
|
+
this.onBackPress(event);
|
|
481
|
+
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
371
485
|
if (this.keySupportsLongPress(event)) {
|
|
372
486
|
this.longPressDetector.monitorKeyPress(event.code, event);
|
|
373
487
|
}
|
|
374
488
|
|
|
375
|
-
//
|
|
376
|
-
if (event.repeat) return;
|
|
489
|
+
// Only handle repeat events for arrow keys
|
|
490
|
+
if (event.repeat && !keyCode(event).matchesAny(...ARROW_KEYS)) return;
|
|
377
491
|
|
|
378
492
|
/**
|
|
379
493
|
When the player is displayed, we listen to Native Play / Pause / Stop
|
|
@@ -414,83 +528,33 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
414
528
|
|
|
415
529
|
if (
|
|
416
530
|
keyCode(event).matches(KEYS.Forward) ||
|
|
417
|
-
keyCode(event).matches(KEYS.C)
|
|
531
|
+
(__DEV__ && keyCode(event).matches(KEYS.C))
|
|
418
532
|
) {
|
|
419
533
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
420
|
-
|
|
534
|
+
KeyInputHandler.getInstance().onForwardPress();
|
|
421
535
|
|
|
422
536
|
return;
|
|
423
537
|
}
|
|
424
538
|
|
|
425
539
|
if (
|
|
426
540
|
keyCode(event).matches(KEYS.Rewind) ||
|
|
427
|
-
keyCode(event).matches(KEYS.Z)
|
|
541
|
+
(__DEV__ && keyCode(event).matches(KEYS.Z))
|
|
428
542
|
) {
|
|
429
543
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
430
|
-
|
|
544
|
+
KeyInputHandler.getInstance().onRewindPress();
|
|
431
545
|
|
|
432
546
|
return;
|
|
433
547
|
}
|
|
434
548
|
}
|
|
435
549
|
|
|
436
|
-
/**
|
|
437
|
-
When pressing backspace or the Native "Back" button:
|
|
438
|
-
if on the transport controls: we show the player
|
|
439
|
-
if on the player : we show the UI
|
|
440
|
-
if on the UI : we exit the app
|
|
441
|
-
*/
|
|
442
|
-
|
|
443
550
|
if (
|
|
444
|
-
keyCode(event).
|
|
445
|
-
|
|
446
|
-
KEYS.Escape,
|
|
447
|
-
KEYS.EscapeDevice,
|
|
448
|
-
KEYS.Backspace
|
|
449
|
-
)
|
|
551
|
+
keyCode(event).matches(KEYS.Enter) ||
|
|
552
|
+
(__DEV__ && keyCode(event).matches(KEYS.X))
|
|
450
553
|
) {
|
|
451
|
-
switch (displayState) {
|
|
452
|
-
case DISPLAY_STATES.DEFAULT:
|
|
453
|
-
case DISPLAY_STATES.PLAYER:
|
|
454
|
-
if (isDialogVisible) {
|
|
455
|
-
this.onConfirmDialogClose();
|
|
456
|
-
} else if (navigator.canGoBack()) {
|
|
457
|
-
navigator.goBack();
|
|
458
|
-
} else if (this.isHomeScreen()) {
|
|
459
|
-
this.platformBack();
|
|
460
|
-
} else if (navigator.currentRoute.includes("hook")) {
|
|
461
|
-
// If code reaches this block navigator cant go back, it is not home,
|
|
462
|
-
// and this is a login plugin that was pushed on top of the home
|
|
463
|
-
// Treat it like a home screen and run platformBack()
|
|
464
|
-
const entryData = navigator?.data?.entry;
|
|
465
|
-
const isHookInHomescreen = entryData?.payload?.home;
|
|
466
|
-
|
|
467
|
-
const isHookFlowBlocker =
|
|
468
|
-
entryData?.hookPlugin?.module?.isFlowBlocker();
|
|
469
|
-
|
|
470
|
-
if (isHookInHomescreen && isHookFlowBlocker) {
|
|
471
|
-
this.platformBack();
|
|
472
|
-
} else {
|
|
473
|
-
navigator.goBack(false, true);
|
|
474
|
-
}
|
|
475
|
-
} else {
|
|
476
|
-
this.goToHome();
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
break;
|
|
480
|
-
case DISPLAY_STATES.HUD:
|
|
481
|
-
// IF transport controls are open, close them instead of closing player
|
|
482
|
-
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
483
|
-
break;
|
|
484
|
-
default:
|
|
485
|
-
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
486
|
-
break;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
if (keyCode(event).matches(KEYS.Enter) || keyCode(event).matches(KEYS.X)) {
|
|
491
554
|
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
492
555
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
493
556
|
} else {
|
|
557
|
+
focusManager.pressIn();
|
|
494
558
|
focusManager.press();
|
|
495
559
|
}
|
|
496
560
|
|
|
@@ -507,10 +571,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
507
571
|
this.platformBack();
|
|
508
572
|
}
|
|
509
573
|
|
|
510
|
-
if (
|
|
511
|
-
keyCode(event).matchesAny(...ARROW_KEYS) &&
|
|
512
|
-
!this.state.isKeyboardVisible
|
|
513
|
-
) {
|
|
574
|
+
if (keyCode(event).matchesAny(...ARROW_KEYS)) {
|
|
514
575
|
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
515
576
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
516
577
|
}
|
|
@@ -523,12 +584,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
523
584
|
focusManager.moveFocus(direction);
|
|
524
585
|
}
|
|
525
586
|
|
|
526
|
-
if (!isDialogVisible) {
|
|
527
|
-
// run focus recovery on user interaction attempt
|
|
528
|
-
// probably we failed to set initial focus for some reason
|
|
529
|
-
focusManager.recoverFocus();
|
|
530
|
-
}
|
|
531
|
-
|
|
532
587
|
if (
|
|
533
588
|
displayState === DISPLAY_STATES.PLAYER ||
|
|
534
589
|
displayState === DISPLAY_STATES.HUD
|
|
@@ -604,6 +659,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
604
659
|
|
|
605
660
|
if (
|
|
606
661
|
(target.tagName === "INPUT" && target.type === "text") ||
|
|
662
|
+
(target.tagName === "INPUT" && target.type === "password") ||
|
|
607
663
|
target.tagName === "TEXTAREA"
|
|
608
664
|
) {
|
|
609
665
|
this.setState({
|
|
@@ -632,7 +688,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
632
688
|
}
|
|
633
689
|
}
|
|
634
690
|
|
|
635
|
-
handleKeyboardDismiss
|
|
691
|
+
handleKeyboardDismiss() {
|
|
636
692
|
this.isDismissing = true;
|
|
637
693
|
|
|
638
694
|
this.setState(
|
|
@@ -643,9 +699,10 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
643
699
|
},
|
|
644
700
|
() => {
|
|
645
701
|
this.isDismissing = false;
|
|
702
|
+
focusManager.recoverFocus();
|
|
646
703
|
}
|
|
647
704
|
);
|
|
648
|
-
}
|
|
705
|
+
}
|
|
649
706
|
|
|
650
707
|
handleKeyboardInput = (value: string) => {
|
|
651
708
|
const { activeInputRef } = this.state;
|
|
@@ -702,26 +759,13 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
702
759
|
}, SEQUENCE_ENTRY_TIME);
|
|
703
760
|
}
|
|
704
761
|
|
|
762
|
+
// TODO: Delete it on next PR if not needed
|
|
705
763
|
private handleLongPress = (event: CustomEvent) => {
|
|
706
764
|
const { keyCode } = event.detail;
|
|
707
|
-
const { displayState } = this.props;
|
|
708
|
-
const playerState = displayState === DISPLAY_STATES.PLAYER;
|
|
709
|
-
const hudState = displayState === DISPLAY_STATES.HUD;
|
|
710
|
-
const playbackState = playerState || hudState;
|
|
711
765
|
this.longPressActive = true;
|
|
712
766
|
this.cancelHudTimeout();
|
|
713
767
|
|
|
714
768
|
switch (keyCode) {
|
|
715
|
-
case KEYS.Forward.code:
|
|
716
|
-
case KEYS.C.code:
|
|
717
|
-
playbackState && this.props.seekMethods.onForwardLongPress();
|
|
718
|
-
break;
|
|
719
|
-
|
|
720
|
-
case KEYS.Rewind.code:
|
|
721
|
-
case KEYS.Z.code:
|
|
722
|
-
playbackState && this.props.seekMethods.onRewindLongPress();
|
|
723
|
-
break;
|
|
724
|
-
|
|
725
769
|
case KEYS.Enter.code:
|
|
726
770
|
case KEYS.X.code:
|
|
727
771
|
focusManager.longPress();
|
|
@@ -729,26 +773,16 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
729
773
|
}
|
|
730
774
|
};
|
|
731
775
|
|
|
776
|
+
// TODO: Delete it on next PR if not needed
|
|
732
777
|
private handleLongPressRelease = (event: CustomEvent) => {
|
|
733
778
|
const { keyCode } = event.detail;
|
|
734
779
|
this.longPressActive = false;
|
|
735
780
|
this.resetHudTimeout();
|
|
736
|
-
// debugger;
|
|
737
781
|
|
|
738
782
|
switch (keyCode) {
|
|
739
|
-
case KEYS.Forward.code:
|
|
740
|
-
case KEYS.C.code:
|
|
741
|
-
this.props.seekMethods.onForwardPressOut();
|
|
742
|
-
break;
|
|
743
|
-
|
|
744
|
-
case KEYS.Rewind.code:
|
|
745
|
-
case KEYS.Z.code:
|
|
746
|
-
this.props.seekMethods.onRewindPressOut();
|
|
747
|
-
break;
|
|
748
|
-
|
|
749
783
|
case KEYS.Enter.code:
|
|
750
784
|
case KEYS.X.code:
|
|
751
|
-
focusManager.pressOut();
|
|
785
|
+
// focusManager.pressOut();
|
|
752
786
|
break;
|
|
753
787
|
}
|
|
754
788
|
};
|
|
@@ -764,6 +798,35 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
764
798
|
].includes(event.code);
|
|
765
799
|
}
|
|
766
800
|
|
|
801
|
+
handlePhysicalKeyboardDismiss(event: CustomEvent) {
|
|
802
|
+
const { value, position, inputElement } = event.detail;
|
|
803
|
+
|
|
804
|
+
this.isDismissing = true;
|
|
805
|
+
|
|
806
|
+
this.setState(
|
|
807
|
+
{
|
|
808
|
+
isKeyboardVisible: false,
|
|
809
|
+
keyboardInput: "",
|
|
810
|
+
activeInputRef: null,
|
|
811
|
+
},
|
|
812
|
+
() => {
|
|
813
|
+
if (inputElement) {
|
|
814
|
+
inputElement.value = value;
|
|
815
|
+
inputElement.focus();
|
|
816
|
+
inputElement.setSelectionRange(position, position);
|
|
817
|
+
|
|
818
|
+
const keyboardEvent = new CustomEvent("keyboardUpdate", {
|
|
819
|
+
detail: { value },
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
document.dispatchEvent(keyboardEvent);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
this.isDismissing = false;
|
|
826
|
+
}
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
|
|
767
830
|
render() {
|
|
768
831
|
return (
|
|
769
832
|
(shouldUseOnScreenKeyboard() && this.state.isKeyboardVisible && (
|
|
@@ -780,7 +843,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
780
843
|
|
|
781
844
|
export const InteractionManager = R.compose(
|
|
782
845
|
withNavigator,
|
|
783
|
-
withUseSeek,
|
|
784
846
|
withXray,
|
|
785
847
|
connectToStore(R.pick(["rivers"])),
|
|
786
848
|
PlayerContentContext.withConsumer,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`loadDomPlugins when there are plugins requiring to write to the dom skips plugins without init method 1`] = `
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
[
|
|
5
|
+
[
|
|
6
6
|
"could not initialize plugin Plugin with Dom node & no init method - it doesn't have an init method",
|
|
7
|
-
|
|
8
|
-
"plugin":
|
|
9
|
-
"configuration":
|
|
7
|
+
{
|
|
8
|
+
"plugin": {
|
|
9
|
+
"configuration": {
|
|
10
10
|
"foo": "bar",
|
|
11
11
|
},
|
|
12
|
-
"module":
|
|
12
|
+
"module": {
|
|
13
13
|
"requiresAppendingDomNode": true,
|
|
14
14
|
},
|
|
15
15
|
"name": "Plugin with Dom node & no init method",
|
package/App/Loader/loadLocale.js
CHANGED
|
@@ -4,8 +4,8 @@ import { QuickBrickCommunicationModule } from "../../Polyfills/QuickBrickCommuni
|
|
|
4
4
|
import { loadLocaleImpl, getLanguageCode } from "./utils";
|
|
5
5
|
|
|
6
6
|
type Locale = {
|
|
7
|
-
language: string
|
|
8
|
-
country: string
|
|
7
|
+
language: string;
|
|
8
|
+
country: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
async function getBrowserLocale() {
|
|
@@ -11,11 +11,28 @@ import {
|
|
|
11
11
|
PLATFORMS,
|
|
12
12
|
} from "./const";
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {"tv" | "web" | "other"} DeviceType
|
|
16
|
+
* @typedef {"samsung_tv" | "lg_tv" | unknown} CustomPlatformTypes
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves the user agent string from the browser or global navigator.
|
|
21
|
+
* @returns {string} The user agent string.
|
|
22
|
+
*/
|
|
14
23
|
export const getUserAgent = () =>
|
|
15
24
|
window?.navigator?.userAgent || global?.navigator?.userAgent;
|
|
16
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Checks if the device is HD (1280 width).
|
|
28
|
+
* @returns {boolean} True if the device is HD, false otherwise.
|
|
29
|
+
*/
|
|
17
30
|
export const isHD = () => window.innerWidth === 1280;
|
|
18
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Checks if the platform is LG.
|
|
34
|
+
* @returns {boolean} True if the platform is LG, false otherwise.
|
|
35
|
+
*/
|
|
19
36
|
export const isLgPlatform = () => {
|
|
20
37
|
const userAgent = getUserAgent();
|
|
21
38
|
|
|
@@ -23,10 +40,13 @@ export const isLgPlatform = () => {
|
|
|
23
40
|
return false;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
|
-
// Note: LG uses the number 0 in their userAgent, possibly because of Palm WebOS
|
|
27
43
|
return hasWebOS || userAgent.includes(PLATFORMS.webos);
|
|
28
44
|
};
|
|
29
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the platform is Samsung.
|
|
48
|
+
* @returns {boolean} True if the platform is Samsung, false otherwise.
|
|
49
|
+
*/
|
|
30
50
|
export const isSamsungPlatform = () => {
|
|
31
51
|
const userAgent = getUserAgent();
|
|
32
52
|
|
|
@@ -42,42 +62,39 @@ export const isSamsungPlatform = () => {
|
|
|
42
62
|
};
|
|
43
63
|
|
|
44
64
|
/**
|
|
45
|
-
* Checks if
|
|
46
|
-
*
|
|
47
|
-
* Use this method when you need to identify the platform on runtime
|
|
48
|
-
* before the VIZIO Companion Library has loaded
|
|
65
|
+
* Checks if the platform is Vizio by using the user agent string.
|
|
66
|
+
* @returns {boolean} True if the platform is Vizio, false otherwise.
|
|
49
67
|
*/
|
|
50
68
|
export const isVizioPlatform = () => {
|
|
51
69
|
const userAgent = getUserAgent();
|
|
52
70
|
|
|
53
|
-
|
|
71
|
+
return (
|
|
54
72
|
userAgent.includes(PLATFORMS.vizio) ||
|
|
55
73
|
userAgent.includes(PLATFORMS.smartcast) ||
|
|
56
|
-
userAgent.includes(PLATFORMS.conjure)
|
|
57
|
-
|
|
58
|
-
return isVizioAgent;
|
|
74
|
+
userAgent.includes(PLATFORMS.conjure)
|
|
75
|
+
);
|
|
59
76
|
};
|
|
60
77
|
|
|
61
78
|
/**
|
|
62
|
-
* Checks if
|
|
63
|
-
*
|
|
64
|
-
* because it mainly checks whether we have access to apis, which may not be available yet
|
|
79
|
+
* Checks if the Vizio APIs are available.
|
|
80
|
+
* @returns {boolean} True if the Vizio APIs are available, false otherwise.
|
|
65
81
|
*/
|
|
66
82
|
export const hasVizioAPIs = () => {
|
|
67
|
-
|
|
83
|
+
return (
|
|
68
84
|
typeof window.VIZIO !== "undefined" &&
|
|
69
|
-
window?.applicaster?.vizioLibraryDidLoad
|
|
70
|
-
|
|
71
|
-
return hasAPIs;
|
|
85
|
+
window?.applicaster?.vizioLibraryDidLoad
|
|
86
|
+
);
|
|
72
87
|
};
|
|
73
88
|
|
|
74
89
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* @returns {"tv" | "web" | "other"} value
|
|
90
|
+
* Determines the device type based on the platform.
|
|
91
|
+
* @returns {DeviceType} The device type ("tv", "web", or "other").
|
|
78
92
|
*/
|
|
79
93
|
export const getDeviceType = () => {
|
|
80
|
-
|
|
94
|
+
/** @type {CustomPlatformTypes} */
|
|
95
|
+
const platformOS = Platform.OS;
|
|
96
|
+
|
|
97
|
+
switch (platformOS) {
|
|
81
98
|
case "samsung_tv":
|
|
82
99
|
return isSamsungPlatform() ? "tv" : "web";
|
|
83
100
|
case "lg_tv":
|
|
@@ -88,14 +105,15 @@ export const getDeviceType = () => {
|
|
|
88
105
|
};
|
|
89
106
|
|
|
90
107
|
/**
|
|
91
|
-
*
|
|
92
|
-
* @param {string} key - key
|
|
108
|
+
* Renames keys based on a predefined map.
|
|
109
|
+
* @param {string} key - The key to rename.
|
|
110
|
+
* @returns {string} The renamed key.
|
|
93
111
|
*/
|
|
94
112
|
export const renameKeys = (key) => desiredKeysMap?.[key] || key;
|
|
95
113
|
|
|
96
114
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
115
|
+
* Retrieves the connection info from WebOS.
|
|
116
|
+
* @returns {Promise<{networkType: string} | null>} A promise that resolves with the connection info or null.
|
|
99
117
|
*/
|
|
100
118
|
export const getWebOSConnectionInfo = () => {
|
|
101
119
|
return new Promise((resolve, reject) => {
|
|
@@ -108,7 +126,6 @@ export const getWebOSConnectionInfo = () => {
|
|
|
108
126
|
webOS.service.request("luna://com.palm.connectionmanager", {
|
|
109
127
|
method: "getStatus",
|
|
110
128
|
parameters: { subscribe: false },
|
|
111
|
-
|
|
112
129
|
onSuccess: (args) => {
|
|
113
130
|
const types = Object.keys(args)
|
|
114
131
|
.filter((key) => args[key].state === "connected")
|
|
@@ -116,7 +133,6 @@ export const getWebOSConnectionInfo = () => {
|
|
|
116
133
|
|
|
117
134
|
resolve({ networkType: types });
|
|
118
135
|
},
|
|
119
|
-
|
|
120
136
|
onFailure: (error) => {
|
|
121
137
|
console.error(
|
|
122
138
|
"getWebOSConnectionInfo: There was an error getting connection info",
|
|
@@ -129,6 +145,10 @@ export const getWebOSConnectionInfo = () => {
|
|
|
129
145
|
});
|
|
130
146
|
};
|
|
131
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Retrieves the connection info from Tizen.
|
|
150
|
+
* @returns {Promise<{networkType: string} | null>} A promise that resolves with the connection info or null.
|
|
151
|
+
*/
|
|
132
152
|
export const getTizenConnectionInfo = () => {
|
|
133
153
|
return new Promise((resolve, reject) => {
|
|
134
154
|
if (!isSamsungPlatform) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`storageObject when the requested storage exists getAllItems returns all keys 1`] = `
|
|
4
|
-
|
|
4
|
+
{
|
|
5
5
|
"baz_::_foo": "baz",
|
|
6
6
|
"baz_::_otherKey": "otherValue",
|
|
7
7
|
"foo": "bar",
|
|
@@ -10,7 +10,7 @@ Object {
|
|
|
10
10
|
`;
|
|
11
11
|
|
|
12
12
|
exports[`storageObject when the requested storage exists getAllItems returns all keys 2`] = `
|
|
13
|
-
|
|
13
|
+
{
|
|
14
14
|
"baz_::_foo": "baz",
|
|
15
15
|
"baz_::_otherKey": "otherValue",
|
|
16
16
|
"foo": "bar",
|
|
@@ -19,14 +19,14 @@ Object {
|
|
|
19
19
|
`;
|
|
20
20
|
|
|
21
21
|
exports[`storageObject when the requested storage exists getAllItems returns all keys in the namespace if provided 1`] = `
|
|
22
|
-
|
|
22
|
+
{
|
|
23
23
|
"foo": "baz",
|
|
24
24
|
"otherKey": "otherValue",
|
|
25
25
|
}
|
|
26
26
|
`;
|
|
27
27
|
|
|
28
28
|
exports[`storageObject when the requested storage exists getAllItems returns all keys in the namespace if provided 2`] = `
|
|
29
|
-
|
|
29
|
+
{
|
|
30
30
|
"foo": "baz",
|
|
31
31
|
"otherKey": "otherValue",
|
|
32
32
|
}
|
package/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { useHistory, useLocation } from "react-router-dom";
|
|
4
3
|
|
|
5
4
|
import { createQuickBrickApp } from "@applicaster/quick-brick-core";
|
|
6
5
|
import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
7
6
|
import * as Contexts from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
8
7
|
import { OfflineHandler } from "@applicaster/zapp-react-native-ui-components/Components/OfflineHandler";
|
|
9
8
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
10
|
-
import { ZappDomRouter } from "./App/Router";
|
|
11
9
|
import { Layout } from "./App/Layout";
|
|
12
10
|
import { SplashLoader } from "./App/Loader/SplashLoader";
|
|
13
11
|
import { appLoader } from "./App/Loader";
|
|
@@ -24,11 +22,6 @@ const contextProviders = R.map(R.prop("withProvider"), R.values(Contexts));
|
|
|
24
22
|
if (withXray) contextProviders.push(withXray);
|
|
25
23
|
|
|
26
24
|
export const ZappApp = createQuickBrickApp({
|
|
27
|
-
navigations: {
|
|
28
|
-
Router: ZappDomRouter,
|
|
29
|
-
useLocation,
|
|
30
|
-
useHistory,
|
|
31
|
-
},
|
|
32
25
|
QuickBrickManager,
|
|
33
26
|
Layout,
|
|
34
27
|
OfflineHandler,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-dom-app",
|
|
3
|
-
"version": "13.0.0-alpha.
|
|
3
|
+
"version": "13.0.0-alpha.2833001702",
|
|
4
4
|
"description": "Zapp App Component for Applicaster's Quick Brick React Native App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,23 +22,32 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@applicaster/zapp-react-dom-ui-components": "13.0.0-alpha.
|
|
26
|
-
"@applicaster/zapp-react-native-bridge": "13.0.0-alpha.
|
|
27
|
-
"@applicaster/zapp-react-native-redux": "13.0.0-alpha.
|
|
28
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.
|
|
29
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.
|
|
25
|
+
"@applicaster/zapp-react-dom-ui-components": "13.0.0-alpha.2833001702",
|
|
26
|
+
"@applicaster/zapp-react-native-bridge": "13.0.0-alpha.2833001702",
|
|
27
|
+
"@applicaster/zapp-react-native-redux": "13.0.0-alpha.2833001702",
|
|
28
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.2833001702",
|
|
29
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.2833001702",
|
|
30
30
|
"abortcontroller-polyfill": "^1.7.5",
|
|
31
|
-
"history": "^4.7.2",
|
|
32
31
|
"react-router-dom": "^5.1.2",
|
|
33
32
|
"typeface-montserrat": "^0.0.54",
|
|
34
|
-
"video.js": "
|
|
35
|
-
"videojs-contrib-eme": "^
|
|
36
|
-
"videojs-contrib-quality-levels": "
|
|
33
|
+
"video.js": "8.21.0",
|
|
34
|
+
"videojs-contrib-eme": "^5.5.1",
|
|
35
|
+
"videojs-contrib-quality-levels": "^4.1.0"
|
|
37
36
|
},
|
|
38
37
|
"peerDependencies": {
|
|
38
|
+
"@applicaster/zapp-pipes-v2-client": "*",
|
|
39
|
+
"@react-native-community/netinfo": "*",
|
|
40
|
+
"@types/node": "*",
|
|
39
41
|
"core-js": "3.29.1",
|
|
40
|
-
"
|
|
41
|
-
"react
|
|
42
|
-
"react-
|
|
42
|
+
"immer": "*",
|
|
43
|
+
"react": "*",
|
|
44
|
+
"react-dom": "*",
|
|
45
|
+
"react-native": "*",
|
|
46
|
+
"react-native-safe-area-context": "*",
|
|
47
|
+
"react-native-svg": "*",
|
|
48
|
+
"react-native-web": "*",
|
|
49
|
+
"uglify-js": "*",
|
|
50
|
+
"validate-color": "*",
|
|
51
|
+
"zustand": "*"
|
|
43
52
|
}
|
|
44
53
|
}
|
package/App/Router/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
|
-
|
|
4
|
-
import { Router } from "react-router";
|
|
5
|
-
import { createMemoryHistory } from "history";
|
|
6
|
-
|
|
7
|
-
const history = createMemoryHistory();
|
|
8
|
-
|
|
9
|
-
export const ZappDomRouter = ({ children, ...otherProps }) => (
|
|
10
|
-
<Router history={history} {...otherProps}>
|
|
11
|
-
{children}
|
|
12
|
-
</Router>
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
ZappDomRouter.propTypes = {
|
|
16
|
-
children: PropTypes.node.isRequired,
|
|
17
|
-
};
|
package/App/Splash/Spinner.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import "./spinner-styles.css";
|
|
4
|
-
|
|
5
|
-
export const Spinner = (color) => {
|
|
6
|
-
const spinnerColor = {
|
|
7
|
-
background: color.color,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
<div>
|
|
12
|
-
<div id="progress">
|
|
13
|
-
<div className="spinner">
|
|
14
|
-
<div style={spinnerColor} className="bar1" />
|
|
15
|
-
<div style={spinnerColor} className="bar2" />
|
|
16
|
-
<div style={spinnerColor} className="bar3" />
|
|
17
|
-
<div style={spinnerColor} className="bar4" />
|
|
18
|
-
<div style={spinnerColor} className="bar5" />
|
|
19
|
-
<div style={spinnerColor} className="bar6" />
|
|
20
|
-
<div style={spinnerColor} className="bar7" />
|
|
21
|
-
<div style={spinnerColor} className="bar8" />
|
|
22
|
-
<div style={spinnerColor} className="bar9" />
|
|
23
|
-
<div style={spinnerColor} className="bar10" />
|
|
24
|
-
<div style={spinnerColor} className="bar11" />
|
|
25
|
-
<div style={spinnerColor} className="bar12" />
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
);
|
|
30
|
-
};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
div.spinner {
|
|
2
|
-
position: absolute;
|
|
3
|
-
width: 100px;
|
|
4
|
-
height: 100px;
|
|
5
|
-
display: inline-block;
|
|
6
|
-
top: 50%;
|
|
7
|
-
left: 50%;
|
|
8
|
-
margin: -60px 0 0 -70px;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
div.spinner div {
|
|
12
|
-
width: 6%;
|
|
13
|
-
height: 16%;
|
|
14
|
-
position: absolute;
|
|
15
|
-
left: 49%;
|
|
16
|
-
top: 43%;
|
|
17
|
-
opacity: 0;
|
|
18
|
-
-webkit-border-radius: 50px;
|
|
19
|
-
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
|
20
|
-
-webkit-animation: fade 1s linear infinite;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@-webkit-keyframes fade {
|
|
24
|
-
from {
|
|
25
|
-
opacity: 1;
|
|
26
|
-
}
|
|
27
|
-
to {
|
|
28
|
-
opacity: 0.25;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
div.spinner div.bar1 {
|
|
33
|
-
-webkit-transform: rotate(0deg) translate(0, -130%);
|
|
34
|
-
-webkit-animation-delay: 0s;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
div.spinner div.bar2 {
|
|
38
|
-
-webkit-transform: rotate(30deg) translate(0, -130%);
|
|
39
|
-
-webkit-animation-delay: -0.9167s;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
div.spinner div.bar3 {
|
|
43
|
-
-webkit-transform: rotate(60deg) translate(0, -130%);
|
|
44
|
-
-webkit-animation-delay: -0.833s;
|
|
45
|
-
}
|
|
46
|
-
div.spinner div.bar4 {
|
|
47
|
-
-webkit-transform: rotate(90deg) translate(0, -130%);
|
|
48
|
-
-webkit-animation-delay: -0.7497s;
|
|
49
|
-
}
|
|
50
|
-
div.spinner div.bar5 {
|
|
51
|
-
-webkit-transform: rotate(120deg) translate(0, -130%);
|
|
52
|
-
-webkit-animation-delay: -0.667s;
|
|
53
|
-
}
|
|
54
|
-
div.spinner div.bar6 {
|
|
55
|
-
-webkit-transform: rotate(150deg) translate(0, -130%);
|
|
56
|
-
-webkit-animation-delay: -0.5837s;
|
|
57
|
-
}
|
|
58
|
-
div.spinner div.bar7 {
|
|
59
|
-
-webkit-transform: rotate(180deg) translate(0, -130%);
|
|
60
|
-
-webkit-animation-delay: -0.5s;
|
|
61
|
-
}
|
|
62
|
-
div.spinner div.bar8 {
|
|
63
|
-
-webkit-transform: rotate(210deg) translate(0, -130%);
|
|
64
|
-
-webkit-animation-delay: -0.4167s;
|
|
65
|
-
}
|
|
66
|
-
div.spinner div.bar9 {
|
|
67
|
-
-webkit-transform: rotate(240deg) translate(0, -130%);
|
|
68
|
-
-webkit-animation-delay: -0.333s;
|
|
69
|
-
}
|
|
70
|
-
div.spinner div.bar10 {
|
|
71
|
-
-webkit-transform: rotate(270deg) translate(0, -130%);
|
|
72
|
-
-webkit-animation-delay: -0.2497s;
|
|
73
|
-
}
|
|
74
|
-
div.spinner div.bar11 {
|
|
75
|
-
-webkit-transform: rotate(300deg) translate(0, -130%);
|
|
76
|
-
-webkit-animation-delay: -0.167s;
|
|
77
|
-
}
|
|
78
|
-
div.spinner div.bar12 {
|
|
79
|
-
-webkit-transform: rotate(330deg) translate(0, -130%);
|
|
80
|
-
-webkit-animation-delay: -0.0833s;
|
|
81
|
-
}
|