@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4337072244 → 12.0.0-alpha.4354608902
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/BaseFocusable/index.tsx +2 -2
- package/Components/Cell/Cell.tsx +9 -8
- package/Components/Cell/CellWithFocusable.tsx +7 -5
- package/Components/Cell/TvOSCellComponent.tsx +6 -11
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +10 -2
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/index.test.tsx +3 -2
- package/Components/Layout/TV/index.tsx +47 -41
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -112
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/NativeFocusables/{index.js → index.ts} +4 -2
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +2 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -0
- package/Components/River/RefreshControl.tsx +2 -2
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/TV/hooks/useInitialFocus.ts +6 -3
- package/Components/Screen/TV/index.web.tsx +12 -21
- package/Components/Screen/__tests__/Screen.test.tsx +3 -0
- package/Components/Screen/index.tsx +55 -58
- package/Components/Screen/navigationHandler.ts +5 -0
- package/Components/Transitioner/Scene.tsx +32 -26
- package/Components/Transitioner/Transitioner.tsx +21 -28
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +28 -1
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +56 -43
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +42 -32
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
- package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +69 -62
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Decorators/Analytics/{index.js → index.tsx} +11 -11
- package/README.md +1 -13
- package/package.json +5 -5
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -14,12 +14,13 @@ import { PlayerDetails } from "./PlayerDetails";
|
|
|
14
14
|
import { playerDimesionsHack } from "./utils";
|
|
15
15
|
import { PathnameContext } from "../../Contexts/PathnameContext";
|
|
16
16
|
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
17
|
+
import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
|
-
AnimationComponent,
|
|
20
|
-
ComponentAnimationType,
|
|
21
20
|
AnimatedScrollModal,
|
|
22
21
|
AnimatedVideoPlayerComponent,
|
|
22
|
+
AnimationComponent,
|
|
23
|
+
ComponentAnimationType,
|
|
23
24
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
24
25
|
|
|
25
26
|
type DimensionsT = {
|
|
@@ -96,7 +97,7 @@ const getEdges = (isTablet: boolean, isInlineModal: boolean) => {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
if (!isInlineModal && Platform.OS === "android") {
|
|
99
|
-
return [
|
|
100
|
+
return [];
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
return ["top"];
|
|
@@ -161,7 +162,7 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
161
162
|
width: isInlineModal && docked ? undefined : baseDimensions.width,
|
|
162
163
|
aspectRatio: !isInlineModal && !pip ? getScreenAspectRatio() : 16 / 9,
|
|
163
164
|
}),
|
|
164
|
-
[baseDimensions, isInlineModal, pip
|
|
165
|
+
[baseDimensions, isInlineModal, pip]
|
|
165
166
|
);
|
|
166
167
|
|
|
167
168
|
const containerDimensions: DimensionsT = React.useMemo(
|
|
@@ -180,65 +181,71 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
180
181
|
[containerDimensions, playerDimesionsHack]
|
|
181
182
|
);
|
|
182
183
|
|
|
184
|
+
const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${entry?.id}`;
|
|
185
|
+
|
|
183
186
|
return (
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
animationType={ComponentAnimationType.moveUpComponent}
|
|
210
|
-
style={isTabletLandscape ? defaultStyles.flex : undefined}
|
|
211
|
-
additionalData={{
|
|
212
|
-
useLayoutMeasure: isTabletLandscape,
|
|
213
|
-
disableAnimatedComponent: !isTabletLandscape,
|
|
214
|
-
resetAnimationValue: isTabletLandscape && docked,
|
|
215
|
-
}}
|
|
216
|
-
>
|
|
217
|
-
<AnimatedVideoPlayerComponent>
|
|
218
|
-
{children(childrenStyles)}
|
|
219
|
-
</AnimatedVideoPlayerComponent>
|
|
220
|
-
</AnimationComponent>
|
|
221
|
-
</View>
|
|
222
|
-
<AnimatedScrollModal>
|
|
223
|
-
{isInlineModal ? (
|
|
224
|
-
<AnimationComponent
|
|
225
|
-
animationType={ComponentAnimationType.componentFade}
|
|
226
|
-
style={defaultStyles.flex}
|
|
187
|
+
<PathnameContext.Provider value={pathname}>
|
|
188
|
+
<ScreenContextProvider pathname={pathname}>
|
|
189
|
+
<WrapperView
|
|
190
|
+
edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
|
|
191
|
+
style={[
|
|
192
|
+
safeAreaStyles(configuration, isTablet),
|
|
193
|
+
style,
|
|
194
|
+
playerDimesionsHack,
|
|
195
|
+
]}
|
|
196
|
+
>
|
|
197
|
+
<AnimationComponent
|
|
198
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
199
|
+
additionalData={{ saveArea: true }}
|
|
200
|
+
style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
|
|
201
|
+
>
|
|
202
|
+
<PathnameContext.Provider value={pathname}>
|
|
203
|
+
<ScreenContextProvider pathname={pathname}>
|
|
204
|
+
<View
|
|
205
|
+
testID={`${entry?.id}-player-container`}
|
|
206
|
+
style={[
|
|
207
|
+
defaultStyles.playerContainer,
|
|
208
|
+
containerDimensions,
|
|
209
|
+
containerStyle,
|
|
210
|
+
playerDimesionsHack,
|
|
211
|
+
]}
|
|
227
212
|
>
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
style={defaultStyles.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
213
|
+
<AnimationComponent
|
|
214
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
215
|
+
style={isTabletLandscape ? defaultStyles.flex : undefined}
|
|
216
|
+
additionalData={{
|
|
217
|
+
useLayoutMeasure: isTabletLandscape,
|
|
218
|
+
disableAnimatedComponent: !isTabletLandscape,
|
|
219
|
+
resetAnimationValue: isTabletLandscape && docked,
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
222
|
+
<AnimatedVideoPlayerComponent>
|
|
223
|
+
{children(childrenStyles)}
|
|
224
|
+
</AnimatedVideoPlayerComponent>
|
|
225
|
+
</AnimationComponent>
|
|
226
|
+
</View>
|
|
227
|
+
<AnimatedScrollModal>
|
|
228
|
+
{isInlineModal && !docked ? (
|
|
229
|
+
<AnimationComponent
|
|
230
|
+
animationType={ComponentAnimationType.componentFade}
|
|
231
|
+
style={defaultStyles.flex}
|
|
232
|
+
>
|
|
233
|
+
<PlayerDetails
|
|
234
|
+
configuration={configuration}
|
|
235
|
+
style={defaultStyles.playerDetails}
|
|
236
|
+
entry={entry}
|
|
237
|
+
isTabletLandscape={isTabletLandscape}
|
|
238
|
+
/>
|
|
239
|
+
</AnimationComponent>
|
|
240
|
+
) : (
|
|
241
|
+
<View style={defaultStyles.playerDetails} />
|
|
242
|
+
)}
|
|
243
|
+
</AnimatedScrollModal>
|
|
244
|
+
</ScreenContextProvider>
|
|
245
|
+
</PathnameContext.Provider>
|
|
246
|
+
</AnimationComponent>
|
|
247
|
+
</WrapperView>
|
|
248
|
+
</ScreenContextProvider>
|
|
249
|
+
</PathnameContext.Provider>
|
|
243
250
|
);
|
|
244
251
|
};
|
|
@@ -129,8 +129,8 @@ const VideoModalComponent = () => {
|
|
|
129
129
|
const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${item?.id}`;
|
|
130
130
|
|
|
131
131
|
return (
|
|
132
|
-
<
|
|
133
|
-
<
|
|
132
|
+
<PathnameContext.Provider value={pathname}>
|
|
133
|
+
<ScreenContextProvider pathname={pathname}>
|
|
134
134
|
{itemIdHooksFinished === item?.id ? (
|
|
135
135
|
<AnimatedPlayerModalWrapper
|
|
136
136
|
style={[
|
|
@@ -153,8 +153,8 @@ const VideoModalComponent = () => {
|
|
|
153
153
|
<Spinner />
|
|
154
154
|
</View>
|
|
155
155
|
)}
|
|
156
|
-
</
|
|
157
|
-
</
|
|
156
|
+
</ScreenContextProvider>
|
|
157
|
+
</PathnameContext.Provider>
|
|
158
158
|
);
|
|
159
159
|
};
|
|
160
160
|
|
|
@@ -25,6 +25,13 @@ jest.mock("react-native-gesture-handler");
|
|
|
25
25
|
|
|
26
26
|
jest.mock("../PlayerDetails", () => ({ PlayerDetails: View }));
|
|
27
27
|
|
|
28
|
+
jest.mock(
|
|
29
|
+
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext",
|
|
30
|
+
() => ({
|
|
31
|
+
useScreenContext: jest.fn().mockReturnValue({ screen: {}, entry: {} }),
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
|
|
28
35
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/device", () => ({
|
|
29
36
|
useIsTablet,
|
|
30
37
|
}));
|
|
@@ -42,9 +42,14 @@ exports[`PlayerWrapper renders inline 1`] = `
|
|
|
42
42
|
}
|
|
43
43
|
animationType="moveUpComponent"
|
|
44
44
|
style={
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
Array [
|
|
46
|
+
Object {
|
|
47
|
+
"flexDirection": "column",
|
|
48
|
+
},
|
|
49
|
+
Object {
|
|
50
|
+
"flex": 1,
|
|
51
|
+
},
|
|
52
|
+
]
|
|
48
53
|
}
|
|
49
54
|
>
|
|
50
55
|
<View
|
|
@@ -120,9 +125,14 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
|
|
|
120
125
|
}
|
|
121
126
|
animationType="moveUpComponent"
|
|
122
127
|
style={
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
Array [
|
|
129
|
+
Object {
|
|
130
|
+
"flexDirection": "column",
|
|
131
|
+
},
|
|
132
|
+
Object {
|
|
133
|
+
"flex": 1,
|
|
134
|
+
},
|
|
135
|
+
]
|
|
126
136
|
}
|
|
127
137
|
>
|
|
128
138
|
<View
|
|
@@ -198,9 +208,14 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
|
|
|
198
208
|
}
|
|
199
209
|
animationType="moveUpComponent"
|
|
200
210
|
style={
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
Array [
|
|
212
|
+
Object {
|
|
213
|
+
"flexDirection": "row",
|
|
214
|
+
},
|
|
215
|
+
Object {
|
|
216
|
+
"flex": 1,
|
|
217
|
+
},
|
|
218
|
+
]
|
|
204
219
|
}
|
|
205
220
|
>
|
|
206
221
|
<View
|
|
@@ -292,9 +307,14 @@ exports[`PlayerWrapper renders properly 1`] = `
|
|
|
292
307
|
}
|
|
293
308
|
animationType="moveUpComponent"
|
|
294
309
|
style={
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
Array [
|
|
311
|
+
Object {
|
|
312
|
+
"flexDirection": "column",
|
|
313
|
+
},
|
|
314
|
+
Object {
|
|
315
|
+
"flex": 1,
|
|
316
|
+
},
|
|
317
|
+
]
|
|
298
318
|
}
|
|
299
319
|
>
|
|
300
320
|
<View
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Dimensions } from "react-native";
|
|
3
2
|
import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
|
|
4
3
|
import {
|
|
5
4
|
addOrientationChangeListener,
|
|
@@ -9,11 +8,10 @@ import {
|
|
|
9
8
|
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
10
9
|
|
|
11
10
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
11
|
+
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
12
12
|
|
|
13
13
|
const { Logger } = getXray();
|
|
14
14
|
|
|
15
|
-
const { width: WIDTH, height: HEIGHT } = Dimensions.get("window");
|
|
16
|
-
|
|
17
15
|
const logger = new Logger(
|
|
18
16
|
"hooks",
|
|
19
17
|
"zapp-react-native-ui-components/Components/VideoModal"
|
|
@@ -24,20 +22,18 @@ type Size = {
|
|
|
24
22
|
height: number | string;
|
|
25
23
|
};
|
|
26
24
|
|
|
27
|
-
const MODAL_SIZE_FOR_PORTRAIT: Size = {
|
|
28
|
-
width: WIDTH,
|
|
29
|
-
height: HEIGHT,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
25
|
const MODAL_SIZE_FOR_LANDSCAPE: Size = {
|
|
33
26
|
width: "100%",
|
|
34
27
|
height: "100%",
|
|
35
28
|
};
|
|
36
29
|
|
|
37
30
|
export const useModalSize = (): Size => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
const frame = useSafeAreaFrame();
|
|
32
|
+
|
|
33
|
+
const [modalSize, setModalSize] = React.useState<Size>({
|
|
34
|
+
width: frame.width,
|
|
35
|
+
height: frame.height,
|
|
36
|
+
});
|
|
41
37
|
|
|
42
38
|
const setNewModalSize = React.useCallback((newSize, log) => {
|
|
43
39
|
setModalSize((oldSize) => {
|
|
@@ -90,7 +86,9 @@ export const useModalSize = (): Size => {
|
|
|
90
86
|
toOrientation === ORIENTATIONS.landscapeSensor;
|
|
91
87
|
|
|
92
88
|
setNewModalSize(
|
|
93
|
-
isLandscape
|
|
89
|
+
isLandscape
|
|
90
|
+
? MODAL_SIZE_FOR_LANDSCAPE
|
|
91
|
+
: { width: frame.width, height: frame.height },
|
|
94
92
|
`useModalSize: set modal size ${
|
|
95
93
|
isLandscape ? "landscape" : "portrait"
|
|
96
94
|
} for orientation: ${to}`
|
|
@@ -33,8 +33,11 @@ export const useConfiguration = () => {
|
|
|
33
33
|
...pluginConfiguration,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const {
|
|
37
|
-
|
|
36
|
+
const {
|
|
37
|
+
minimised_height = 0,
|
|
38
|
+
minimised_height_tablet = 0,
|
|
39
|
+
modal_background_color,
|
|
40
|
+
} = config;
|
|
38
41
|
|
|
39
42
|
const minimisedHeight = useIsTablet()
|
|
40
43
|
? minimised_height_tablet
|
|
@@ -6,23 +6,23 @@ import { callOnChildren } from "../utils";
|
|
|
6
6
|
|
|
7
7
|
export function ViewportTracker(props) {
|
|
8
8
|
const viewportEvents = useViewportEventsContext();
|
|
9
|
-
const { children } = props;
|
|
10
|
-
const [width, setWidth] = React.useState(0);
|
|
11
|
-
const [height, setHeight] = React.useState(0);
|
|
12
|
-
const [offsetX, setOffsetX] = React.useState(0);
|
|
13
|
-
const [offsetY, setOffsetY] = React.useState(0);
|
|
14
9
|
const [nodeHandle, setNodeHandle] = React.useState(null);
|
|
15
10
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
const childrenRef = React.useRef(props.children);
|
|
12
|
+
|
|
13
|
+
const dimensionsRef = React.useRef({ width: 0, height: 0 });
|
|
14
|
+
const offsetRef = React.useRef({ offsetX: 0, offsetY: 0 });
|
|
15
|
+
|
|
16
|
+
const assignRef = React.useCallback((ref) => {
|
|
17
|
+
childrenRef.current?.ref?.(ref);
|
|
18
|
+
setNodeHandle(findNodeHandle(ref));
|
|
19
|
+
}, []);
|
|
23
20
|
|
|
24
21
|
const onViewportChange = React.useCallback(
|
|
25
|
-
(
|
|
22
|
+
({
|
|
23
|
+
event = { ...dimensionsRef.current, ...offsetRef.current },
|
|
24
|
+
shouldMeasureLayout = true,
|
|
25
|
+
} = {}) => {
|
|
26
26
|
if (nodeHandle && event?.width > 0 && event?.height > 0) {
|
|
27
27
|
viewportEvents?.notify?.({
|
|
28
28
|
parentHandle: nodeHandle,
|
|
@@ -36,54 +36,45 @@ export function ViewportTracker(props) {
|
|
|
36
36
|
|
|
37
37
|
const onLayout = React.useCallback(
|
|
38
38
|
(event) => {
|
|
39
|
-
callOnChildren(
|
|
40
|
-
|
|
41
|
-
setHeight(event?.nativeEvent?.layout?.height);
|
|
39
|
+
callOnChildren(childrenRef.current, "onLayout", event);
|
|
40
|
+
dimensionsRef.current = event?.nativeEvent?.layout;
|
|
42
41
|
|
|
43
|
-
onViewportChange(
|
|
44
|
-
width: event?.nativeEvent?.layout?.width,
|
|
45
|
-
height: event?.nativeEvent?.layout?.height,
|
|
46
|
-
offsetX,
|
|
47
|
-
offsetY,
|
|
48
|
-
});
|
|
42
|
+
onViewportChange();
|
|
49
43
|
},
|
|
50
|
-
[
|
|
44
|
+
[onViewportChange]
|
|
51
45
|
);
|
|
52
46
|
|
|
53
47
|
const onContentSizeChange = React.useCallback(
|
|
54
48
|
(contentWidth, contentHeight) => {
|
|
55
49
|
callOnChildren(
|
|
56
|
-
|
|
50
|
+
childrenRef.current,
|
|
57
51
|
"onContentSizeChange",
|
|
58
52
|
contentWidth,
|
|
59
53
|
contentHeight
|
|
60
54
|
);
|
|
61
55
|
|
|
62
|
-
onViewportChange(
|
|
56
|
+
onViewportChange();
|
|
63
57
|
},
|
|
64
|
-
[onViewportChange
|
|
58
|
+
[onViewportChange]
|
|
65
59
|
);
|
|
66
60
|
|
|
67
61
|
const onScroll = React.useCallback(
|
|
68
62
|
(event) => {
|
|
69
|
-
callOnChildren(
|
|
70
|
-
|
|
71
|
-
setOffsetY(event?.nativeEvent?.contentOffset?.y);
|
|
63
|
+
callOnChildren(childrenRef.current, "onScroll", event);
|
|
64
|
+
offsetRef.current = event?.nativeEvent?.contentOffset;
|
|
72
65
|
|
|
73
|
-
onViewportChange(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
height,
|
|
77
|
-
offsetX: event?.nativeEvent?.contentOffset?.x,
|
|
78
|
-
offsetY: event?.nativeEvent?.contentOffset?.y,
|
|
79
|
-
},
|
|
80
|
-
false
|
|
81
|
-
);
|
|
66
|
+
onViewportChange({
|
|
67
|
+
shouldMeasureLayout: false,
|
|
68
|
+
});
|
|
82
69
|
},
|
|
83
|
-
[onViewportChange
|
|
70
|
+
[onViewportChange]
|
|
84
71
|
);
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
childrenRef.current = props.children;
|
|
75
|
+
}, [props.children]);
|
|
76
|
+
|
|
77
|
+
return React.cloneElement(React.Children.only(props.children), {
|
|
87
78
|
ref: assignRef,
|
|
88
79
|
onLayout,
|
|
89
80
|
onContentSizeChange,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
|
|
4
|
+
type ProviderArgs = {
|
|
5
|
+
id: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const FocusableGroupContextProvider = ({
|
|
10
|
+
id,
|
|
11
|
+
children,
|
|
12
|
+
}: ProviderArgs) => (
|
|
13
|
+
<FocusableGroupContext.Provider value={id}>
|
|
14
|
+
{children}
|
|
15
|
+
</FocusableGroupContext.Provider>
|
|
16
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { FocusableGroupContextProvider, FocusableGroupContext } from "../";
|
|
5
|
+
|
|
6
|
+
const MockComponent = () => {
|
|
7
|
+
const focusableContext = useContext(FocusableGroupContext) || "default";
|
|
8
|
+
|
|
9
|
+
return <Text testID={focusableContext} />;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe("FocusableGroupContextProvider", () => {
|
|
13
|
+
it("should provide focusable context to the wrapped component", () => {
|
|
14
|
+
const { getByTestId } = render(
|
|
15
|
+
<FocusableGroupContextProvider id="testId">
|
|
16
|
+
<MockComponent />
|
|
17
|
+
</FocusableGroupContextProvider>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(getByTestId("testId")).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { withFocusableContext } from "../withFocusableContext";
|
|
5
|
+
import { FocusableGroupContext } from "../FocusableGroupContext";
|
|
6
|
+
|
|
7
|
+
const MockComponent = ({ groupId }: { groupId: string }) => (
|
|
8
|
+
<Text testID={groupId} />
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const WrappedComponent = withFocusableContext(MockComponent);
|
|
12
|
+
|
|
13
|
+
describe("withFocusableContext HOC", () => {
|
|
14
|
+
it("should provide focusable context to the wrapped component", () => {
|
|
15
|
+
const { getByTestId } = render(<WrappedComponent />, {
|
|
16
|
+
// eslint-disable-next-line react/display-name
|
|
17
|
+
wrapper: ({ children }: { children: React.ReactElement }) => (
|
|
18
|
+
<FocusableGroupContext.Provider value="test">
|
|
19
|
+
{children}
|
|
20
|
+
</FocusableGroupContext.Provider>
|
|
21
|
+
),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(getByTestId("test")).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
import { FocusableGroupContextProvider } from "./FocusableGroupContextProvider";
|
|
4
|
+
|
|
5
|
+
export { FocusableGroupContext, FocusableGroupContextProvider };
|
|
6
|
+
|
|
7
|
+
export const useGroupId = () => React.useContext(FocusableGroupContext);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FocusableGroupContext } from "./FocusableGroupContext";
|
|
3
|
+
|
|
4
|
+
export const withFocusableContext = (Component) => {
|
|
5
|
+
// eslint-disable-next-line react/display-name
|
|
6
|
+
return ({ groupId, ...props }: Record<string, any>) => (
|
|
7
|
+
<FocusableGroupContext.Consumer>
|
|
8
|
+
{(groupIdContext: string) => {
|
|
9
|
+
// eslint-disable-next-line react/display-name
|
|
10
|
+
const propsGroupId = groupId || null;
|
|
11
|
+
const providedGroupId = propsGroupId || groupIdContext;
|
|
12
|
+
|
|
13
|
+
return <Component {...props} groupId={providedGroupId} />;
|
|
14
|
+
}}
|
|
15
|
+
</FocusableGroupContext.Consumer>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
3
|
+
|
|
4
|
+
export const ScreenDataContext = React.createContext<any>(null);
|
|
5
|
+
|
|
6
|
+
// Use this only to provide initial screenData context, before the Transitioner and Screen is rendered.
|
|
7
|
+
export const withScreenDataContextProvider = (Component: any) => {
|
|
8
|
+
return function ScreenDataContextProvider(props: any) {
|
|
9
|
+
const { activeRiver } = useNavigation();
|
|
10
|
+
|
|
11
|
+
// use only initial activeRiver as this context should only be used for "Home", initial route
|
|
12
|
+
const screenData = React.useMemo(() => ({ screen: activeRiver }), []);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ScreenDataContext.Provider value={screenData}>
|
|
16
|
+
<Component {...props} />
|
|
17
|
+
</ScreenDataContext.Provider>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -5,18 +5,18 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
|
5
5
|
|
|
6
6
|
type ComponentProps = {
|
|
7
7
|
component: {
|
|
8
|
-
id: string
|
|
9
|
-
rules: { item_limit: number
|
|
10
|
-
component_type: string
|
|
8
|
+
id: string;
|
|
9
|
+
rules: { item_limit: number; component_cells_selectable: boolean };
|
|
10
|
+
component_type: string;
|
|
11
11
|
styles: {
|
|
12
|
-
cell_style: string
|
|
13
|
-
header: { visible: boolean }
|
|
14
|
-
component_cells_selectable: boolean
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
zappPipesData: { url: string
|
|
18
|
-
selected: boolean
|
|
19
|
-
assets: { menu_button: string }
|
|
12
|
+
cell_style: string;
|
|
13
|
+
header: { visible: boolean };
|
|
14
|
+
component_cells_selectable: boolean;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
zappPipesData: { url: string; data: { title: string } };
|
|
18
|
+
selected: boolean;
|
|
19
|
+
assets: { menu_button: string };
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
function withAnalytics(Component) {
|
package/README.md
CHANGED
|
@@ -78,17 +78,6 @@ export default MyAwesomeComponent;
|
|
|
78
78
|
export { MyAwesomeComponent } from "./MyAwesomeComponent";
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
We provide flow types for component props - please use it to make sure your component will be compliant
|
|
82
|
-
|
|
83
|
-
```javascript
|
|
84
|
-
import * as React from "react";
|
|
85
|
-
import type { ZappComponentProps } from "../../flow-types"; // in the root of the project
|
|
86
|
-
|
|
87
|
-
export class MyComponent extends React.Component<ZappComponentProps> {
|
|
88
|
-
/* ... */
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
81
|
## Connecting my component to Zapp Pipes
|
|
93
82
|
|
|
94
83
|
Zapp App components rely on [Zapp-Pipes](https://github.com/applicaster/zapp-pipes) to load data.
|
|
@@ -100,10 +89,9 @@ In order to connect your component to ZappPipes, you simply need to use the `Zap
|
|
|
100
89
|
import * as React from "react";
|
|
101
90
|
import { View, Text } from "react-native";
|
|
102
91
|
import { zappPipesDataConnector } from "../ZappPipesDataConnector";
|
|
103
|
-
import type { ZappComponentProps } from "../../flow-types";
|
|
104
92
|
|
|
105
93
|
@zappPipesDataConnector
|
|
106
|
-
export class MyComponent extends React.Component
|
|
94
|
+
export class MyComponent extends React.Component {
|
|
107
95
|
renderComponent = (data) => {
|
|
108
96
|
return (
|
|
109
97
|
<View>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.4354608902",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"redux-mock-store": "^1.5.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
38
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
39
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
40
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
37
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.4354608902",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4354608902",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.4354608902",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.4354608902",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|
|
File without changes
|
|
File without changes
|