@applicaster/zapp-react-native-ui-components 16.0.0-rc.11 → 16.0.0-rc.111

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 (156) hide show
  1. package/Components/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
  2. package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
  3. package/Components/AudioPlayer/tv/index.tsx +5 -1
  4. package/Components/Cell/Cell.tsx +3 -6
  5. package/Components/Cell/TvOSCellComponent.tsx +0 -1
  6. package/Components/CellRendererResolver/index.ts +2 -2
  7. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
  9. package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
  10. package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
  11. package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
  12. package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
  13. package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
  14. package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
  15. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
  16. package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
  17. package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
  18. package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
  19. package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
  20. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
  21. package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
  22. package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
  23. package/Components/GeneralContentScreen/index.ts +2 -0
  24. package/Components/Layout/FullWidthRow.tsx +38 -0
  25. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  26. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  28. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  29. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  30. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  31. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  32. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  33. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  34. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  35. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  36. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  37. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
  38. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  39. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  40. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  41. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  42. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  43. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  44. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  45. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  46. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  47. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  48. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  49. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  50. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  52. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  53. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  54. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  55. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  56. package/Components/MasterCell/dataAdapter.ts +15 -5
  57. package/Components/MasterCell/hooks/index.ts +2 -0
  58. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  59. package/Components/MasterCell/index.tsx +30 -5
  60. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  61. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  62. package/Components/MasterCell/utils/index.ts +85 -46
  63. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
  64. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  65. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
  66. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  67. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
  68. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
  69. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
  70. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
  71. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1028 -0
  72. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
  73. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +164 -0
  74. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  75. package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
  76. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +393 -0
  77. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +523 -0
  78. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  79. package/Components/ModalComponent/BottomSheetModalContent.tsx +436 -50
  80. package/Components/ModalComponent/Button/index.tsx +5 -3
  81. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  82. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  83. package/Components/ModalComponent/Header/index.tsx +20 -7
  84. package/Components/ModalComponent/Header/utils.ts +1 -1
  85. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  86. package/Components/ModalComponent/SortableList.tsx +156 -0
  87. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  88. package/Components/ModalComponent/TextInputContent.tsx +135 -0
  89. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  90. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
  91. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  92. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
  93. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  94. package/Components/ModalComponent/index.tsx +18 -9
  95. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
  96. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  97. package/Components/ModalComponent/presets/index.ts +27 -0
  98. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  99. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  100. package/Components/ModalComponent/presets/types.ts +35 -0
  101. package/Components/ModalComponent/showTextInput.ts +52 -0
  102. package/Components/ModalComponent/utils.ts +82 -21
  103. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  104. package/Components/OfflineHandler/__tests__/index.test.tsx +186 -17
  105. package/Components/OfflineHandler/hooks.ts +111 -0
  106. package/Components/OfflineHandler/index.tsx +91 -75
  107. package/Components/OfflineHandler/utils/index.ts +1 -13
  108. package/Components/PlayerContainer/PlayerContainer.tsx +33 -18
  109. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  110. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
  111. package/Components/PreloaderWrapper/index.tsx +1 -1
  112. package/Components/River/ComponentsMap/ComponentsMap.tsx +87 -61
  113. package/Components/River/River.tsx +4 -0
  114. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -89
  115. package/Components/River/__tests__/componentsMap.test.js +8 -3
  116. package/Components/River/__tests__/resultCallback.test.tsx +47 -0
  117. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  118. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  119. package/Components/Screen/index.tsx +13 -4
  120. package/Components/Screen/navigationHandler.ts +8 -8
  121. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  122. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  123. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  124. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  125. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  126. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
  127. package/Components/TopCutoffOverlay/index.tsx +2 -2
  128. package/Components/Transitioner/AnimationManager.js +1 -1
  129. package/Components/Transitioner/Scene.tsx +4 -3
  130. package/Components/Transitioner/Transitioner.tsx +98 -49
  131. package/Components/Transitioner/__tests__/transitioner.test.js +372 -3
  132. package/Components/VideoLive/LiveImageManager.ts +9 -3
  133. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  134. package/Components/VideoModal/utils.ts +6 -1
  135. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
  136. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  137. package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
  138. package/Contexts/CachedDimensionsContext/index.ts +17 -2
  139. package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  140. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  141. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  142. package/Helpers/index.js +0 -39
  143. package/Hooks/useEntryActionsExpander.ts +63 -0
  144. package/assets/empty-Info.png +0 -0
  145. package/package.json +6 -5
  146. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  147. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  148. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  149. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  150. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  151. package/Components/Screen/utils.ts +0 -16
  152. package/Helpers/Analytics/index.js +0 -95
  153. /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
  154. /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
  155. /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
  156. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -21,11 +21,23 @@ export const SHOWN = 1; // opacity = 1
