@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4220424021 → 12.0.0-alpha.4223432180
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/Cell/Cell.tsx +8 -1
- package/Components/Focusable/__tests__/index.android.test.tsx +72 -0
- package/Components/Focusable/index.android.tsx +15 -9
- package/Components/FocusableList/FocusableChild.ts +2 -4
- package/Components/FocusableList/index.tsx +11 -12
- package/Components/FocusableScrollView/index.tsx +1 -1
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +6 -5
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +14 -8
- package/Components/Transitioner/Transitioner.tsx +13 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +5 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +2 -1
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +11 -3
- package/Components/VideoModal/PlayerDetails.tsx +16 -2
- package/Components/VideoModal/PlayerWrapper.tsx +40 -10
- package/Components/VideoModal/VideoModal.tsx +33 -27
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +56 -10
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -1
- package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
- package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
- package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
- package/Contexts/CachedDimensionsContext/index.ts +13 -9
- package/Contexts/ConfirmDialogState/index.ts +1 -1
- package/Contexts/ScreenContext/index.tsx +6 -1
- package/const.ts +6 -0
- package/index.js +3 -0
- package/package.json +5 -5
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -276,13 +276,20 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
276
276
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
277
277
|
>
|
|
278
278
|
{(focused, event) => {
|
|
279
|
+
const isFocused = this.isCellFocused(focused);
|
|
280
|
+
|
|
281
|
+
if (isFocused) {
|
|
282
|
+
const accessibilityManager = AccessibilityManager.getInstance();
|
|
283
|
+
accessibilityManager.readText({ text: item.title });
|
|
284
|
+
}
|
|
285
|
+
|
|
279
286
|
return (
|
|
280
287
|
<FocusableCell
|
|
281
288
|
{...{
|
|
282
289
|
index,
|
|
283
290
|
CellRenderer,
|
|
284
291
|
item,
|
|
285
|
-
focused:
|
|
292
|
+
focused: isFocused,
|
|
286
293
|
scrollTo: this.scrollToIndex(event),
|
|
287
294
|
behavior,
|
|
288
295
|
}}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, act } from "@testing-library/react-native";
|
|
3
|
+
import { Touchable } from "../../Touchable";
|
|
4
|
+
|
|
5
|
+
const mockUseIsRTL = jest.fn();
|
|
6
|
+
|
|
7
|
+
jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
8
|
+
useIsRTL: mockUseIsRTL,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const mockUseFocusManager = jest.fn();
|
|
12
|
+
|
|
13
|
+
jest.mock("@applicaster/zapp-react-native-utils/focusManager", () => ({
|
|
14
|
+
useFocusManager: mockUseFocusManager,
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const mockUsePrevious = jest.fn();
|
|
18
|
+
|
|
19
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/utils", () => ({
|
|
20
|
+
usePrevious: mockUsePrevious,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const { Focusable } = require("../index.android");
|
|
24
|
+
|
|
25
|
+
describe("Focusable", () => {
|
|
26
|
+
const mockFocusManager = {
|
|
27
|
+
isFocused: jest.fn(),
|
|
28
|
+
onDisableFocusChange: jest.fn(),
|
|
29
|
+
registerFocusable: jest.fn(),
|
|
30
|
+
focusedId: "test-id",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
36
|
+
mockUseFocusManager.mockReturnValue(mockFocusManager);
|
|
37
|
+
mockUsePrevious.mockReturnValue(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("updates disableFocus state when disableFocus prop changes", () => {
|
|
41
|
+
const { rerender } = render(
|
|
42
|
+
<Focusable id="test-id" disableFocus={false}>
|
|
43
|
+
<Touchable testID="touchable" />
|
|
44
|
+
</Focusable>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
rerender(
|
|
48
|
+
<Focusable id="test-id" disableFocus={true}>
|
|
49
|
+
<Touchable testID="touchable" />
|
|
50
|
+
</Focusable>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(mockFocusManager.onDisableFocusChange).toHaveBeenCalledWith(
|
|
54
|
+
"test-id"
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("calls focusManager.registerFocusable on mount and unregisters on unmount", () => {
|
|
59
|
+
const unregister = jest.fn();
|
|
60
|
+
mockFocusManager.registerFocusable.mockReturnValue(unregister);
|
|
61
|
+
|
|
62
|
+
const { unmount } = render(
|
|
63
|
+
<Focusable id="test-id">
|
|
64
|
+
<Touchable testID="touchable" />
|
|
65
|
+
</Focusable>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(mockFocusManager.registerFocusable).toHaveBeenCalled();
|
|
69
|
+
act(() => unmount());
|
|
70
|
+
expect(unregister).toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -128,7 +128,10 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
128
128
|
|
|
129
129
|
const _onBlur = React.useCallback(
|
|
130
130
|
(ref, options = {}) => {
|
|
131
|
-
|
|
131
|
+
if (ref.props.id !== focusManager.focusedId) {
|
|
132
|
+
setFocused(false);
|
|
133
|
+
}
|
|
134
|
+
|
|
132
135
|
onBlur?.(ref, options);
|
|
133
136
|
},
|
|
134
137
|
[onBlur]
|
|
@@ -148,15 +151,14 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
148
151
|
[isRTL, nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight]
|
|
149
152
|
);
|
|
150
153
|
|
|
151
|
-
const contextState = React.useMemo(
|
|
152
|
-
|
|
154
|
+
const contextState = React.useMemo(() => {
|
|
155
|
+
return {
|
|
153
156
|
focused,
|
|
154
157
|
...parentFocus,
|
|
155
158
|
ref: touchableRef,
|
|
156
159
|
setIsFocusable,
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
);
|
|
160
|
+
};
|
|
161
|
+
}, [parentFocus, focused]);
|
|
160
162
|
|
|
161
163
|
return (
|
|
162
164
|
<Touchable
|
|
@@ -173,9 +175,13 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
173
175
|
{...parentFocus}
|
|
174
176
|
>
|
|
175
177
|
<FocusableContext.Provider value={contextState}>
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
{React.useMemo(
|
|
179
|
+
() =>
|
|
180
|
+
typeof children === "function"
|
|
181
|
+
? children(focused, parentFocus, touchableRef)
|
|
182
|
+
: children,
|
|
183
|
+
[children, focused, parentFocus]
|
|
184
|
+
)}
|
|
179
185
|
</FocusableContext.Provider>
|
|
180
186
|
</Touchable>
|
|
181
187
|
);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { isEqual } from "@applicaster/zapp-react-native-utils/equalUtils";
|
|
3
3
|
import { useFocusable } from "../Focusable/index.android";
|
|
4
|
-
import { useCellState } from "./hooks/useCellState.android";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* returns parent focus from prop or from context
|
|
@@ -30,15 +29,14 @@ const useParentFocus = (
|
|
|
30
29
|
);
|
|
31
30
|
|
|
32
31
|
function FocusableChildComponent(props) {
|
|
33
|
-
const { setIsFocusable, ...focusableContext } = useFocusable();
|
|
32
|
+
const { setIsFocusable, focused, ...focusableContext } = useFocusable();
|
|
33
|
+
|
|
34
34
|
const parentFocus = useParentFocus(props, focusableContext);
|
|
35
35
|
|
|
36
36
|
const onLoadFailed = React.useCallback(() => {
|
|
37
37
|
setIsFocusable(false);
|
|
38
38
|
}, []);
|
|
39
39
|
|
|
40
|
-
const focused = useCellState(props.id);
|
|
41
|
-
|
|
42
40
|
return props.renderItem({
|
|
43
41
|
...props,
|
|
44
42
|
focused,
|
|
@@ -88,6 +88,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
88
88
|
data = [],
|
|
89
89
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
90
90
|
onAllComponentsLoaded, // TODO: re-implement it
|
|
91
|
+
omitPropsPropagation = [],
|
|
91
92
|
} = props;
|
|
92
93
|
|
|
93
94
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -252,9 +253,9 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
252
253
|
]
|
|
253
254
|
);
|
|
254
255
|
|
|
255
|
-
const
|
|
256
|
-
(
|
|
257
|
-
|
|
256
|
+
const getFlatListProps = React.useCallback(
|
|
257
|
+
R.omit(
|
|
258
|
+
[
|
|
258
259
|
"onListElementFocus",
|
|
259
260
|
"onListElementPress",
|
|
260
261
|
"onListElementPressOut",
|
|
@@ -267,17 +268,17 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
267
268
|
"focusableItemProps",
|
|
268
269
|
"renderItem",
|
|
269
270
|
"extraChildrenData",
|
|
270
|
-
"extraData",
|
|
271
|
-
"keyExtractor",
|
|
272
271
|
"onAllComponentsLoaded",
|
|
273
272
|
"focused",
|
|
274
273
|
"id",
|
|
275
274
|
"initialFocusDirection",
|
|
276
275
|
"withStateMemory",
|
|
277
276
|
"useSequentialLoading",
|
|
278
|
-
...
|
|
279
|
-
]
|
|
280
|
-
|
|
277
|
+
...omitPropsPropagation,
|
|
278
|
+
],
|
|
279
|
+
R.__
|
|
280
|
+
),
|
|
281
|
+
[omitPropsPropagation]
|
|
281
282
|
);
|
|
282
283
|
|
|
283
284
|
const onEndReached = React.useCallback(
|
|
@@ -289,7 +290,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
289
290
|
|
|
290
291
|
const initialNumToRender = toFiniteNumberWithDefault(
|
|
291
292
|
10,
|
|
292
|
-
|
|
293
|
+
props.initialNumToRender
|
|
293
294
|
);
|
|
294
295
|
|
|
295
296
|
return (
|
|
@@ -298,12 +299,10 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
298
299
|
<FlatList
|
|
299
300
|
focusable={false}
|
|
300
301
|
scrollEnabled={false}
|
|
301
|
-
extraData={props.extraData}
|
|
302
302
|
ref={ref}
|
|
303
|
-
{...
|
|
303
|
+
{...getFlatListProps(props)}
|
|
304
304
|
renderItem={renderItem}
|
|
305
305
|
onEndReached={onEndReached}
|
|
306
|
-
keyExtractor={props.keyExtractor}
|
|
307
306
|
initialNumToRender={initialNumToRender}
|
|
308
307
|
/>
|
|
309
308
|
</ChildrenFocusDeactivatorView>
|
|
@@ -5,6 +5,7 @@ import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/acti
|
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
7
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
8
|
+
import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
|
|
8
9
|
|
|
9
10
|
const { Logger } = getXray();
|
|
10
11
|
|
|
@@ -44,6 +45,11 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
44
45
|
|
|
45
46
|
const actionContext = useActions(pluginIdentifier);
|
|
46
47
|
|
|
48
|
+
const accessibilityManager = useAccessibilityManager({});
|
|
49
|
+
|
|
50
|
+
const { ttsLabel = "" } =
|
|
51
|
+
actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
|
|
52
|
+
|
|
47
53
|
const onPress = (event) => {
|
|
48
54
|
event?.preventDefault?.();
|
|
49
55
|
|
|
@@ -88,6 +94,12 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
88
94
|
mouse: focusable.mouse,
|
|
89
95
|
});
|
|
90
96
|
});
|
|
97
|
+
|
|
98
|
+
if (ttsLabel) {
|
|
99
|
+
accessibilityManager.readText({
|
|
100
|
+
text: ttsLabel,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
91
103
|
};
|
|
92
104
|
|
|
93
105
|
const handleBlur = (_focusable, _direction) => {
|
|
@@ -38,21 +38,22 @@ function Image({
|
|
|
38
38
|
|
|
39
39
|
const shouldRenderImg = source && !error;
|
|
40
40
|
|
|
41
|
+
// Default placeholder image fallback is empty string because it won't rerender
|
|
42
|
+
// in case of undefined or {uri: undefined} source
|
|
43
|
+
// https://github.com/facebook/react-native/issues/9195
|
|
41
44
|
const defaultPlaceHolderImage = React.useMemo(
|
|
42
45
|
() => ({ uri: placeholderImage || "" }),
|
|
43
46
|
[source, error]
|
|
44
47
|
);
|
|
45
48
|
|
|
46
|
-
const _source = shouldRenderImg
|
|
47
|
-
? withDimensions(source)
|
|
48
|
-
: defaultPlaceHolderImage;
|
|
49
|
-
|
|
50
49
|
return (
|
|
51
50
|
// @ts-ignore
|
|
52
51
|
<MemoizedImage
|
|
53
52
|
style={style as ImageStyle}
|
|
54
53
|
onError={() => setErrorState(true)}
|
|
55
|
-
source={
|
|
54
|
+
source={
|
|
55
|
+
shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
|
|
56
|
+
}
|
|
56
57
|
{...R.omit(["source"], otherProps)}
|
|
57
58
|
/>
|
|
58
59
|
);
|
|
@@ -31,10 +31,10 @@ function Image({
|
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<RnImage
|
|
34
|
-
defaultSource={placeholderImage ||
|
|
34
|
+
defaultSource={placeholderImage || null}
|
|
35
35
|
style={style}
|
|
36
36
|
source={updatedSource}
|
|
37
|
-
{...R.omit(["source"], otherProps)}
|
|
37
|
+
{...R.omit(["source", "placeholderImage"], otherProps)}
|
|
38
38
|
/>
|
|
39
39
|
);
|
|
40
40
|
}
|
|
@@ -362,13 +362,15 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
362
362
|
const toggleFullscreen = (event) => {
|
|
363
363
|
const { fullscreen = false } = event || {};
|
|
364
364
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
if (fullscreen) {
|
|
367
|
+
navigator.fullscreenVideoModal();
|
|
368
|
+
playerEvent("onFullscreenPlayerWillPresent");
|
|
369
|
+
} else {
|
|
370
|
+
navigator.maximiseVideoModal();
|
|
371
|
+
playerEvent("onFullscreenPlayerWillDismiss");
|
|
372
|
+
}
|
|
373
|
+
});
|
|
372
374
|
};
|
|
373
375
|
|
|
374
376
|
const onCellTap = (entry) => {
|
|
@@ -463,6 +465,10 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
463
465
|
|
|
464
466
|
if (mode === VideoModalMode.FULLSCREEN) {
|
|
465
467
|
toggleFullscreen({ fullscreen: false });
|
|
468
|
+
|
|
469
|
+
if (!isModal) {
|
|
470
|
+
playerManager.closeNativePlayer();
|
|
471
|
+
}
|
|
466
472
|
}
|
|
467
473
|
|
|
468
474
|
return !!(
|
|
@@ -519,7 +525,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
519
525
|
}
|
|
520
526
|
|
|
521
527
|
return () => {
|
|
522
|
-
playerEvent("player_did_close");
|
|
528
|
+
playerEvent("player_did_close", { item });
|
|
523
529
|
|
|
524
530
|
if (!isModal) {
|
|
525
531
|
showNavBar(true);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import { update, compose, tail, append, take, identity } from "ramda";
|
|
3
|
+
import { update, compose, tail, append, take, identity, isNil } from "ramda";
|
|
4
4
|
|
|
5
5
|
import { AnimationManager } from "./AnimationManager";
|
|
6
6
|
import { Scene } from "./Scene";
|
|
@@ -50,6 +50,10 @@ function scenesForBackTransition(props: SceneProps, { scenes }) {
|
|
|
50
50
|
: [prepareScene(props.children), scenes[0]];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
const isModalClosed = (navigator) => {
|
|
54
|
+
return !!isNil(navigator?.modalData);
|
|
55
|
+
};
|
|
56
|
+
|
|
53
57
|
type Props = {
|
|
54
58
|
transitionConfig: any;
|
|
55
59
|
children: React.ReactNode;
|
|
@@ -313,7 +317,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
313
317
|
<Scene
|
|
314
318
|
key={scenes[from.index].key}
|
|
315
319
|
pathname={scenes[from.index].key}
|
|
316
|
-
isActive={
|
|
320
|
+
isActive={
|
|
321
|
+
scenes[from.index].key === this.props.navigator.currentRoute &&
|
|
322
|
+
isModalClosed(this.props.navigator)
|
|
323
|
+
}
|
|
317
324
|
style={from.style}
|
|
318
325
|
pointerEvents="none"
|
|
319
326
|
overlayStyle={from.overlayStyle}
|
|
@@ -329,7 +336,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
329
336
|
const toScene = scenes[to.index] && (
|
|
330
337
|
<Scene
|
|
331
338
|
pathname={scenes[to.index].key}
|
|
332
|
-
isActive={
|
|
339
|
+
isActive={
|
|
340
|
+
scenes[to.index].key === this.props.navigator.currentRoute &&
|
|
341
|
+
isModalClosed(this.props.navigator)
|
|
342
|
+
}
|
|
333
343
|
key={scenes[to.index].key}
|
|
334
344
|
style={to.style}
|
|
335
345
|
overlayStyle={to.overlayStyle}
|
|
@@ -223,7 +223,8 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
223
223
|
(videoModalState.mode === "MAXIMIZED" &&
|
|
224
224
|
videoModalState.previousMode === "MINIMIZED" &&
|
|
225
225
|
previousItemId === videoModalState.item?.id) ||
|
|
226
|
-
previousItemId !== videoModalState.item?.id
|
|
226
|
+
(previousItemId !== videoModalState.item?.id &&
|
|
227
|
+
videoModalState.mode !== "FULLSCREEN")
|
|
227
228
|
) {
|
|
228
229
|
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
229
230
|
setTimeout(() => resetPlayerAnimationState());
|
|
@@ -60,7 +60,10 @@ export const AnimationView = ({
|
|
|
60
60
|
const {
|
|
61
61
|
width: screenWidth,
|
|
62
62
|
deviceInfo: { isTablet, isTabletLandscape },
|
|
63
|
-
} = useDimensions("window", {
|
|
63
|
+
} = useDimensions("window", {
|
|
64
|
+
deviceInfo: true,
|
|
65
|
+
updateForInactiveScreens: true,
|
|
66
|
+
});
|
|
64
67
|
|
|
65
68
|
const { videoModalState } = useNavigation();
|
|
66
69
|
const insets = useSafeAreaInsets();
|
|
@@ -301,13 +304,18 @@ export const AnimationView = ({
|
|
|
301
304
|
typeof additionalData.height === "number" && additionalData.height;
|
|
302
305
|
}
|
|
303
306
|
|
|
304
|
-
if (
|
|
307
|
+
if (
|
|
308
|
+
videoModalState.mode === "MAXIMIZED" &&
|
|
309
|
+
defaultValue.x !== screenWidth &&
|
|
310
|
+
width &&
|
|
311
|
+
height
|
|
312
|
+
) {
|
|
305
313
|
const value = { x: width, y: height };
|
|
306
314
|
setDefaultValue(value);
|
|
307
315
|
animatedValue.setValue(value);
|
|
308
316
|
}
|
|
309
317
|
}
|
|
310
|
-
}, [
|
|
318
|
+
}, [screenWidth]);
|
|
311
319
|
|
|
312
320
|
React.useEffect(() => {
|
|
313
321
|
if (
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
StyleProp,
|
|
4
|
+
ViewStyle,
|
|
5
|
+
Animated,
|
|
6
|
+
Easing,
|
|
7
|
+
Dimensions,
|
|
8
|
+
} from "react-native";
|
|
3
9
|
import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
4
10
|
import { ComponentsMap } from "@applicaster/zapp-react-native-ui-components/Components/River/ComponentsMap";
|
|
5
11
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
12
|
|
|
13
|
+
const { width: SCREEN_WIDTH } = Dimensions.get("screen");
|
|
14
|
+
|
|
7
15
|
type Configuration = {
|
|
8
16
|
[key: string]: any;
|
|
9
17
|
modal_background_color?: string;
|
|
@@ -15,6 +23,7 @@ type Props = {
|
|
|
15
23
|
configuration: Configuration;
|
|
16
24
|
isTabletLandscape: boolean;
|
|
17
25
|
isAudioPlayer?: boolean;
|
|
26
|
+
isTablet: boolean;
|
|
18
27
|
};
|
|
19
28
|
|
|
20
29
|
const containerStyle = ({
|
|
@@ -31,6 +40,7 @@ export const PlayerDetails = ({
|
|
|
31
40
|
configuration,
|
|
32
41
|
isTabletLandscape,
|
|
33
42
|
isAudioPlayer,
|
|
43
|
+
isTablet,
|
|
34
44
|
}: Props) => {
|
|
35
45
|
const screenData = useTargetScreenData(entry);
|
|
36
46
|
const insets = useSafeAreaInsets();
|
|
@@ -77,7 +87,11 @@ export const PlayerDetails = ({
|
|
|
77
87
|
transform: [{ translateY }],
|
|
78
88
|
opacity,
|
|
79
89
|
},
|
|
80
|
-
|
|
90
|
+
{
|
|
91
|
+
// workaround for avoid wrong text-height after going back to portrait rotation
|
|
92
|
+
// we don't see this view in landscape mode, so we are able to use fixed width from portrait mode
|
|
93
|
+
width: isTablet ? undefined : SCREEN_WIDTH,
|
|
94
|
+
},
|
|
81
95
|
]}
|
|
82
96
|
>
|
|
83
97
|
{screenData && (
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
ViewStyle,
|
|
8
8
|
} from "react-native";
|
|
9
9
|
import { Edge, SafeAreaView } from "react-native-safe-area-context";
|
|
10
|
-
|
|
11
10
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
12
11
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
12
|
import { PlayerDetails } from "./PlayerDetails";
|
|
@@ -23,6 +22,8 @@ import {
|
|
|
23
22
|
ComponentAnimationType,
|
|
24
23
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
25
24
|
|
|
25
|
+
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("screen");
|
|
26
|
+
|
|
26
27
|
type DimensionsT = {
|
|
27
28
|
width: number | string;
|
|
28
29
|
height: number | string | undefined;
|
|
@@ -69,10 +70,8 @@ const directionStyles = (isTabletLandscape: boolean): ViewStyle => {
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
const getScreenAspectRatio = () => {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const longEdge = Math.max(width, height);
|
|
75
|
-
const shortEdge = Math.min(width, height);
|
|
73
|
+
const longEdge = Math.max(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
74
|
+
const shortEdge = Math.min(SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
76
75
|
|
|
77
76
|
return longEdge / shortEdge;
|
|
78
77
|
};
|
|
@@ -125,10 +124,37 @@ const getTabletWidth = (
|
|
|
125
124
|
return Number(width) - sidebarWidth;
|
|
126
125
|
};
|
|
127
126
|
|
|
128
|
-
|
|
127
|
+
const getStyles = (baseStyle, isMobile, isPortrait) => {
|
|
128
|
+
if (isMobile && isPortrait) {
|
|
129
|
+
return { width: SCREEN_WIDTH, height: SCREEN_HEIGHT };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (isMobile && !isPortrait) {
|
|
133
|
+
return { width: SCREEN_HEIGHT, height: SCREEN_WIDTH };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return baseStyle;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const showDetails = (isMobile: boolean, docked: boolean): boolean => {
|
|
140
|
+
// for mobile we always show details. Mounting of it very heavy operation.
|
|
141
|
+
if (isMobile) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// workaround for tablets we need to mount/unmount in order to avoid PlayerDetails content dissappearing
|
|
146
|
+
// FIXME - find out the reason of dissapearing of content
|
|
147
|
+
if (docked) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const PlayerWrapperComponent = (props: Props) => {
|
|
129
155
|
const {
|
|
130
156
|
entry,
|
|
131
|
-
style,
|
|
157
|
+
style: baseStyle,
|
|
132
158
|
containerStyle,
|
|
133
159
|
inline,
|
|
134
160
|
docked,
|
|
@@ -143,6 +169,8 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
143
169
|
|
|
144
170
|
const isInlineModal = inline && isModal;
|
|
145
171
|
|
|
172
|
+
const style = getStyles(baseStyle, !isTablet, isInlineModal);
|
|
173
|
+
|
|
146
174
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
147
175
|
|
|
148
176
|
const tabletWidth = getTabletWidth(configuration, style);
|
|
@@ -224,8 +252,9 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
224
252
|
</AnimatedVideoPlayerComponent>
|
|
225
253
|
</AnimationComponent>
|
|
226
254
|
</View>
|
|
255
|
+
|
|
227
256
|
<AnimatedScrollModal>
|
|
228
|
-
{
|
|
257
|
+
{showDetails(!isTablet, docked) && (
|
|
229
258
|
<AnimationComponent
|
|
230
259
|
animationType={ComponentAnimationType.componentFade}
|
|
231
260
|
style={defaultStyles.flex}
|
|
@@ -235,10 +264,9 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
235
264
|
style={defaultStyles.playerDetails}
|
|
236
265
|
entry={entry}
|
|
237
266
|
isTabletLandscape={isTabletLandscape}
|
|
267
|
+
isTablet={isTablet}
|
|
238
268
|
/>
|
|
239
269
|
</AnimationComponent>
|
|
240
|
-
) : (
|
|
241
|
-
<View style={defaultStyles.playerDetails} />
|
|
242
270
|
)}
|
|
243
271
|
</AnimatedScrollModal>
|
|
244
272
|
</ScreenContextProvider>
|
|
@@ -249,3 +277,5 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
249
277
|
</PathnameContext.Provider>
|
|
250
278
|
);
|
|
251
279
|
};
|
|
280
|
+
|
|
281
|
+
export const PlayerWrapper = PlayerWrapperComponent;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import { StyleSheet, View, StatusBar } from "react-native";
|
|
4
4
|
|
|
5
5
|
import { HandlePlayable } from "@applicaster/zapp-react-native-ui-components/Components/HandlePlayable";
|
|
6
6
|
import {
|
|
@@ -129,32 +129,38 @@ const VideoModalComponent = () => {
|
|
|
129
129
|
const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${item?.id}`;
|
|
130
130
|
|
|
131
131
|
return (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
132
|
+
<>
|
|
133
|
+
{/* TODO: Workaround to avoid unnecessary UI effect when switching from portrait to fullscreen */}
|
|
134
|
+
<StatusBar hidden={false} />
|
|
135
|
+
{/* TODO: Workaround to avoid unnecessary UI effect when switching from portrait to fullscreen */}
|
|
136
|
+
|
|
137
|
+
<PathnameContext.Provider value={pathname}>
|
|
138
|
+
<ScreenContextProvider pathname={pathname}>
|
|
139
|
+
{itemIdHooksFinished === item?.id ? (
|
|
140
|
+
<AnimatedPlayerModalWrapper
|
|
141
|
+
style={[
|
|
142
|
+
styles.container,
|
|
143
|
+
{
|
|
144
|
+
backgroundColor,
|
|
145
|
+
},
|
|
146
|
+
]}
|
|
147
|
+
>
|
|
148
|
+
<HandlePlayable
|
|
149
|
+
item={item}
|
|
150
|
+
isModal={mode !== "PIP"}
|
|
151
|
+
modalHeight={modalSize.height}
|
|
152
|
+
modalWidth={modalSize.width}
|
|
153
|
+
mode={mode}
|
|
154
|
+
/>
|
|
155
|
+
</AnimatedPlayerModalWrapper>
|
|
156
|
+
) : (
|
|
157
|
+
<View style={styles.loaderContainer}>
|
|
158
|
+
<Spinner />
|
|
159
|
+
</View>
|
|
160
|
+
)}
|
|
161
|
+
</ScreenContextProvider>
|
|
162
|
+
</PathnameContext.Provider>
|
|
163
|
+
</>
|
|
158
164
|
);
|
|
159
165
|
};
|
|
160
166
|
|
|
@@ -8,6 +8,13 @@ const props = {
|
|
|
8
8
|
configuration: { modal_background_color: "transparent" },
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
|
|
12
|
+
useDimensions: jest.fn(() => ({
|
|
13
|
+
width: 20,
|
|
14
|
+
height: 30,
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
17
|
+
|
|
11
18
|
jest.mock("react-native-safe-area-context", () => ({
|
|
12
19
|
useSafeAreaInsets: jest.fn(() => ({
|
|
13
20
|
top: 20,
|
|
@@ -9,6 +9,7 @@ exports[`PlayerDetails renders properly 1`] = `
|
|
|
9
9
|
"flex": 1,
|
|
10
10
|
"marginTop": -8,
|
|
11
11
|
"paddingTop": -8,
|
|
12
|
+
"width": 750,
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
>
|
|
@@ -29,6 +30,7 @@ exports[`PlayerDetails renders properly on tablet in landscape orientation 1`] =
|
|
|
29
30
|
"flex": 1,
|
|
30
31
|
"marginTop": -20,
|
|
31
32
|
"paddingTop": 40,
|
|
33
|
+
"width": 750,
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
>
|
|
@@ -27,8 +27,8 @@ exports[`PlayerWrapper renders inline 1`] = `
|
|
|
27
27
|
"backgroundColor": "transparent",
|
|
28
28
|
},
|
|
29
29
|
Object {
|
|
30
|
-
"height":
|
|
31
|
-
"width":
|
|
30
|
+
"height": 1334,
|
|
31
|
+
"width": 750,
|
|
32
32
|
},
|
|
33
33
|
Object {},
|
|
34
34
|
]
|
|
@@ -91,6 +91,7 @@ exports[`PlayerWrapper renders inline 1`] = `
|
|
|
91
91
|
"id": "test",
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
isTablet={false}
|
|
94
95
|
isTabletLandscape={false}
|
|
95
96
|
style={
|
|
96
97
|
Object {
|
|
@@ -132,8 +133,8 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
|
|
|
132
133
|
"backgroundColor": "transparent",
|
|
133
134
|
},
|
|
134
135
|
Object {
|
|
135
|
-
"height":
|
|
136
|
-
"width":
|
|
136
|
+
"height": 1334,
|
|
137
|
+
"width": 750,
|
|
137
138
|
},
|
|
138
139
|
Object {},
|
|
139
140
|
]
|
|
@@ -177,13 +178,35 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
|
|
|
177
178
|
testID="test-player-container"
|
|
178
179
|
/>
|
|
179
180
|
<View
|
|
181
|
+
animationType="componentFade"
|
|
180
182
|
style={
|
|
181
183
|
Object {
|
|
182
184
|
"flex": 1,
|
|
183
|
-
"paddingTop": 20,
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
+
>
|
|
188
|
+
<View
|
|
189
|
+
configuration={
|
|
190
|
+
Object {
|
|
191
|
+
"tablet_landscape_player_container_background_color": "red",
|
|
192
|
+
"tablet_landscape_sidebar_width": "35%",
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
entry={
|
|
196
|
+
Object {
|
|
197
|
+
"id": "test",
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
isTablet={false}
|
|
201
|
+
isTabletLandscape={false}
|
|
202
|
+
style={
|
|
203
|
+
Object {
|
|
204
|
+
"flex": 1,
|
|
205
|
+
"paddingTop": 20,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/>
|
|
209
|
+
</View>
|
|
187
210
|
</View>
|
|
188
211
|
</RNCSafeAreaView>
|
|
189
212
|
</RNCSafeAreaProvider>
|
|
@@ -296,6 +319,7 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
|
|
|
296
319
|
"id": "test",
|
|
297
320
|
}
|
|
298
321
|
}
|
|
322
|
+
isTablet={true}
|
|
299
323
|
isTabletLandscape={true}
|
|
300
324
|
style={
|
|
301
325
|
Object {
|
|
@@ -337,8 +361,8 @@ exports[`PlayerWrapper renders properly 1`] = `
|
|
|
337
361
|
"backgroundColor": "transparent",
|
|
338
362
|
},
|
|
339
363
|
Object {
|
|
340
|
-
"height":
|
|
341
|
-
"width":
|
|
364
|
+
"height": 750,
|
|
365
|
+
"width": 1334,
|
|
342
366
|
},
|
|
343
367
|
Object {},
|
|
344
368
|
]
|
|
@@ -382,13 +406,35 @@ exports[`PlayerWrapper renders properly 1`] = `
|
|
|
382
406
|
testID="test-player-container"
|
|
383
407
|
/>
|
|
384
408
|
<View
|
|
409
|
+
animationType="componentFade"
|
|
385
410
|
style={
|
|
386
411
|
Object {
|
|
387
412
|
"flex": 1,
|
|
388
|
-
"paddingTop": 20,
|
|
389
413
|
}
|
|
390
414
|
}
|
|
391
|
-
|
|
415
|
+
>
|
|
416
|
+
<View
|
|
417
|
+
configuration={
|
|
418
|
+
Object {
|
|
419
|
+
"tablet_landscape_player_container_background_color": "red",
|
|
420
|
+
"tablet_landscape_sidebar_width": "35%",
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
entry={
|
|
424
|
+
Object {
|
|
425
|
+
"id": "test",
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
isTablet={false}
|
|
429
|
+
isTabletLandscape={false}
|
|
430
|
+
style={
|
|
431
|
+
Object {
|
|
432
|
+
"flex": 1,
|
|
433
|
+
"paddingTop": 20,
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/>
|
|
437
|
+
</View>
|
|
392
438
|
</View>
|
|
393
439
|
</RNCSafeAreaView>
|
|
394
440
|
</RNCSafeAreaProvider>
|
|
@@ -45,7 +45,10 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
|
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
return (
|
|
48
|
-
<SafeAreaView
|
|
48
|
+
<SafeAreaView
|
|
49
|
+
style={[style.view, isRTL ? style.rtlStyle : {}]}
|
|
50
|
+
testID="BarView-safeAreaView"
|
|
51
|
+
>
|
|
49
52
|
{backButton}
|
|
50
53
|
<BarTitle title={barState.title} screenStyles={screenStyles} />
|
|
51
54
|
{closeButton}
|
|
@@ -11,12 +11,16 @@ const renderEmptyView = () => {
|
|
|
11
11
|
return <View style={emptyViewStyle} />;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
type FloatingButtonProps = {
|
|
14
|
+
type FloatingButtonProps = Testable & {
|
|
15
15
|
onPress: () => void;
|
|
16
16
|
screenStyles: any;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
const BackButton = ({
|
|
19
|
+
const BackButton = ({
|
|
20
|
+
onPress,
|
|
21
|
+
screenStyles,
|
|
22
|
+
testID = "backButton",
|
|
23
|
+
}: FloatingButtonProps) => {
|
|
20
24
|
const containerStyle: any = {};
|
|
21
25
|
|
|
22
26
|
if (!onPress) {
|
|
@@ -25,6 +29,7 @@ const BackButton = ({ onPress, screenStyles }: FloatingButtonProps) => {
|
|
|
25
29
|
|
|
26
30
|
return (
|
|
27
31
|
<ActionButton
|
|
32
|
+
testID={`${testID}-actionButton`}
|
|
28
33
|
onPress={onPress}
|
|
29
34
|
buttonStyles={containerStyle}
|
|
30
35
|
imageUrl={screenStyles.back_button_image}
|
|
@@ -11,12 +11,16 @@ const renderEmptyView = () => {
|
|
|
11
11
|
return <View style={emptyViewStyle} />;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
type CloseButtonProps = {
|
|
14
|
+
type CloseButtonProps = Testable & {
|
|
15
15
|
onPress: () => void;
|
|
16
16
|
screenStyles?: any;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
const CloseButton = ({
|
|
19
|
+
const CloseButton = ({
|
|
20
|
+
onPress,
|
|
21
|
+
screenStyles,
|
|
22
|
+
testID = "closeButton",
|
|
23
|
+
}: CloseButtonProps) => {
|
|
20
24
|
const containerStyle: any = {};
|
|
21
25
|
|
|
22
26
|
if (!onPress) {
|
|
@@ -25,6 +29,7 @@ const CloseButton = ({ onPress, screenStyles }: CloseButtonProps) => {
|
|
|
25
29
|
|
|
26
30
|
return (
|
|
27
31
|
<ActionButton
|
|
32
|
+
testID={`${testID}-actionButton`}
|
|
28
33
|
onPress={onPress}
|
|
29
34
|
buttonStyles={containerStyle}
|
|
30
35
|
imageUrl={screenStyles.close_button_image}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
3
|
+
import { fireEvent } from "@testing-library/react-native";
|
|
4
|
+
|
|
5
|
+
const mockUseIsRTL = jest.fn(() => true);
|
|
6
|
+
|
|
7
|
+
jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
8
|
+
useIsRTL: mockUseIsRTL,
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const BarView = require("../BarView").default;
|
|
12
|
+
|
|
13
|
+
describe("BarView", () => {
|
|
14
|
+
const screenStyles = {
|
|
15
|
+
title_font_color: "#000",
|
|
16
|
+
title_font_android: "Roboto",
|
|
17
|
+
title_font_ios: "San Francisco",
|
|
18
|
+
title_font_size: "16",
|
|
19
|
+
background_color: "#fff",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const barState = {
|
|
23
|
+
backHandler: jest.fn(),
|
|
24
|
+
closeHandler: jest.fn(),
|
|
25
|
+
title: "Test Title",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
jest.clearAllMocks();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("renders without crashing", () => {
|
|
33
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
34
|
+
|
|
35
|
+
const { getByText } = renderWithProviders(
|
|
36
|
+
<BarView screenStyles={screenStyles} barState={barState} />
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
expect(getByText("Test Title")).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("applies RTL styles when isRTL is true", () => {
|
|
43
|
+
mockUseIsRTL.mockReturnValue(true);
|
|
44
|
+
|
|
45
|
+
const { getByTestId } = renderWithProviders(
|
|
46
|
+
<BarView screenStyles={screenStyles} barState={barState} />
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(getByTestId("BarView-safeAreaView").props.style).toContainEqual({
|
|
50
|
+
transform: [{ scaleX: -1 }],
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("does not apply RTL styles when isRTL is false", () => {
|
|
55
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
56
|
+
|
|
57
|
+
const { getByTestId } = renderWithProviders(
|
|
58
|
+
<BarView screenStyles={screenStyles} barState={barState} />
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(getByTestId("BarView-safeAreaView").props.style).not.toContainEqual({
|
|
62
|
+
transform: [{ scaleX: -1 }],
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("calls closeHandler when CloseButton is pressed", () => {
|
|
67
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
68
|
+
|
|
69
|
+
const { getByTestId } = renderWithProviders(
|
|
70
|
+
<BarView screenStyles={screenStyles} barState={barState} />
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
fireEvent.press(getByTestId("closeButton-actionButton-touchable"));
|
|
74
|
+
expect(barState.closeHandler).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("calls backHandler when BackButton is pressed", () => {
|
|
78
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
79
|
+
|
|
80
|
+
const { getByTestId } = renderWithProviders(
|
|
81
|
+
<BarView screenStyles={screenStyles} barState={barState} />
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
fireEvent.press(getByTestId("backButton-actionButton-touchable"));
|
|
85
|
+
expect(barState.backHandler).toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -28,7 +28,7 @@ styles: {
|
|
|
28
28
|
}
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
type ActionButtonProps = {
|
|
31
|
+
type ActionButtonProps = Testable & {
|
|
32
32
|
onPress: () => void;
|
|
33
33
|
buttonStyles: any;
|
|
34
34
|
imageUrl: string;
|
|
@@ -46,11 +46,16 @@ const ActionButton = ({
|
|
|
46
46
|
buttonStyles,
|
|
47
47
|
imageUrl,
|
|
48
48
|
imageStyle = closeButtonStyle,
|
|
49
|
+
testID,
|
|
49
50
|
}: ActionButtonProps) => {
|
|
50
51
|
return (
|
|
51
|
-
<View style={buttonStyles}>
|
|
52
|
-
<TouchableOpacity onPress={onPress}>
|
|
53
|
-
<Image
|
|
52
|
+
<View style={buttonStyles} testID={testID}>
|
|
53
|
+
<TouchableOpacity onPress={onPress} testID={`${testID}-touchable`}>
|
|
54
|
+
<Image
|
|
55
|
+
source={{ uri: imageUrl }}
|
|
56
|
+
style={imageStyle}
|
|
57
|
+
testID={`${testID}-image`}
|
|
58
|
+
/>
|
|
54
59
|
</TouchableOpacity>
|
|
55
60
|
</View>
|
|
56
61
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { create, useStore } from "zustand";
|
|
2
2
|
import { produce } from "immer";
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
3
4
|
|
|
4
5
|
type Dimensions = {
|
|
5
6
|
width: Option<number>;
|
|
@@ -31,16 +32,19 @@ export const useCachedDimensions = (id: string) => {
|
|
|
31
32
|
dimensionsStore
|
|
32
33
|
) as DimensionsState;
|
|
33
34
|
|
|
34
|
-
const getCachedDimensions = () => {
|
|
35
|
+
const getCachedDimensions = useCallback(() => {
|
|
35
36
|
return dimensions[id] || initialDimensions();
|
|
36
|
-
};
|
|
37
|
+
}, [dimensions?.[id], id]);
|
|
37
38
|
|
|
38
|
-
const handleSetCachedDimensions = (newDimensions) => {
|
|
39
|
+
const handleSetCachedDimensions = useCallback((newDimensions) => {
|
|
39
40
|
setCachedDimensions(id, newDimensions);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return useMemo(
|
|
44
|
+
() => ({
|
|
45
|
+
getCachedDimensions,
|
|
46
|
+
setCachedDimensions: handleSetCachedDimensions,
|
|
47
|
+
}),
|
|
48
|
+
[getCachedDimensions, handleSetCachedDimensions]
|
|
49
|
+
);
|
|
46
50
|
};
|
|
@@ -2,7 +2,7 @@ import { createStore } from "zustand/vanilla";
|
|
|
2
2
|
import { useStore } from "zustand";
|
|
3
3
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
4
4
|
|
|
5
|
-
interface ConfirmationDialogState {
|
|
5
|
+
export interface ConfirmationDialogState {
|
|
6
6
|
isDialogVisible: boolean;
|
|
7
7
|
messages: string;
|
|
8
8
|
confirmAction: () => void;
|
|
@@ -177,7 +177,12 @@ export function withScreenContext(Component: React.ComponentType<any>) {
|
|
|
177
177
|
return function WithScreenContextWrapper(props) {
|
|
178
178
|
return (
|
|
179
179
|
<ScreenContext.Consumer>
|
|
180
|
-
{(
|
|
180
|
+
{useCallback(
|
|
181
|
+
(value) => (
|
|
182
|
+
<Component {...props} screenContext={value} />
|
|
183
|
+
),
|
|
184
|
+
[Component, props]
|
|
185
|
+
)}
|
|
181
186
|
</ScreenContext.Consumer>
|
|
182
187
|
);
|
|
183
188
|
};
|
package/const.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ViewStyle } from "react-native";
|
|
2
|
+
|
|
1
3
|
export const tvPluginsWithCellRenderer = [
|
|
2
4
|
"group-qb",
|
|
3
5
|
"gallery-qb",
|
|
@@ -5,3 +7,7 @@ export const tvPluginsWithCellRenderer = [
|
|
|
5
7
|
"hero-qb",
|
|
6
8
|
"list-qb",
|
|
7
9
|
];
|
|
10
|
+
|
|
11
|
+
// Can't be used in StyleSheet.create, need to be inline/defined as a constant
|
|
12
|
+
// https://github.com/necolas/react-native-web/issues/1427
|
|
13
|
+
export const flatListOverflowStyle: ViewStyle = { overflow: "visible" };
|
package/index.js
CHANGED
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.4223432180",
|
|
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.4223432180",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4223432180",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.4223432180",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.4223432180",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|