@applicaster/zapp-react-native-ui-components 16.0.0-rc.8 → 16.0.0-rc.80
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/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
- package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
- package/Components/AudioPlayer/tv/index.tsx +5 -1
- package/Components/Cell/Cell.tsx +3 -6
- package/Components/Cell/TvOSCellComponent.tsx +0 -1
- package/Components/CellRendererResolver/index.ts +2 -2
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
- package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +39 -0
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
- package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
- package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
- package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
- package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
- package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
- package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
- package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
- package/Components/GeneralContentScreen/index.ts +2 -0
- package/Components/Layout/FullWidthRow.tsx +38 -0
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +16 -5
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
- package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
- package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
- package/Components/MasterCell/dataAdapter.ts +15 -5
- package/Components/MasterCell/hooks/index.ts +2 -0
- package/Components/MasterCell/hooks/usePressedState.ts +4 -0
- package/Components/MasterCell/index.tsx +30 -5
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
- package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
- package/Components/MasterCell/utils/index.ts +85 -46
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +54 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +21 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +58 -0
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +314 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +395 -0
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +763 -0
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +653 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +874 -0
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +11 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +199 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +383 -42
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +142 -0
- package/Components/ModalComponent/SortableList.web.tsx +34 -0
- package/Components/ModalComponent/TextInputContent.tsx +100 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
- package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +11 -0
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +43 -0
- package/Components/ModalComponent/utils.ts +76 -20
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
- package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
- package/Components/OfflineHandler/hooks.ts +123 -0
- package/Components/OfflineHandler/index.tsx +51 -73
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +25 -17
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +2 -2
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +3 -15
- package/Components/Screen/index.tsx +8 -4
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +20 -3
- package/Components/TopCutoffOverlay/index.tsx +2 -2
- package/Components/Transitioner/Transitioner.tsx +28 -17
- package/Components/VideoLive/LiveImageManager.ts +1 -1
- package/Components/VideoModal/utils.ts +6 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
- package/Contexts/CachedDimensionsContext/index.ts +17 -2
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/index.js +0 -39
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/package.json +6 -5
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
- package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
- package/Components/Screen/utils.ts +0 -16
- package/Helpers/Analytics/index.js +0 -95
- /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
- /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
- /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
2
|
import { PressableView } from "../../PressableView";
|
|
3
|
+
import { usePressedState } from "../../../hooks";
|
|
3
4
|
|
|
4
5
|
import { ActionButtonController } from "../../ActionButtonsCore/components";
|
|
5
6
|
|
|
@@ -20,7 +21,137 @@ const isValidElement = (
|
|
|
20
21
|
): child is React.ReactElement<ChildElementProps> =>
|
|
21
22
|
React.isValidElement(child);
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
type ActionButtonContentProps = {
|
|
25
|
+
style: any;
|
|
26
|
+
children: React.ReactNode;
|
|
27
|
+
action: any;
|
|
28
|
+
focusedStyles: any;
|
|
29
|
+
entry: any;
|
|
30
|
+
props: Record<string, any>;
|
|
31
|
+
actionContext: any;
|
|
32
|
+
actionState: any;
|
|
33
|
+
isActive: boolean;
|
|
34
|
+
onPress: () => any;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const ActionButtonContent = ({
|
|
38
|
+
children,
|
|
39
|
+
action,
|
|
40
|
+
entry,
|
|
41
|
+
actionContext,
|
|
42
|
+
actionState,
|
|
43
|
+
isActive,
|
|
44
|
+
}: ActionButtonContentProps) => {
|
|
45
|
+
const isPressed = usePressedState();
|
|
46
|
+
|
|
47
|
+
const supportsEntryState =
|
|
48
|
+
typeof actionContext?.initialEntryState === "function";
|
|
49
|
+
|
|
50
|
+
const shouldRenderAsset = Boolean(
|
|
51
|
+
supportsEntryState ? actionState?.mobileButtonAssets : false
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const shouldRenderLabel = Boolean(
|
|
55
|
+
supportsEntryState && resolveLabelText(actionState?.label)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const _cloneChildrenWithState = useCallback(
|
|
59
|
+
(nodes?: React.ReactNode): React.ReactNode => {
|
|
60
|
+
return React.Children.map(nodes, (child) => {
|
|
61
|
+
if (!isValidElement(child)) {
|
|
62
|
+
return child;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const role = child.props.mobileActionRole;
|
|
66
|
+
|
|
67
|
+
const nextChildren = _cloneChildrenWithState(child.props.children);
|
|
68
|
+
|
|
69
|
+
// Prevents of the asset rendering when the action doesn't provide asset for current entry state
|
|
70
|
+
if (role === "asset" && !shouldRenderAsset) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Prevents of the label rendering when the action doesn't provide label for current entry state.
|
|
75
|
+
// Also prevents of the label container when it doesn't have children to avoid unnecessary empty space.
|
|
76
|
+
if (role === "label" && !shouldRenderLabel) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Prevents of the label container rendering when it doesn't have children to avoid unnecessary empty space.
|
|
81
|
+
if (
|
|
82
|
+
role === "label_container" &&
|
|
83
|
+
React.Children.count(nextChildren) === 0
|
|
84
|
+
) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const nextProps: Partial<ChildElementProps> = {};
|
|
89
|
+
|
|
90
|
+
// Inject asset or uri to Asset component with role asset
|
|
91
|
+
if (role === "asset") {
|
|
92
|
+
const resolvedAsset = selectByAssetFlavour(
|
|
93
|
+
actionState,
|
|
94
|
+
action.flavour,
|
|
95
|
+
isActive
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (typeof resolvedAsset === "function") {
|
|
99
|
+
const AssetComponent = resolvedAsset as CellActionAssetComponent;
|
|
100
|
+
|
|
101
|
+
nextProps.asset = (
|
|
102
|
+
<AssetComponent
|
|
103
|
+
flavour={action.flavour || "flavour_1"}
|
|
104
|
+
width={action.width}
|
|
105
|
+
height={action.height}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
} else {
|
|
109
|
+
nextProps.uri = resolvedAsset;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Inject state and entry to Text component with role label
|
|
114
|
+
// Use isPressed state for mobile buttons to set focused state on mobile
|
|
115
|
+
if (role === "label") {
|
|
116
|
+
nextProps.state = isActive || isPressed ? "focused" : "default";
|
|
117
|
+
nextProps.entry = entry;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (nextChildren !== child.props.children) {
|
|
121
|
+
nextProps.children = nextChildren;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return React.cloneElement(child, nextProps);
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
[
|
|
128
|
+
shouldRenderAsset,
|
|
129
|
+
shouldRenderLabel,
|
|
130
|
+
actionState,
|
|
131
|
+
action.flavour,
|
|
132
|
+
action.width,
|
|
133
|
+
action.height,
|
|
134
|
+
isActive,
|
|
135
|
+
isPressed,
|
|
136
|
+
entry,
|
|
137
|
+
]
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (!shouldRenderAsset && !shouldRenderLabel) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return _cloneChildrenWithState(children);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const ActionButton = ({
|
|
148
|
+
style,
|
|
149
|
+
children,
|
|
150
|
+
action,
|
|
151
|
+
focusedStyles,
|
|
152
|
+
entry,
|
|
153
|
+
...props
|
|
154
|
+
}) => {
|
|
24
155
|
return (
|
|
25
156
|
<ActionButtonController
|
|
26
157
|
action={action}
|
|
@@ -31,105 +162,28 @@ export const ActionButton = ({ style, children, action, entry, ...props }) => {
|
|
|
31
162
|
);
|
|
32
163
|
}}
|
|
33
164
|
>
|
|
34
|
-
{(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return child;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const role = child.props.mobileActionRole;
|
|
55
|
-
|
|
56
|
-
const nextChildren = _cloneChildrenWithState(child.props.children);
|
|
57
|
-
|
|
58
|
-
// Prevents of the asset rendering when the action doesn't provide asset for current entry state
|
|
59
|
-
if (role === "asset" && !shouldRenderAsset) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Prevents of the label rendering when the action doesn't provide label for current entry state.
|
|
64
|
-
// Also prevents of the label container when it doesn't have children to avoid unnecessary empty space.
|
|
65
|
-
if (role === "label" && !shouldRenderLabel) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Prevents of the label container rendering when it doesn't have children to avoid unnecessary empty space.
|
|
70
|
-
if (
|
|
71
|
-
role === "label_container" &&
|
|
72
|
-
React.Children.count(nextChildren) === 0
|
|
73
|
-
) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const nextProps: Partial<ChildElementProps> = {};
|
|
78
|
-
|
|
79
|
-
// Inject asset or uri to Asset component with role asset
|
|
80
|
-
if (role === "asset") {
|
|
81
|
-
const resolvedAsset = selectByAssetFlavour(
|
|
82
|
-
actionState,
|
|
83
|
-
action.flavour,
|
|
84
|
-
isActive
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
if (typeof resolvedAsset === "function") {
|
|
88
|
-
const AssetComponent =
|
|
89
|
-
resolvedAsset as CellActionAssetComponent;
|
|
90
|
-
|
|
91
|
-
nextProps.asset = (
|
|
92
|
-
<AssetComponent
|
|
93
|
-
flavour={action.flavour || "flavour_1"}
|
|
94
|
-
width={action.width}
|
|
95
|
-
height={action.height}
|
|
96
|
-
/>
|
|
97
|
-
);
|
|
98
|
-
} else {
|
|
99
|
-
nextProps.uri = resolvedAsset;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Inject state and entry to Text component with role label
|
|
104
|
-
if (role === "label") {
|
|
105
|
-
nextProps.state = isActive ? "focused" : "default";
|
|
106
|
-
nextProps.entry = entry;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (nextChildren !== child.props.children) {
|
|
110
|
-
nextProps.children = nextChildren;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return React.cloneElement(child, nextProps);
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
if (!shouldRenderAsset && !shouldRenderLabel) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<PressableView
|
|
123
|
-
testID={props.testID || `${entry?.id}`}
|
|
124
|
-
style={isActive ? { ...style, ...props.focusedStyles } : style}
|
|
125
|
-
onPress={onPress}
|
|
126
|
-
accessibilityLabel={props.accessibilityLabel || `${entry?.id}`}
|
|
127
|
-
accessibilityHint={props.accessibilityHint}
|
|
165
|
+
{(renderProps) => (
|
|
166
|
+
<PressableView
|
|
167
|
+
testOnly_pressed={props.testOnly_pressed}
|
|
168
|
+
testID={props.testID || `${entry?.id}`}
|
|
169
|
+
style={style}
|
|
170
|
+
pressedStyle={focusedStyles}
|
|
171
|
+
onPress={renderProps.onPress}
|
|
172
|
+
accessibilityLabel={props.accessibilityLabel || `${entry?.id}`}
|
|
173
|
+
accessibilityHint={props.accessibilityHint}
|
|
174
|
+
>
|
|
175
|
+
<ActionButtonContent
|
|
176
|
+
style={style}
|
|
177
|
+
action={action}
|
|
178
|
+
focusedStyles={focusedStyles}
|
|
179
|
+
entry={entry}
|
|
180
|
+
props={props}
|
|
181
|
+
{...renderProps}
|
|
128
182
|
>
|
|
129
|
-
{
|
|
130
|
-
</
|
|
131
|
-
|
|
132
|
-
}
|
|
183
|
+
{children}
|
|
184
|
+
</ActionButtonContent>
|
|
185
|
+
</PressableView>
|
|
186
|
+
)}
|
|
133
187
|
</ActionButtonController>
|
|
134
188
|
);
|
|
135
189
|
};
|
package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { View } from "react-native";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
3
|
import { ImageContainer } from "../../ImageContainer";
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
@@ -10,13 +10,24 @@ type Props = {
|
|
|
10
10
|
cellUUID?: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
const styles = StyleSheet.create({
|
|
14
|
+
assetContainer: {
|
|
15
|
+
flexShrink: 0,
|
|
16
|
+
justifyContent: "center",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
13
21
|
export const AssetComponent = (props: Props & Record<string, unknown>) => {
|
|
14
22
|
return props.asset && React.isValidElement(props.asset) ? (
|
|
15
|
-
<View style={props.style} testID={props.testID}>
|
|
23
|
+
<View style={[styles.assetContainer, props.style]} testID={props.testID}>
|
|
16
24
|
{React.cloneElement(props.asset, { cellUUID: props.cellUUID })}
|
|
17
25
|
</View>
|
|
18
26
|
) : (
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
<ImageContainer
|
|
28
|
+
style={[styles.assetContainer, props.style]}
|
|
29
|
+
{...(props as any)}
|
|
30
|
+
uri={props.uri}
|
|
31
|
+
/>
|
|
21
32
|
);
|
|
22
33
|
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
toNumberWithDefault,
|
|
3
|
+
toNumberWithDefaultZero,
|
|
4
|
+
} from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
2
5
|
import { compact } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
3
6
|
|
|
4
7
|
import { Asset } from "./Asset";
|
|
@@ -10,23 +13,37 @@ import {
|
|
|
10
13
|
getPressableStyles,
|
|
11
14
|
getTextLabelStyles,
|
|
12
15
|
} from "./utils";
|
|
16
|
+
import { ViewStyle } from "react-native";
|
|
17
|
+
import { Spacer } from "./Spacer";
|
|
13
18
|
|
|
14
|
-
const displayModeStyle = (value) => {
|
|
19
|
+
const displayModeStyle = (value, isVertical: boolean) => {
|
|
15
20
|
const mode = value("display_mode") || "dynamic";
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
+
const defaultStyle = {
|
|
23
|
+
flexShrink: 1,
|
|
24
|
+
};
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
flex: 1,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
26
|
+
const width = toNumberWithDefault(140, value("width"));
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
switch (mode) {
|
|
29
|
+
case "fixed":
|
|
30
|
+
return {
|
|
31
|
+
...defaultStyle,
|
|
32
|
+
width,
|
|
33
|
+
maxWidth: width,
|
|
34
|
+
};
|
|
35
|
+
case "fill":
|
|
36
|
+
return {
|
|
37
|
+
...defaultStyle,
|
|
38
|
+
width: isVertical ? "100%" : undefined,
|
|
39
|
+
flex: !isVertical ? 1 : undefined,
|
|
40
|
+
};
|
|
41
|
+
case "dynamic":
|
|
42
|
+
default:
|
|
43
|
+
return {
|
|
44
|
+
...defaultStyle,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
30
47
|
};
|
|
31
48
|
|
|
32
49
|
type Props = {
|
|
@@ -34,7 +51,8 @@ type Props = {
|
|
|
34
51
|
value: Function;
|
|
35
52
|
stylePrefix: string;
|
|
36
53
|
specificPrefix: string;
|
|
37
|
-
spacingStyle:
|
|
54
|
+
spacingStyle: ViewStyle;
|
|
55
|
+
isVertical: boolean;
|
|
38
56
|
};
|
|
39
57
|
|
|
40
58
|
export const Button = ({
|
|
@@ -43,8 +61,9 @@ export const Button = ({
|
|
|
43
61
|
stylePrefix,
|
|
44
62
|
specificPrefix,
|
|
45
63
|
spacingStyle,
|
|
64
|
+
isVertical,
|
|
46
65
|
}: Props) => {
|
|
47
|
-
//
|
|
66
|
+
// Retrieves values depending to the slot
|
|
48
67
|
const getSlotBasedValue = (property: string) =>
|
|
49
68
|
value(`${specificPrefix}_${property}`);
|
|
50
69
|
|
|
@@ -68,21 +87,30 @@ export const Button = ({
|
|
|
68
87
|
const testID = `mobile_action_button_${index + 1}`;
|
|
69
88
|
const actionIdentifier = getSlotBasedValue("assign_action");
|
|
70
89
|
const assetAlignment = getValue("asset_alignment") || "left";
|
|
90
|
+
|
|
91
|
+
const hasHorizontalAlignment = ["left", "right"].includes(assetAlignment);
|
|
92
|
+
const vGutter = toNumberWithDefaultZero(getValue("vertical_gutter"));
|
|
93
|
+
const hGutter = toNumberWithDefaultZero(getValue("horizontal_gutter"));
|
|
71
94
|
const actionAssetFlavour = getValue("action_asset_flavour");
|
|
72
95
|
const contentsAlignment = getValue("contents_alignment") || "center";
|
|
96
|
+
const displayMode = getValue("display_mode") || "dynamic";
|
|
73
97
|
|
|
74
98
|
return {
|
|
75
99
|
type: "MobileActionButton",
|
|
76
100
|
style: {
|
|
77
|
-
|
|
78
|
-
alignContent: "center",
|
|
79
|
-
alignItems: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
80
|
-
justifyContent: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
101
|
+
// alignContent: "center", Why do we need this?
|
|
81
102
|
...getPressableStyles(getValue),
|
|
82
|
-
...displayModeStyle(getValue),
|
|
103
|
+
...displayModeStyle(getValue, isVertical),
|
|
83
104
|
...spacingStyle,
|
|
84
105
|
},
|
|
85
106
|
additionalProps: {
|
|
107
|
+
displayMode,
|
|
108
|
+
alignment: {
|
|
109
|
+
alignContent: "center",
|
|
110
|
+
flexDirection: getContentDirection(assetAlignment),
|
|
111
|
+
alignItems: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
112
|
+
justifyContent: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
113
|
+
},
|
|
86
114
|
action: {
|
|
87
115
|
identifier: actionIdentifier,
|
|
88
116
|
flavour: actionAssetFlavour,
|
|
@@ -102,7 +130,12 @@ export const Button = ({
|
|
|
102
130
|
testID,
|
|
103
131
|
})
|
|
104
132
|
: null,
|
|
105
|
-
|
|
133
|
+
Spacer({
|
|
134
|
+
enabled: assetEnabled && labelEnabled,
|
|
135
|
+
style: hasHorizontalAlignment
|
|
136
|
+
? { width: hGutter }
|
|
137
|
+
: { height: vGutter },
|
|
138
|
+
}),
|
|
106
139
|
labelEnabled
|
|
107
140
|
? TextLabelsContainer({
|
|
108
141
|
style: getTextLabelStyles(getValue),
|
|
@@ -114,7 +147,8 @@ export const Button = ({
|
|
|
114
147
|
color: getValue("focused_font_color"),
|
|
115
148
|
},
|
|
116
149
|
transformText: getValue("text_transform") || "default",
|
|
117
|
-
numberOfLines: getValue("number_of_lines"),
|
|
150
|
+
numberOfLines: getValue("number_of_lines") || 1,
|
|
151
|
+
ellipsizeMode: "tail",
|
|
118
152
|
},
|
|
119
153
|
actionIdentifier,
|
|
120
154
|
testID,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
type Props = {
|
|
2
2
|
enabled?: boolean;
|
|
3
|
+
style?: object;
|
|
3
4
|
};
|
|
4
5
|
|
|
5
|
-
export const Spacer = ({
|
|
6
|
+
export const Spacer = ({
|
|
7
|
+
enabled = false,
|
|
8
|
+
style = { flex: 1 },
|
|
9
|
+
}: Props = {}) => {
|
|
6
10
|
if (!enabled) {
|
|
7
11
|
return null;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
return {
|
|
11
15
|
type: "View",
|
|
12
|
-
style
|
|
13
|
-
flex: 1,
|
|
14
|
-
},
|
|
16
|
+
style,
|
|
15
17
|
};
|
|
16
18
|
};
|
package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts
CHANGED
|
@@ -14,6 +14,9 @@ export const TextLabelsContainer = ({
|
|
|
14
14
|
}: Props) => {
|
|
15
15
|
return {
|
|
16
16
|
type: "View",
|
|
17
|
+
style: {
|
|
18
|
+
flexShrink: 1,
|
|
19
|
+
},
|
|
17
20
|
additionalProps: {
|
|
18
21
|
mobileActionRole: "label_container",
|
|
19
22
|
},
|
|
@@ -26,7 +29,6 @@ export const TextLabelsContainer = ({
|
|
|
26
29
|
context: actionIdentifier,
|
|
27
30
|
name: "label_1",
|
|
28
31
|
},
|
|
29
|
-
state: "default",
|
|
30
32
|
mobileActionRole: "label",
|
|
31
33
|
testID: testID ? `${testID}-label` : undefined,
|
|
32
34
|
...extraProps,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Text as RNText,
|
|
2
|
+
import { Pressable, Text as RNText, View } from "react-native";
|
|
3
3
|
import { render, fireEvent } from "@testing-library/react-native";
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
|
|
@@ -8,6 +8,11 @@ import { elementMapper } from "../../../../elementMapper";
|
|
|
8
8
|
import { defaultComponents } from "../../../index";
|
|
9
9
|
import { MobileActionButtons } from "..";
|
|
10
10
|
import { AssetComponent } from "../AssetComponent";
|
|
11
|
+
import { usePressedState } from "../../../../hooks/usePressedState";
|
|
12
|
+
|
|
13
|
+
jest.mock("../../../../hooks/usePressedState", () => ({
|
|
14
|
+
usePressedState: jest.fn(),
|
|
15
|
+
}));
|
|
11
16
|
|
|
12
17
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/actions", () => ({
|
|
13
18
|
useActions: jest.fn(),
|
|
@@ -136,6 +141,7 @@ const baseNode = {
|
|
|
136
141
|
borderColor: "rgba(4,4,4,1)",
|
|
137
142
|
},
|
|
138
143
|
testID: "mobile-action-button",
|
|
144
|
+
testOnly_pressed: false,
|
|
139
145
|
},
|
|
140
146
|
elements: [
|
|
141
147
|
{
|
|
@@ -190,14 +196,20 @@ const baseNode = {
|
|
|
190
196
|
describe("MobileActionButton", () => {
|
|
191
197
|
beforeEach(() => {
|
|
192
198
|
jest.clearAllMocks();
|
|
199
|
+
(usePressedState as jest.Mock).mockReturnValue(false);
|
|
193
200
|
});
|
|
194
201
|
|
|
195
|
-
const renderNode = (node = baseNode) =>
|
|
196
|
-
|
|
202
|
+
const renderNode = ({ node = baseNode, pressed = false } = {}) => {
|
|
203
|
+
if (pressed) {
|
|
204
|
+
node.props.testOnly_pressed = true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return render(
|
|
197
208
|
<React.Fragment>
|
|
198
209
|
{elementMapper(defaultComponents)(node as never)}
|
|
199
210
|
</React.Fragment>
|
|
200
211
|
);
|
|
212
|
+
};
|
|
201
213
|
|
|
202
214
|
it("renders nested image and text children through elementMapper", () => {
|
|
203
215
|
mockUseActions.mockReturnValue(buildActionContext());
|
|
@@ -210,12 +222,13 @@ describe("MobileActionButton", () => {
|
|
|
210
222
|
});
|
|
211
223
|
|
|
212
224
|
it("applies focused styles when action entry state is active", () => {
|
|
225
|
+
(usePressedState as jest.Mock).mockReturnValue(true);
|
|
213
226
|
mockUseActions.mockReturnValue(buildActionContext({ active: true }));
|
|
214
227
|
|
|
215
|
-
const { getByTestId, getByText } = renderNode();
|
|
228
|
+
const { getByTestId, getByText } = renderNode({ pressed: true });
|
|
216
229
|
|
|
217
230
|
expect(
|
|
218
|
-
getByTestId("mobile-action-button").props.style.backgroundColor
|
|
231
|
+
getByTestId("mobile-action-button").props.style[2].backgroundColor
|
|
219
232
|
).toBe("rgba(3,3,3,1)");
|
|
220
233
|
|
|
221
234
|
expect(getByText("Play").props.style).toEqual(
|
|
@@ -253,6 +266,8 @@ describe("MobileActionButton", () => {
|
|
|
253
266
|
})
|
|
254
267
|
);
|
|
255
268
|
|
|
269
|
+
node.props.testOnly_pressed = false;
|
|
270
|
+
|
|
256
271
|
const { UNSAFE_getAllByType, UNSAFE_getByType, getByTestId, getByText } =
|
|
257
272
|
render(
|
|
258
273
|
<React.Fragment>
|
|
@@ -260,14 +275,14 @@ describe("MobileActionButton", () => {
|
|
|
260
275
|
</React.Fragment>
|
|
261
276
|
);
|
|
262
277
|
|
|
263
|
-
const pressable = UNSAFE_getByType(
|
|
278
|
+
const pressable = UNSAFE_getByType(Pressable);
|
|
264
279
|
const label = getByText("Play");
|
|
265
280
|
const asset = getByTestId("mobile_action_button_1-asset");
|
|
266
281
|
|
|
267
282
|
expect(pressable.props.testID).toBe("mobile_action_button_1");
|
|
268
283
|
expect(pressable.props.accessibilityLabel).toBe("entry-1");
|
|
269
284
|
|
|
270
|
-
expect(pressable.props.style).toMatchObject({
|
|
285
|
+
expect(pressable.props.style({ pressed: false })[0]).toMatchObject({
|
|
271
286
|
backgroundColor: "rgba(1,1,1,1)",
|
|
272
287
|
borderColor: "rgba(2,2,2,1)",
|
|
273
288
|
borderWidth: 1,
|
|
@@ -278,15 +293,11 @@ describe("MobileActionButton", () => {
|
|
|
278
293
|
height: 24,
|
|
279
294
|
});
|
|
280
295
|
|
|
281
|
-
expect(label.props.style).
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
lineHeight: 24,
|
|
287
|
-
}),
|
|
288
|
-
])
|
|
289
|
-
);
|
|
296
|
+
expect(label.props.style[0]).toMatchObject({
|
|
297
|
+
color: "rgba(10,10,10,1)",
|
|
298
|
+
fontSize: 15,
|
|
299
|
+
lineHeight: 24,
|
|
300
|
+
});
|
|
290
301
|
|
|
291
302
|
expect(UNSAFE_getAllByType(View).length).toBeGreaterThan(0);
|
|
292
303
|
expect(UNSAFE_getAllByType(RNText).length).toBeGreaterThan(0);
|
|
@@ -324,7 +335,7 @@ describe("MobileActionButton", () => {
|
|
|
324
335
|
buildActionContext({ mobileButtonAssets: MockAssetComponent })
|
|
325
336
|
);
|
|
326
337
|
|
|
327
|
-
const { getByTestId } = renderNode(nodeWithFlavour1);
|
|
338
|
+
const { getByTestId } = renderNode({ node: nodeWithFlavour1 });
|
|
328
339
|
|
|
329
340
|
expect(MockAssetComponent).toHaveBeenCalled();
|
|
330
341
|
expect(getByTestId("mobile-action-button-asset")).toBeTruthy();
|
|
@@ -339,7 +350,7 @@ describe("MobileActionButton", () => {
|
|
|
339
350
|
buildActionContext({ mobileButtonAssets: MockAssetComponent })
|
|
340
351
|
);
|
|
341
352
|
|
|
342
|
-
renderNode(nodeWithFlavour1);
|
|
353
|
+
renderNode({ node: nodeWithFlavour1 });
|
|
343
354
|
|
|
344
355
|
expect(MockAssetComponent).toHaveBeenCalledWith(
|
|
345
356
|
expect.objectContaining({ flavour: "flavour_1" }),
|
|
@@ -356,7 +367,7 @@ describe("MobileActionButton", () => {
|
|
|
356
367
|
buildActionContext({ mobileButtonAssets: MockAssetComponent })
|
|
357
368
|
);
|
|
358
369
|
|
|
359
|
-
renderNode(nodeWithFlavour2);
|
|
370
|
+
renderNode({ node: nodeWithFlavour2 });
|
|
360
371
|
|
|
361
372
|
expect(MockAssetComponent).toHaveBeenCalledWith(
|
|
362
373
|
expect.objectContaining({ flavour: "flavour_2" }),
|
|
@@ -369,7 +380,7 @@ describe("MobileActionButton", () => {
|
|
|
369
380
|
buildActionContext({ mobileButtonAssets: undefined })
|
|
370
381
|
);
|
|
371
382
|
|
|
372
|
-
const { queryByTestId } = renderNode(nodeWithFlavour1);
|
|
383
|
+
const { queryByTestId } = renderNode({ node: nodeWithFlavour1 });
|
|
373
384
|
|
|
374
385
|
expect(queryByTestId("mobile-action-button-asset")).toBeNull();
|
|
375
386
|
});
|
|
@@ -385,7 +396,7 @@ describe("MobileActionButton", () => {
|
|
|
385
396
|
})
|
|
386
397
|
);
|
|
387
398
|
|
|
388
|
-
const { getByTestId } = renderNode(nodeWithFlavour1);
|
|
399
|
+
const { getByTestId } = renderNode({ node: nodeWithFlavour1 });
|
|
389
400
|
|
|
390
401
|
expect(getByTestId("mobile-action-button-asset")).toBeTruthy();
|
|
391
402
|
});
|
package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts
CHANGED
|
@@ -241,10 +241,21 @@ describe("MobileActionButtons", () => {
|
|
|
241
241
|
expect(overImageResult?.additionalProps?.contentStyle).toMatchObject({
|
|
242
242
|
flexDirection: "column",
|
|
243
243
|
alignItems: "center",
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
paddingTop: 5,
|
|
245
|
+
paddingRight: 6,
|
|
246
|
+
paddingBottom: 7,
|
|
247
|
+
paddingLeft: 8,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(overImageResult?.style).toMatchObject({
|
|
251
|
+
alignItems: "flex-end",
|
|
252
|
+
bottom: 0,
|
|
253
|
+
justifyContent: "flex-start",
|
|
254
|
+
left: 0,
|
|
255
|
+
position: "absolute",
|
|
256
|
+
right: 0,
|
|
257
|
+
top: 0,
|
|
258
|
+
zIndex: 10,
|
|
248
259
|
});
|
|
249
260
|
|
|
250
261
|
expect(
|