21
21
  type Props = {
22
22
  componentsToRender: ZappUIComponent[];
23
23
  backgroundColor?: string;
24
+ /**
25
+ * Renders every component at once instead of revealing them a few at a time.
26
+ *
27
+ * For a screen that builds its own components and holds all of them already -
28
+ * a form, say - staggering buys nothing and costs: each rebuild of the list
29
+ * tears it back down to the first few and lets the rest crawl in again.
30
+ *
31
+ * This is a flag rather than a count on purpose. A count would have to be
32
+ * re-read whenever the number of components changes, while "do not stagger"
33
+ * stays true whatever the screen ends up holding.
34
+ */
35
+ disableIncrementalLoading?: boolean;
24
36
  };
25
37
 
26
38
  export const withScreenRevealManager = (Component) => {
27
39
  return function WithScreenRevealManager(props: Props) {
28
- const { componentsToRender } = props;
40
+ const { componentsToRender, disableIncrementalLoading } = props;
29
41
 
30
42
  const [isContentReadyToBeShown, setIsContentReadyToBeShown] =
31
43
  React.useState(false);
@@ -42,7 +54,8 @@ export const withScreenRevealManager = (Component) => {
42
54
  () =>
43
55
  new ScreenRevealManager(
44
56
  componentsToRender,
45
- handleSetIsContentReadyToBeShown
57
+ handleSetIsContentReadyToBeShown,
58
+ disableIncrementalLoading ? componentsToRender.length : undefined
46
59
  )
47
60
  );
48
61
 
@@ -72,7 +85,7 @@ export const withScreenRevealManager = (Component) => {
72
85
 
73
86
  if (isFirstComponentScreenPicker(componentsToRender)) {
74
87
  // for screen-picker with have additional internal ComponentsMap, no need to add this wrapper
75
- return <Component {...props} />;
88
+ return <Component {...props} initialNumberToLoad={1} />;
76
89
  }
77
90
 
78
91
  return (
@@ -80,7 +93,11 @@ export const withScreenRevealManager = (Component) => {
80
93
  <Component
81
94
  {...props}
82
95
  initialNumberToLoad={
83
- managerRef.current.numberOfComponentsWaitToLoadBeforePresent
96
+ // Recomputed on every render, so the count follows the components
97
+ // even though the manager settled its own expectation at mount.
98
+ disableIncrementalLoading
99
+ ? componentsToRender.length
100
+ : managerRef.current.numberOfComponentsWaitToLoadBeforePresent
84
101
  }
85
102
  onLoadFinishedFromScreenRevealManager={
86
103
  managerRef.current.onLoadFinished
@@ -7,7 +7,7 @@ import { useMarginTop } from "./hooks";
7
7
 
8
8
  interface IProps {
9
9
  targetScreenId?: string;
10
- children?: React.ReactNode;
10
+ children: React.ReactElement | null;
11
11
  applyTopCutoff?: boolean;
12
12
  }
13
13
 
@@ -21,7 +21,7 @@ export const TopCutoffOverlay: React.FC<IProps> = ({
21
21
  targetScreenId,
22
22
  children,
23
23
  applyTopCutoff = true,
24
- }: IProps) => {
24
+ }) => {
25
25
  const cutoffHeight = useMarginTop(targetScreenId);
26
26
 
27
27
  const { backgroundColor: screenBackgroundColor } =
@@ -66,7 +66,7 @@ export class AnimationManager {
66
66
  *
67
67
  * @param {object} to contains style to animate and scenes index
68
68
  * @param {string} action push|back
69
- * @param {number} stepsBack number of steps back
69
+ * @param {number} [stepsBack] number of steps back, used by the back action only
70
70
  */
71
71
  stateForAction({ to, scenes }, action, stepsBack) {
72
72
  let rootIndex = to.index;
@@ -17,13 +17,14 @@ const fullWidthDimensions = {
17
17
  type Props = {
18
18
  children: any;
19
19
  style: any;
20
- pointerEvents: ViewProps["pointerEvents"];
21
- overlayStyle: ViewStyle;
22
- animating: boolean;
20
+ pointerEvents?: ViewProps["pointerEvents"];
21
+ overlayStyle?: ViewStyle;
22
+ animating?: boolean;
23
23
  contentStyle: ViewStyle;
24
24
  pathname: string;
25
25
  isActive: boolean;
26
26
  screenData: NavigationScreenData;
27
+ screenUniqueId?: string;
27
28
  };
28
29
 
29
30
  export function CurrentScreenContextProvider({
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { append, compose, identity, isNil, tail, take, update } from "ramda";
3
+ import { append, compose, identity, tail, update } from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
@@ -10,6 +10,7 @@ import {
10
10
  shouldSkipAnimationForPreviousWebViewScene,
11
11
  } from "./utils";
12
12
  import { v4 as uuid_v4 } from "uuid";
13
+ import { isScreenActiveForRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive";
13
14
 
14
15
  export const NAV_ACTION_PUSH = "PUSH";
15
16
 
@@ -17,11 +18,23 @@ export const NAV_ACTION_REPLACE = "REPLACE";
17
18
 
18
19
  export const NAV_ACTION_BACK = "POP";
19
20
 
20
- type SceneProps = {
21
- children: React.ReactNode;
22
- overlayStyle: any;
23
- style: any;
24
- animating: boolean;
21
+ const RIVER_SEGMENT_REGEX = /river\//g;
22
+
23
+ // Number of "river/" segments in the route, i.e. its depth in the navigation stack
24
+ function countRiverSegments(route?: string): number {
25
+ return (route?.match(RIVER_SEGMENT_REGEX) || []).length;
26
+ }
27
+
28
+ // The screen element rendered for the current route
29
+ type SceneChild = React.ReactElement<{
30
+ pathname: string;
31
+ screenData: NavigationScreenData;
32
+ }>;
33
+
34
+ type TransitionerScene = {
35
+ children: SceneChild;
36
+ key: string;
37
+ screenUniqueId: string;
25
38
  };
26
39
 
27
40
  /**
@@ -30,7 +43,7 @@ type SceneProps = {
30
43
  * @param {Object} children
31
44
  * @returns { children: Object, key: string }
32
45
  */
33
- function prepareScene(children) {
46
+ function prepareScene(children: SceneChild): TransitionerScene {
34
47
  return {
35
48
  children,
36
49
  key: children.props.pathname,
@@ -44,22 +57,26 @@ function prepareScene(children) {
44
57
  * @param {any} props Component's props
45
58
  * @param {any} state Component's state
46
59
  */
47
- function scenesForBackTransition(props: SceneProps, { scenes }) {
60
+ function scenesForBackTransition(
61
+ props: Pick<Props, "children">,
62
+ { scenes }: Pick<State, "scenes">
63
+ ): TransitionerScene[] {
48
64
  return scenes.length > 1
49
65
  ? identity(scenes)
50
66
  : [prepareScene(props.children), scenes[0]];
51
67
  }
52
68
 
53
- const isModalClosed = (navigator) => {
54
- return !!isNil(navigator?.modalData);
55
- };
56
-
57
69
  type Props = {
58
70
  transitionConfig: any;
59
- children: React.ReactNode;
71
+ isRTL?: boolean;
72
+ children: SceneChild;
60
73
  navigator: {
61
74
  previousAction: string;
62
75
  currentRoute: string;
76
+ videoModalState?: {
77
+ visible?: boolean;
78
+ mode?: string;
79
+ };
63
80
  screenData: {
64
81
  [key: string]: any;
65
82
  };
@@ -77,13 +94,12 @@ type Props = {
77
94
  };
78
95
 
79
96
  type State = {
80
- animatedValue: any;
81
97
  animating: boolean;
82
98
  duration: number;
83
99
  easing: any;
84
100
  from: any;
85
101
  to: any;
86
- scenes: any;
102
+ scenes: TransitionerScene[];
87
103
  };
88
104
 
89
105
  const styles = {
@@ -91,11 +107,18 @@ const styles = {
91
107
  } as const;
92
108
 
93
109
  export class TransitionerComponent extends React.PureComponent<Props, State> {
110
+ private animationManager: AnimationManager;
111
+
112
+ private transitionId: number;
113
+
94
114
  constructor(props: Props) {
95
115
  super(props);
96
116
 
97
117
  this.animationManager = new AnimationManager(props);
98
118
 
119
+ // Bumped by every animated transition; end callbacks of older ones are ignored
120
+ this.transitionId = 0;
121
+
99
122
  this.state = {
100
123
  scenes: [prepareScene(props.children)], // starting with index: 0
101
124
  ...this.animationManager.initialState(),
@@ -112,29 +135,36 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
112
135
  * and trigger push animation with callbacks.
113
136
  */
114
137
  pushTransitionStart() {
138
+ const transitionId = ++this.transitionId;
139
+
115
140
  this.setState(
116
141
  {
117
- scenes: append(prepareScene(this.props.children), this.state.scenes),
142
+ // Append right after the visible scene: stateForAction(PUSH) animates to.index + 1
143
+ scenes: [
144
+ ...this.state.scenes.slice(0, this.state.to.index + 1),
145
+ prepareScene(this.props.children),
146
+ ],
118
147
  ...this.animationManager.stateForAction(this.state, NAV_ACTION_PUSH),
119
148
  },
120
149
  () => {
121
- this.animationManager.animate(this.state, this.pushTransitionEnd);
150
+ this.animationManager.animate(this.state, () =>
151
+ this.pushTransitionEnd(transitionId)
152
+ );
122
153
  }
123
154
  );
124
155
  }
125
156
 
126
157
  /**
127
158
  * Trigger back animation.
128
- * The last scene in the array is removed in the "backTransitionEnd" callback,
159
+ * The scenes after the target one are removed in the "backTransitionEnd" callback,
129
160
  * only after the animation is complete.
130
161
  */
131
- backTransitionStart() {
132
- const previousRoute = this.props.navigator?.currentRoute;
162
+ backTransitionStart(previousRoute: string) {
163
+ const transitionId = ++this.transitionId;
133
164
  const currentRoute = this.props.navigator?.currentRoute;
134
165
 
135
166
  const diffLengthRoutes =
136
- (previousRoute?.match(/river\//g) || []).length -
137
- (currentRoute?.match(/river\//g) || []).length;
167
+ countRiverSegments(previousRoute) - countRiverSegments(currentRoute);
138
168
 
139
169
  const stepsBack =
140
170
  diffLengthRoutes && diffLengthRoutes > 0 ? diffLengthRoutes : 1;
@@ -150,30 +180,32 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
150
180
  },
151
181
  () => {
152
182
  this.animationManager.animate(this.state, () =>
153
- this.backTransitionEnd(stepsBack)
183
+ this.backTransitionEnd(transitionId)
154
184
  );
155
185
  }
156
186
  );
157
187
  }
158
188
 
159
- shouldSkipAnimationForRoute(route) {
189
+ shouldSkipAnimationForRoute(route: string) {
160
190
  // We are skipping animations for some routes, likes hooks & the player mainly
161
191
 
162
192
  return route.includes("/playable") || route.includes("/hook");
163
193
  }
164
194
 
165
- shouldResetStateForRoute(route) {
195
+ shouldResetStateForRoute(route: string) {
166
196
  // We are resetting the transitioner state for root routes
167
197
 
168
- return (route?.match(/river\//g) || []).length === 1;
198
+ return countRiverSegments(route) === 1;
169
199
  }
170
200
 
171
- transitionWithoutAnimation(resetState) {
172
- const { scenes } = this.state;
201
+ transitionWithoutAnimation(resetState?: boolean) {
202
+ // Scenes after the visible one are only leaving (back animation in flight),
203
+ // so the new scene replaces the one being backed to
204
+ const scenes = this.state.scenes.slice(0, this.state.to.index + 1);
173
205
  const newScene = prepareScene(this.props.children);
174
206
  const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
175
207
 
176
- let newState;
208
+ let newState: Pick<State, "scenes"> | Pick<State, "scenes" | "to">;
177
209
 
178
210
  if (resetState) {
179
211
  newState = {
@@ -241,7 +273,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
241
273
  break;
242
274
 
243
275
  case NAV_ACTION_BACK: {
244
- this.backTransitionStart();
276
+ this.backTransitionStart(previousRoute);
245
277
  break;
246
278
  }
247
279
 
@@ -263,28 +295,37 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
263
295
  }
264
296
  }
265
297
 
266
- // Sets state.animating to false
267
- pushTransitionEnd() {
298
+ // Sets state.animating to false,
299
+ // unless a newer transition has started since this one
300
+ pushTransitionEnd(transitionId: number) {
301
+ if (transitionId !== this.transitionId) return;
302
+
268
303
  this.setState({
269
304
  animating: false,
270
305
  });
271
306
  }
272
307
 
273
308
  // Sets state.animating to false
274
- // and remove last scene from scenes stack
275
- backTransitionEnd(stepsBack) {
276
- this.setState({
309
+ // and drops every scene after the target one. Reads the latest state,
310
+ // so it's correct however many backs were merged into this animation.
311
+ // Ignored if a newer transition has started since this one
312
+ backTransitionEnd(transitionId: number) {
313
+ if (transitionId !== this.transitionId) return;
314
+
315
+ this.setState(({ scenes, to }) => ({
277
316
  animating: false,
278
- scenes: take(this.state.scenes.length - stepsBack, this.state.scenes),
279
- });
317
+ scenes: scenes.slice(0, to.index + 1),
318
+ }));
280
319
  }
281
320
 
282
321
  // On initial state, both "to" and "from" point to a single scene
283
322
  // so only a single scene should be rendered,
284
323
  // instead of dangerous nulls or duplicates.
285
324
  renderSingleScene({ scenes, to }) {
286
- const { contentStyle } = this.props;
287
- const screenData = this.props.children.props.screenData;
325
+ const { contentStyle, navigator, children } = this.props;
326
+
327
+ const { currentRoute, videoModalState } = navigator;
328
+ const screenData = children.props.screenData;
288
329
  const pathname = scenes[to.index].key;
289
330
 
290
331
  return (
@@ -293,7 +334,11 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
293
334
  <Scene
294
335
  {...{ style: to?.style || {} }}
295
336
  pathname={pathname}
296
- isActive={pathname === this.props.navigator.currentRoute}
337
+ isActive={isScreenActiveForRoute(
338
+ pathname,
339
+ currentRoute,
340
+ videoModalState
341
+ )}
297
342
  contentStyle={contentStyle}
298
343
  key={scenes[to.index].key}
299
344
  screenUniqueId={scenes[to.index].screenUniqueId}
@@ -311,16 +356,19 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
311
356
  // Looks redundant, but when written like this
312
357
  // we do not need to pass or generate keys.
313
358
  renderScenes({ scenes, from, to }) {
314
- const { contentStyle } = this.props;
359
+ const { contentStyle, navigator } = this.props;
360
+
361
+ const { currentRoute, videoModalState } = navigator;
315
362
 
316
363
  const fromScene = scenes[from.index] && (
317
364
  <Scene
318
365
  key={scenes[from.index].key}
319
366
  pathname={scenes[from.index].key}
320
- isActive={
321
- scenes[from.index].key === this.props.navigator.currentRoute &&
322
- isModalClosed(this.props.navigator)
323
- }
367
+ isActive={isScreenActiveForRoute(
368
+ scenes[from.index].key,
369
+ currentRoute,
370
+ videoModalState
371
+ )}
324
372
  style={from.style}
325
373
  pointerEvents="none"
326
374
  overlayStyle={from.overlayStyle}
@@ -336,10 +384,11 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
336
384
  const toScene = scenes[to.index] && (
337
385
  <Scene
338
386
  pathname={scenes[to.index].key}
339
- isActive={
340
- scenes[to.index].key === this.props.navigator.currentRoute &&
341
- isModalClosed(this.props.navigator)
342
- }
387
+ isActive={isScreenActiveForRoute(
388
+ scenes[to.index].key,
389
+ currentRoute,
390
+ videoModalState
391
+ )}
343
392
  key={scenes[to.index].key}
344
393
  style={to.style}
345
394
  overlayStyle={to.overlayStyle}