@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5333112458 → 14.0.0-alpha.5351122050
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/Components/AnimatedInOut/index.tsx +5 -3
- package/Components/AudioPlayer/mobile/Layout.tsx +1 -1
- package/Components/AudioPlayer/tv/helpers.tsx +10 -3
- package/Components/BaseFocusable/index.tsx +23 -12
- package/Components/Cell/Cell.tsx +3 -8
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
- package/Components/Cell/index.js +1 -1
- package/Components/ComponentResolver/index.ts +1 -1
- package/Components/FeedLoader/FeedLoader.tsx +6 -15
- package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
- package/Components/FeedLoader/index.js +2 -8
- package/Components/Focusable/FocusableTvOS.tsx +3 -3
- package/Components/Focusable/FocusableiOS.tsx +2 -2
- package/Components/Focusable/index.tsx +1 -1
- package/Components/FocusableList/index.tsx +4 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -10
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -8
- package/Components/Layout/TV/LayoutBackground.tsx +1 -1
- package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
- package/Components/MasterCell/elementMapper.tsx +1 -2
- package/Components/MasterCell/utils/behaviorProvider.ts +2 -2
- package/Components/MasterCell/utils/index.ts +1 -15
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
- package/Components/OfflineHandler/__tests__/index.test.tsx +26 -35
- package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +26 -22
- package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
- package/Components/PlayerContainer/index.ts +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +378 -0
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
- package/Components/River/RefreshControl.tsx +11 -17
- package/Components/River/TV/River.tsx +2 -17
- package/Components/River/TV/index.tsx +3 -1
- package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
- package/Components/River/TV/withRiverDataLoader.tsx +17 -0
- package/Components/River/TV/withTVEventHandler.tsx +1 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/__tests__/river.test.js +12 -26
- package/Components/River/index.tsx +1 -1
- package/Components/Screen/__tests__/Screen.test.tsx +28 -29
- package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
- package/Components/Screen/navigationHandler.ts +20 -2
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
- package/Components/ScreenRevealManager/index.ts +1 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
- package/Components/Tabs/TV/Tabs.android.tsx +0 -2
- package/Components/Tabs/Tabs.tsx +2 -3
- package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +0 -13
- package/Components/TextInputTv/index.tsx +0 -11
- package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
- package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
- package/Components/Transitioner/Scene.tsx +0 -1
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
- package/Components/VideoLive/animationUtils.ts +3 -3
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +3 -9
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +24 -8
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
- package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
- package/Contexts/ScreenContext/index.tsx +46 -6
- package/Contexts/ScreenDataContext/index.tsx +0 -2
- package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
- package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
- package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
- package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
- package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
- package/Decorators/RiverFeedLoader/index.tsx +21 -9
- package/Decorators/RiverFeedLoader/utils/index.ts +0 -23
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
- package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
- package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +27 -312
- package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +266 -0
- package/Decorators/ZappPipesDataConnector/types.ts +29 -0
- package/Decorators/ZappPipesDataConnector/utils/mongoFilter.ts +738 -0
- package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +157 -0
- package/events/index.ts +1 -0
- package/package.json +5 -7
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
|
@@ -4,9 +4,11 @@ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/uti
|
|
|
4
4
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
5
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
6
|
|
|
7
|
-
type AnimatedInterpolatedStyle =
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
type AnimatedInterpolatedStyle = any;
|
|
8
|
+
|
|
9
|
+
// type AnimatedInterpolatedStyle =
|
|
10
|
+
// | Animated.AnimatedInterpolation
|
|
11
|
+
// | [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
10
12
|
|
|
11
13
|
type AnimationConfig = {
|
|
12
14
|
duration: number;
|
|
@@ -27,7 +27,7 @@ export function AudioPlayerMobileLayout({
|
|
|
27
27
|
}: Props) {
|
|
28
28
|
const fadeAnimation = useRef(new Animated.Value(0)).current;
|
|
29
29
|
|
|
30
|
-
const mainContainerStyles = platformSelect({
|
|
30
|
+
const mainContainerStyles: ViewStyle = platformSelect({
|
|
31
31
|
native: {
|
|
32
32
|
backgroundColor: "transparent",
|
|
33
33
|
overflow: "hidden",
|
|
@@ -27,13 +27,20 @@ const LTR = {
|
|
|
27
27
|
justifyContent: "flex-start",
|
|
28
28
|
textAlign: "left",
|
|
29
29
|
alignItems: "flex-end",
|
|
30
|
-
};
|
|
30
|
+
} as const;
|
|
31
31
|
|
|
32
32
|
const RTL = {
|
|
33
33
|
flexDirection: "row-reverse",
|
|
34
34
|
justifyContent: "flex-end",
|
|
35
35
|
textAlign: "right",
|
|
36
36
|
alignItems: "flex-start",
|
|
37
|
-
};
|
|
37
|
+
} as const;
|
|
38
38
|
|
|
39
|
-
export const directionStyles = (
|
|
39
|
+
export const directionStyles = (
|
|
40
|
+
isRTL: boolean
|
|
41
|
+
): {
|
|
42
|
+
flexDirection: "row" | "row-reverse";
|
|
43
|
+
justifyContent: "flex-start" | "flex-end";
|
|
44
|
+
textAlign: "left" | "right";
|
|
45
|
+
alignItems: "flex-end" | "flex-start";
|
|
46
|
+
} => (isRTL ? RTL : LTR);
|
|
@@ -146,10 +146,14 @@ export class BaseFocusable<
|
|
|
146
146
|
* @param {Object} scrollDirection
|
|
147
147
|
* @returns {Promise}
|
|
148
148
|
*/
|
|
149
|
-
onFocus: FocusManager.FocusEventCB = (
|
|
149
|
+
onFocus: FocusManager.FocusEventCB = (
|
|
150
|
+
focusable,
|
|
151
|
+
scrollDirection,
|
|
152
|
+
context
|
|
153
|
+
) => {
|
|
150
154
|
const { onFocus = noop } = this.props;
|
|
151
155
|
this.setFocusedState(true);
|
|
152
|
-
onFocus(focusable, scrollDirection);
|
|
156
|
+
onFocus(focusable, scrollDirection, context);
|
|
153
157
|
};
|
|
154
158
|
|
|
155
159
|
/**
|
|
@@ -247,8 +251,8 @@ export class BaseFocusable<
|
|
|
247
251
|
* @param {Object} scrollDirection
|
|
248
252
|
* @returns {Promise}
|
|
249
253
|
*/
|
|
250
|
-
focus(_, scrollDirection) {
|
|
251
|
-
return this.onFocus(this, scrollDirection); // invokeComponentMethod(this, "onFocus", scrollDirection);
|
|
254
|
+
focus(_, scrollDirection, context?: FocusManager.FocusContext) {
|
|
255
|
+
return this.onFocus(this, scrollDirection, context); // invokeComponentMethod(this, "onFocus", scrollDirection, context);
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
/**
|
|
@@ -258,9 +262,10 @@ export class BaseFocusable<
|
|
|
258
262
|
*/
|
|
259
263
|
blur(
|
|
260
264
|
_,
|
|
261
|
-
scrollDirection?: FocusManager.Web.Direction | FocusManager.IOS.Direction
|
|
265
|
+
scrollDirection?: FocusManager.Web.Direction | FocusManager.IOS.Direction,
|
|
266
|
+
context?: FocusManager.FocusContext
|
|
262
267
|
) {
|
|
263
|
-
return this.onBlur(this, scrollDirection);
|
|
268
|
+
return this.onBlur(this, scrollDirection, context);
|
|
264
269
|
}
|
|
265
270
|
|
|
266
271
|
/**
|
|
@@ -272,7 +277,7 @@ export class BaseFocusable<
|
|
|
272
277
|
* @param {string} scrollDirection string representation of the direction of the navigation which landed
|
|
273
278
|
* to this item being focused
|
|
274
279
|
*/
|
|
275
|
-
_executeFocusSequence(methodNames, scrollDirection) {
|
|
280
|
+
_executeFocusSequence(methodNames, scrollDirection, context) {
|
|
276
281
|
return R.reduce(
|
|
277
282
|
(sequence, methodName) => {
|
|
278
283
|
const method = this[methodName]; // Access the method by name
|
|
@@ -284,7 +289,7 @@ export class BaseFocusable<
|
|
|
284
289
|
}
|
|
285
290
|
|
|
286
291
|
return sequence
|
|
287
|
-
.then(() => method.call(this, scrollDirection))
|
|
292
|
+
.then(() => method.call(this, this, scrollDirection, context))
|
|
288
293
|
.catch((e) => {
|
|
289
294
|
throw e; // Re-throw for consistent error handling
|
|
290
295
|
});
|
|
@@ -294,15 +299,21 @@ export class BaseFocusable<
|
|
|
294
299
|
);
|
|
295
300
|
}
|
|
296
301
|
|
|
297
|
-
setFocus(
|
|
302
|
+
setFocus(
|
|
303
|
+
scrollDirection?: ScrollDirection,
|
|
304
|
+
context?: FocusManager.FocusContext
|
|
305
|
+
) {
|
|
298
306
|
const focusMethods = ["willReceiveFocus", "focus", "hasReceivedFocus"];
|
|
299
307
|
|
|
300
|
-
return this._executeFocusSequence(focusMethods, scrollDirection);
|
|
308
|
+
return this._executeFocusSequence(focusMethods, scrollDirection, context);
|
|
301
309
|
}
|
|
302
310
|
|
|
303
|
-
setBlur(
|
|
311
|
+
setBlur(
|
|
312
|
+
scrollDirection?: ScrollDirection,
|
|
313
|
+
context?: FocusManager.FocusContext
|
|
314
|
+
) {
|
|
304
315
|
const blurMethods = ["willLoseFocus", "blur", "hasLostFocus"];
|
|
305
316
|
|
|
306
|
-
return this._executeFocusSequence(blurMethods, scrollDirection);
|
|
317
|
+
return this._executeFocusSequence(blurMethods, scrollDirection, context);
|
|
307
318
|
}
|
|
308
319
|
}
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -70,8 +70,6 @@ type State = {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
export class CellComponent extends React.Component<Props, State> {
|
|
73
|
-
accessibilityManager: AccessibilityManager;
|
|
74
|
-
|
|
75
73
|
constructor(props) {
|
|
76
74
|
super(props);
|
|
77
75
|
this.onPress = this.onPress.bind(this);
|
|
@@ -85,8 +83,6 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
85
83
|
this.state = {
|
|
86
84
|
hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
|
|
87
85
|
};
|
|
88
|
-
|
|
89
|
-
this.accessibilityManager = AccessibilityManager.getInstance();
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
setScreenLayout(componentAnchorPointY, screenLayout) {
|
|
@@ -261,21 +257,20 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
261
257
|
style={styles.baseCell}
|
|
262
258
|
isFocusable={isFocusable}
|
|
263
259
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
264
|
-
{...this.accessibilityManager.getButtonAccessibilityProps(
|
|
265
|
-
item?.extensions?.accessibility?.label || item?.title
|
|
266
|
-
)}
|
|
267
260
|
>
|
|
268
261
|
{(focused, event) => {
|
|
269
262
|
const isFocused = this.isCellFocused(focused);
|
|
270
263
|
|
|
271
264
|
if (isFocused) {
|
|
265
|
+
const accessibilityManager = AccessibilityManager.getInstance();
|
|
266
|
+
|
|
272
267
|
const accessibilityTitle =
|
|
273
268
|
item?.extensions?.accessibility?.label || item?.title || "";
|
|
274
269
|
|
|
275
270
|
const accessibilityHint =
|
|
276
271
|
item?.extensions?.accessibility?.hint || "";
|
|
277
272
|
|
|
278
|
-
|
|
273
|
+
accessibilityManager.readText({
|
|
279
274
|
text: `${accessibilityTitle} ${accessibilityHint}`,
|
|
280
275
|
});
|
|
281
276
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { View } from "react-native";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { act
|
|
3
|
+
import { act } from "@testing-library/react-native";
|
|
4
4
|
import { CellWithFocusable } from "../CellWithFocusable.tsx";
|
|
5
5
|
|
|
6
6
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
7
|
+
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils/index.tsx";
|
|
7
8
|
|
|
8
9
|
const renderWith = (props) => {
|
|
9
|
-
return
|
|
10
|
+
return renderWithProviders(<CellWithFocusable {...props} />);
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
describe("CellWithFocusable", () => {
|
package/Components/Cell/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
|
|
3
|
-
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
3
|
+
import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
|
|
4
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
|
|
3
|
-
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
3
|
+
import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
|
|
4
4
|
|
|
5
5
|
import { ComponentResolverComponent } from "./ComponentResolver";
|
|
6
6
|
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import { selectZappPipes } from "@applicaster/zapp-react-native-redux";
|
|
3
4
|
|
|
4
5
|
type Props = {
|
|
5
|
-
zappPipes:
|
|
6
|
-
loadPipesData:
|
|
7
|
-
feed
|
|
8
|
-
|
|
9
|
-
clearCache: boolean;
|
|
10
|
-
meta: any;
|
|
11
|
-
loadLocalFavorites: boolean;
|
|
12
|
-
silentRefresh: boolean;
|
|
13
|
-
parentFeed: ZappFeed;
|
|
14
|
-
callback: () => void;
|
|
15
|
-
bodyParams: any;
|
|
16
|
-
riverId: string;
|
|
17
|
-
}>
|
|
18
|
-
) => void;
|
|
6
|
+
zappPipes: ReturnType<typeof selectZappPipes>;
|
|
7
|
+
loadPipesData: ReturnType<
|
|
8
|
+
typeof import("@applicaster/zapp-react-native-utils/reactHooks/feed").useLoadPipesDataDispatch
|
|
9
|
+
>;
|
|
19
10
|
feedUrl: string;
|
|
20
11
|
children: (feed: ZappFeed) => React.ComponentType<any>;
|
|
21
12
|
onFeedLoaded: (feed: ZappFeed) => {};
|
|
22
|
-
onError: (
|
|
13
|
+
onError: (error: ZappPipesData["error"]) => {};
|
|
23
14
|
refreshing: boolean;
|
|
24
15
|
refreshCallback: () => void;
|
|
25
16
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
selectZappPipes,
|
|
4
|
+
useAppSelector,
|
|
5
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
6
|
+
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
|
|
7
|
+
|
|
8
|
+
export const FeedLoaderHOC = (_Component: any) => {
|
|
9
|
+
return function FeedLoaderHOC(props: any) {
|
|
10
|
+
const zappPipes = useAppSelector(selectZappPipes);
|
|
11
|
+
const loadPipesData = useLoadPipesDataDispatch();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<_Component
|
|
15
|
+
{...props}
|
|
16
|
+
zappPipes={zappPipes}
|
|
17
|
+
loadPipesData={loadPipesData}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
|
-
|
|
3
|
-
import { connectToStore } from "@applicaster/zapp-react-native-redux";
|
|
4
|
-
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
5
|
-
|
|
6
1
|
import { FeedLoaderComponent } from "./FeedLoader";
|
|
2
|
+
import { FeedLoaderHOC } from "./FeedLoaderHOC";
|
|
7
3
|
|
|
8
|
-
export const FeedLoader =
|
|
9
|
-
loadPipesData,
|
|
10
|
-
})(FeedLoaderComponent);
|
|
4
|
+
export const FeedLoader = FeedLoaderHOC(FeedLoaderComponent);
|
|
@@ -16,9 +16,9 @@ function noop() {}
|
|
|
16
16
|
type Props = {
|
|
17
17
|
id: string;
|
|
18
18
|
groupId: string;
|
|
19
|
-
onPress?: (nativeEvent:
|
|
20
|
-
onFocus?: (nativeEvent:
|
|
21
|
-
onBlur?: (nativeEvent:
|
|
19
|
+
onPress?: (nativeEvent: any) => void;
|
|
20
|
+
onFocus?: (nativeEvent: any) => void;
|
|
21
|
+
onBlur?: (nativeEvent: any) => void;
|
|
22
22
|
children: (focused?: boolean) => React.ReactNode;
|
|
23
23
|
isParallaxDisabled: boolean;
|
|
24
24
|
preferredFocus?: boolean;
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
|
|
3
3
|
type Props = {
|
|
4
4
|
children: () => React.ReactNode;
|
|
5
|
-
}
|
|
5
|
+
} & Record<string, any>;
|
|
6
6
|
|
|
7
7
|
function FocusableiOSComponent({ children }: Props) {
|
|
8
8
|
if (typeof children === "function") {
|
|
@@ -12,4 +12,4 @@ function FocusableiOSComponent({ children }: Props) {
|
|
|
12
12
|
return children;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export const FocusableiOS =
|
|
15
|
+
export const FocusableiOS = FocusableiOSComponent;
|
|
@@ -4,7 +4,7 @@ import { FocusableiOS } from "./FocusableiOS";
|
|
|
4
4
|
|
|
5
5
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
6
6
|
|
|
7
|
-
export const Focusable = platformSelect({
|
|
7
|
+
export const Focusable: React.ComponentType<any> = platformSelect({
|
|
8
8
|
tvos: FocusableTvOS,
|
|
9
9
|
ios: FocusableiOS,
|
|
10
10
|
default: FocusableDefault,
|
|
@@ -91,6 +91,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
91
91
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
92
92
|
omitPropsPropagation = [],
|
|
93
93
|
useScrollView = false,
|
|
94
|
+
onScrollToIndexFailed = noop,
|
|
94
95
|
} = props;
|
|
95
96
|
|
|
96
97
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -277,6 +278,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
277
278
|
"withStateMemory",
|
|
278
279
|
"useSequentialLoading",
|
|
279
280
|
"useScrollView",
|
|
281
|
+
"onScrollToIndexFailed",
|
|
280
282
|
...omitPropsPropagation,
|
|
281
283
|
],
|
|
282
284
|
R.__
|
|
@@ -305,6 +307,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
305
307
|
{...getFlatListProps(props)}
|
|
306
308
|
onEndReached={onEndReached}
|
|
307
309
|
initialNumToRender={initialNumToRender}
|
|
310
|
+
onScrollToIndexFailed={onScrollToIndexFailed}
|
|
308
311
|
renderItem={renderItem}
|
|
309
312
|
focused={focused}
|
|
310
313
|
data={data}
|
|
@@ -319,6 +322,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
319
322
|
renderItem={renderItem}
|
|
320
323
|
onEndReached={onEndReached}
|
|
321
324
|
initialNumToRender={initialNumToRender}
|
|
325
|
+
onScrollToIndexFailed={onScrollToIndexFailed}
|
|
322
326
|
/>
|
|
323
327
|
)}
|
|
324
328
|
</ChildrenFocusDeactivatorView>
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import React, { Dispatch, useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
create,
|
|
5
|
-
ReactTestRenderer,
|
|
6
|
-
ReactTestRendererJSON,
|
|
7
|
-
} from "react-test-renderer";
|
|
2
|
+
import { act, render } from "@testing-library/react-native";
|
|
3
|
+
import { View } from "react-native";
|
|
8
4
|
import { FreezeWithCallback } from "../index";
|
|
9
5
|
|
|
10
|
-
const SimpleContent = () => <
|
|
6
|
+
const SimpleContent = () => <View testID="simple-content" />;
|
|
11
7
|
|
|
12
8
|
interface InnerProps {
|
|
13
9
|
value: number;
|
|
14
10
|
}
|
|
11
|
+
|
|
15
12
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
16
|
-
const Inner = ({ value }: InnerProps) =>
|
|
13
|
+
const Inner = ({ value }: InnerProps) => (
|
|
14
|
+
<View testID="inner-component" data-value={value} />
|
|
15
|
+
);
|
|
17
16
|
|
|
18
17
|
interface TestSubscriber {
|
|
19
18
|
renderCount: number;
|
|
@@ -51,24 +50,20 @@ const Container = ({ freeze, children }: ContainerProps) => (
|
|
|
51
50
|
);
|
|
52
51
|
|
|
53
52
|
function setupTest(initialFreeze: boolean = false) {
|
|
54
|
-
let testRenderer: ReactTestRenderer | undefined;
|
|
55
53
|
const [Subscriber, subscriberState] = createSubscriberComponent();
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
);
|
|
63
|
-
});
|
|
55
|
+
const renderResult = render(
|
|
56
|
+
<Container freeze={initialFreeze}>
|
|
57
|
+
<Subscriber />
|
|
58
|
+
</Container>
|
|
59
|
+
);
|
|
64
60
|
|
|
65
61
|
return {
|
|
66
|
-
|
|
67
|
-
testInstance: testRenderer?.root,
|
|
62
|
+
renderResult,
|
|
68
63
|
subscriberState,
|
|
69
64
|
updateFreeze: (freeze: boolean) => {
|
|
70
65
|
act(() =>
|
|
71
|
-
|
|
66
|
+
renderResult.rerender(
|
|
72
67
|
<Container freeze={freeze}>
|
|
73
68
|
<Subscriber />
|
|
74
69
|
</Container>
|
|
@@ -80,91 +75,120 @@ function setupTest(initialFreeze: boolean = false) {
|
|
|
80
75
|
|
|
81
76
|
describe("FreezeWithCallback", () => {
|
|
82
77
|
test("Renders stuff not frozen", () => {
|
|
83
|
-
const
|
|
78
|
+
const { getByTestId } = render(
|
|
84
79
|
<Container freeze={false}>
|
|
85
80
|
<SimpleContent />
|
|
86
81
|
</Container>
|
|
87
82
|
);
|
|
88
83
|
|
|
89
|
-
expect(
|
|
84
|
+
expect(getByTestId("simple-content")).toBeTruthy();
|
|
90
85
|
});
|
|
91
86
|
|
|
92
87
|
test("Does not render stuff when frozen", () => {
|
|
93
|
-
const
|
|
88
|
+
const { queryByTestId } = render(
|
|
94
89
|
<Container freeze>
|
|
95
90
|
<SimpleContent />
|
|
96
91
|
</Container>
|
|
97
92
|
);
|
|
98
93
|
|
|
99
|
-
expect(
|
|
94
|
+
expect(queryByTestId("simple-content")).toBe(null);
|
|
100
95
|
});
|
|
101
96
|
|
|
102
97
|
test("Stuff is gone after freeze", () => {
|
|
103
|
-
const
|
|
98
|
+
const { toJSON, getByTestId, rerender } = render(
|
|
104
99
|
<Container freeze={false}>
|
|
105
100
|
<SimpleContent />
|
|
106
101
|
</Container>
|
|
107
102
|
);
|
|
108
103
|
|
|
109
|
-
expect(
|
|
104
|
+
expect(getByTestId("simple-content")).toBeTruthy();
|
|
110
105
|
|
|
111
106
|
act(() =>
|
|
112
|
-
|
|
107
|
+
rerender(
|
|
113
108
|
<Container freeze>
|
|
114
109
|
<SimpleContent />
|
|
115
110
|
</Container>
|
|
116
111
|
)
|
|
117
112
|
);
|
|
118
113
|
|
|
119
|
-
expect(
|
|
114
|
+
expect(toJSON()).toBe(null);
|
|
120
115
|
});
|
|
121
116
|
|
|
122
117
|
test("Updates work when not frozen", () => {
|
|
123
|
-
const {
|
|
118
|
+
const { renderResult, subscriberState } = setupTest();
|
|
119
|
+
|
|
120
|
+
expect(
|
|
121
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
122
|
+
).toEqual(0);
|
|
124
123
|
|
|
125
|
-
expect(testInstance?.findByType(Inner).props.value).toEqual(0);
|
|
126
124
|
act(() => subscriberState.subscription(1));
|
|
127
|
-
|
|
125
|
+
|
|
126
|
+
expect(
|
|
127
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
128
|
+
).toEqual(1);
|
|
129
|
+
|
|
128
130
|
expect(subscriberState.renderCount).toBe(2);
|
|
129
131
|
});
|
|
130
132
|
|
|
131
133
|
test("Updates does not propagate when frozen", () => {
|
|
132
|
-
const {
|
|
134
|
+
const { renderResult, subscriberState, updateFreeze } = setupTest();
|
|
135
|
+
|
|
136
|
+
expect(
|
|
137
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
138
|
+
).toEqual(0);
|
|
133
139
|
|
|
134
|
-
expect(testInstance?.findByType(Inner).props.value).toEqual(0);
|
|
135
140
|
updateFreeze(true);
|
|
136
141
|
act(() => subscriberState.subscription(1));
|
|
137
|
-
|
|
142
|
+
|
|
143
|
+
expect(
|
|
144
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
145
|
+
).toEqual(0);
|
|
146
|
+
|
|
138
147
|
expect(subscriberState.renderCount).toBe(1);
|
|
139
148
|
});
|
|
140
149
|
|
|
141
150
|
test("State persists after defrost", () => {
|
|
142
|
-
const {
|
|
143
|
-
|
|
151
|
+
const { renderResult, subscriberState, updateFreeze } = setupTest();
|
|
152
|
+
|
|
153
|
+
expect(
|
|
154
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
155
|
+
).toEqual(0);
|
|
144
156
|
|
|
145
|
-
expect(testInstance?.findByType(Inner).props.value).toEqual(0);
|
|
146
157
|
act(() => subscriberState.subscription(1));
|
|
147
|
-
|
|
158
|
+
|
|
159
|
+
expect(
|
|
160
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
161
|
+
).toEqual(1);
|
|
148
162
|
|
|
149
163
|
updateFreeze(true);
|
|
150
|
-
expect(
|
|
164
|
+
expect(renderResult.toJSON()).toBe(null);
|
|
151
165
|
|
|
152
166
|
updateFreeze(false);
|
|
153
|
-
expect((
|
|
154
|
-
|
|
167
|
+
expect(renderResult.getByTestId("inner-component")).toBeTruthy();
|
|
168
|
+
|
|
169
|
+
expect(
|
|
170
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
171
|
+
).toEqual(1);
|
|
155
172
|
});
|
|
156
173
|
|
|
157
174
|
test("Update propagate after defrost", () => {
|
|
158
|
-
const {
|
|
175
|
+
const { renderResult, subscriberState, updateFreeze } = setupTest();
|
|
159
176
|
|
|
160
177
|
updateFreeze(true);
|
|
161
178
|
act(() => subscriberState.subscription(1));
|
|
162
179
|
act(() => subscriberState.subscription(2));
|
|
163
180
|
act(() => subscriberState.subscription(3));
|
|
164
|
-
|
|
181
|
+
|
|
182
|
+
expect(
|
|
183
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
184
|
+
).toEqual(0);
|
|
165
185
|
|
|
166
186
|
updateFreeze(false);
|
|
167
|
-
|
|
187
|
+
|
|
188
|
+
expect(
|
|
189
|
+
renderResult.getByTestId("inner-component").props["data-value"]
|
|
190
|
+
).toEqual(3);
|
|
191
|
+
|
|
168
192
|
expect(subscriberState.renderCount).toBe(2);
|
|
169
193
|
});
|
|
170
194
|
});
|