@applicaster/zapp-react-native-ui-components 16.0.0-alpha.1453660071 → 16.0.0-alpha.1454930193
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/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +15 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +64 -0
- package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +18 -0
- package/Components/LinkHandler/LinkHandler.tsx +2 -7
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- 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/LiveImage/executePreloadHooks.ts +2 -4
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -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/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -2
- package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
- package/Components/MasterCell/hooks/index.ts +2 -0
- package/Components/MasterCell/hooks/usePressedState.ts +4 -0
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
- package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1007 -0
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +356 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +521 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +505 -50
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- 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 +156 -0
- package/Components/ModalComponent/SortableList.web.tsx +34 -0
- package/Components/ModalComponent/TextInputContent.tsx +135 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
- package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +18 -9
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -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 +52 -0
- package/Components/ModalComponent/utils.ts +82 -21
- 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 +111 -0
- package/Components/OfflineHandler/index.tsx +51 -73
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +11 -7
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +66 -13
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +85 -59
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -75
- package/Components/River/__tests__/componentsMap.test.js +8 -3
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/Components/Screen/__tests__/Screen.test.tsx +24 -0
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +5 -0
- package/Components/Screen/navigationHandler.ts +8 -8
- 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 +21 -4
- package/Components/TopCutoffOverlay/index.tsx +2 -2
- package/Components/Transitioner/Transitioner.tsx +30 -20
- package/Components/Transitioner/__tests__/transitioner.test.js +83 -2
- package/Components/VideoLive/LiveImageManager.ts +9 -3
- package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
- package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
- package/Contexts/ModalNavigationContext/index.tsx +2 -2
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/assets/empty-Info.png +0 -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/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "./utils";
|
|
7
7
|
import { Button } from "./Button";
|
|
8
8
|
import { buildActionButtonsModel } from "../../ActionButtonsCore/model";
|
|
9
|
+
import { ViewStyle } from "react-native";
|
|
9
10
|
|
|
10
11
|
const CONTAINER_PREFIX = "mobile_buttons_container";
|
|
11
12
|
const BUTTON_PREFIX = "mobile_button";
|
|
@@ -42,9 +43,24 @@ export const MobileActionButtons = ({
|
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
const {
|
|
47
|
+
container: { stacking, verticalGutter, horizontalGutter },
|
|
48
|
+
} = model;
|
|
49
|
+
|
|
50
|
+
const isVertical = stacking === "vertical";
|
|
51
|
+
const isOverImage = position === "over_image";
|
|
52
|
+
const gutter = isVertical ? verticalGutter : horizontalGutter;
|
|
53
|
+
|
|
54
|
+
const containerPaddings = {
|
|
55
|
+
paddingTop: model.container.margins.top,
|
|
56
|
+
paddingRight: model.container.margins.right,
|
|
57
|
+
paddingBottom: model.container.margins.bottom,
|
|
58
|
+
paddingLeft: model.container.margins.left,
|
|
59
|
+
};
|
|
60
|
+
|
|
45
61
|
const style = {
|
|
46
62
|
alignItems: "center",
|
|
47
|
-
...(
|
|
63
|
+
...(isOverImage
|
|
48
64
|
? {
|
|
49
65
|
position: "absolute",
|
|
50
66
|
zIndex: 10,
|
|
@@ -60,28 +76,18 @@ export const MobileActionButtons = ({
|
|
|
60
76
|
};
|
|
61
77
|
|
|
62
78
|
const contentStyle = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
...containerPaddings,
|
|
80
|
+
flexDirection: isVertical ? "column" : "row",
|
|
81
|
+
width: isVertical ? "100%" : undefined,
|
|
82
|
+
alignSelf: !isOverImage ? model.container.horizontalAlign : undefined,
|
|
66
83
|
alignItems: model.container.horizontalAlign,
|
|
67
|
-
marginTop: model.container.margins.top,
|
|
68
|
-
marginRight: model.container.margins.right,
|
|
69
|
-
marginBottom: model.container.margins.bottom,
|
|
70
|
-
marginLeft: model.container.margins.left,
|
|
71
84
|
};
|
|
72
85
|
|
|
73
86
|
const elements = compact(
|
|
74
87
|
model.buttons.map(({ renderIndex, specificPrefix, stylePrefix }) => {
|
|
75
88
|
const isNotLast = renderIndex < model.buttons.length - 1;
|
|
76
89
|
|
|
77
|
-
const {
|
|
78
|
-
container: { stacking, verticalGutter, horizontalGutter },
|
|
79
|
-
} = model;
|
|
80
|
-
|
|
81
|
-
const isVertical = stacking === "vertical";
|
|
82
|
-
const gutter = isVertical ? verticalGutter : horizontalGutter;
|
|
83
|
-
|
|
84
|
-
const spacingStyle = {
|
|
90
|
+
const spacingStyle: ViewStyle = {
|
|
85
91
|
[isVertical ? "marginBottom" : "marginRight"]: isNotLast ? gutter : 0,
|
|
86
92
|
};
|
|
87
93
|
|
|
@@ -91,6 +97,7 @@ export const MobileActionButtons = ({
|
|
|
91
97
|
stylePrefix,
|
|
92
98
|
specificPrefix,
|
|
93
99
|
spacingStyle,
|
|
100
|
+
isVertical,
|
|
94
101
|
});
|
|
95
102
|
|
|
96
103
|
if (!button) return null;
|
|
@@ -5,14 +5,19 @@ import {
|
|
|
5
5
|
} from "..";
|
|
6
6
|
|
|
7
7
|
describe("mobile action insertion helpers", () => {
|
|
8
|
-
const
|
|
8
|
+
const slots = [
|
|
9
|
+
{ name: "text_label_1", element: { type: "View", id: "text_label_1" } },
|
|
10
|
+
{ name: "text_label_2", element: { type: "View", id: "text_label_2" } },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const labels = slots.map((slot) => slot.element);
|
|
9
14
|
const buttons = { type: "View", name: "buttons" };
|
|
10
15
|
|
|
11
16
|
it("inserts label buttons below target label", () => {
|
|
12
17
|
const result = insertButtonsBetweenLabels(
|
|
13
18
|
{ mobile_buttons_container_position: "below_text_label_1" },
|
|
14
19
|
buttons,
|
|
15
|
-
|
|
20
|
+
slots
|
|
16
21
|
);
|
|
17
22
|
|
|
18
23
|
expect(result).toEqual([labels[0], buttons, labels[1]]);
|
|
@@ -22,7 +27,7 @@ describe("mobile action insertion helpers", () => {
|
|
|
22
27
|
const result = insertButtonsBetweenLabels(
|
|
23
28
|
{ mobile_buttons_container_position: "unknown" },
|
|
24
29
|
buttons,
|
|
25
|
-
|
|
30
|
+
slots
|
|
26
31
|
);
|
|
27
32
|
|
|
28
33
|
expect(result).toEqual([labels[0], labels[1]]);
|
|
@@ -8,7 +8,7 @@ import { Platform } from "react-native";
|
|
|
8
8
|
export const insertButtonsBetweenLabels = (
|
|
9
9
|
configuration: Record<string, unknown>,
|
|
10
10
|
buttons,
|
|
11
|
-
|
|
11
|
+
slots = [] // { name, element } per canonical text label slot
|
|
12
12
|
) =>
|
|
13
13
|
insertBetweenLabels(
|
|
14
14
|
{
|
|
@@ -19,7 +19,7 @@ export const insertButtonsBetweenLabels = (
|
|
|
19
19
|
appendWhenMissing: false,
|
|
20
20
|
},
|
|
21
21
|
buttons,
|
|
22
|
-
|
|
22
|
+
slots
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
export const insertButtonsBetweenLabelContainers = (
|
|
@@ -3,18 +3,20 @@ import { insertButtonsBetweenLabels } from "..";
|
|
|
3
3
|
describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
4
4
|
const buttons = "buttons";
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
{ name: "label_1" },
|
|
8
|
-
{ name: "label_2" },
|
|
9
|
-
{ name: "label_3" },
|
|
6
|
+
const slots = [
|
|
7
|
+
{ name: "label_1", element: { id: "label_1" } },
|
|
8
|
+
{ name: "label_2", element: { id: "label_2" } },
|
|
9
|
+
{ name: "label_3", element: { id: "label_3" } },
|
|
10
10
|
];
|
|
11
11
|
|
|
12
|
+
const labels = slots.map((slot) => slot.element);
|
|
13
|
+
|
|
12
14
|
it("put buttons on top", () => {
|
|
13
15
|
const configuration = {
|
|
14
16
|
tv_buttons_container_position: "on_top",
|
|
15
17
|
};
|
|
16
18
|
|
|
17
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
19
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
18
20
|
|
|
19
21
|
expect(result).toEqual([buttons, ...labels]);
|
|
20
22
|
});
|
|
@@ -24,7 +26,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
24
26
|
tv_buttons_container_position: "unknown_position",
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
29
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
28
30
|
|
|
29
31
|
expect(result).toEqual([...labels, buttons]);
|
|
30
32
|
});
|
|
@@ -34,7 +36,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
34
36
|
tv_buttons_container_position: "label_1",
|
|
35
37
|
};
|
|
36
38
|
|
|
37
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
39
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
38
40
|
|
|
39
41
|
expect(result).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
40
42
|
});
|
|
@@ -44,7 +46,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
44
46
|
tv_buttons_container_position: "label_2",
|
|
45
47
|
};
|
|
46
48
|
|
|
47
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
49
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
48
50
|
|
|
49
51
|
expect(result).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
50
52
|
});
|
|
@@ -54,22 +56,52 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
54
56
|
tv_buttons_container_position: "label_3",
|
|
55
57
|
};
|
|
56
58
|
|
|
57
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
59
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
58
60
|
|
|
59
61
|
expect(result).toEqual([labels[0], labels[1], labels[2], buttons]);
|
|
60
62
|
});
|
|
61
63
|
|
|
62
|
-
it("put
|
|
64
|
+
it("put above label_2", () => {
|
|
65
|
+
const configuration = {
|
|
66
|
+
tv_buttons_container_position: "above_label_2",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
70
|
+
|
|
71
|
+
expect(result).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("keeps the slot when its label is empty (null element)", () => {
|
|
75
|
+
const slotsWithEmpty = [
|
|
76
|
+
{ name: "label_1", element: { id: "label_1" } },
|
|
77
|
+
{ name: "label_2", element: null },
|
|
78
|
+
{ name: "label_3", element: { id: "label_3" } },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const configuration = {
|
|
82
|
+
tv_buttons_container_position: "above_label_2",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const result = insertButtonsBetweenLabels(
|
|
86
|
+
configuration,
|
|
87
|
+
buttons,
|
|
88
|
+
slotsWithEmpty
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(result).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("appends buttons when the target is unknown", () => {
|
|
63
95
|
const configuration = {
|
|
64
96
|
tv_buttons_container_position: "label_X",
|
|
65
97
|
};
|
|
66
98
|
|
|
67
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
99
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
68
100
|
|
|
69
101
|
expect(result).toEqual([labels[0], labels[1], labels[2], buttons]);
|
|
70
102
|
});
|
|
71
103
|
|
|
72
|
-
it("
|
|
104
|
+
it("appends buttons when there are no slots", () => {
|
|
73
105
|
const configuration = {
|
|
74
106
|
tv_buttons_container_position: "label_X",
|
|
75
107
|
};
|
|
@@ -88,7 +120,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
88
120
|
tv_buttons_container_position: "label_X",
|
|
89
121
|
};
|
|
90
122
|
|
|
91
|
-
const result = insertButtonsBetweenLabels(configuration, null,
|
|
123
|
+
const result = insertButtonsBetweenLabels(configuration, null, slots);
|
|
92
124
|
|
|
93
125
|
expect(result).toEqual(labels);
|
|
94
126
|
});
|
|
@@ -34,7 +34,7 @@ export const memoizedGetPluginIdentifier = memoizee(getPluginIdentifier);
|
|
|
34
34
|
export const insertButtonsBetweenLabels = (
|
|
35
35
|
configuration: Record<string, unknown>,
|
|
36
36
|
buttons,
|
|
37
|
-
|
|
37
|
+
slots = [] // { name, element } per canonical text label slot
|
|
38
38
|
) =>
|
|
39
39
|
insertBetweenLabels(
|
|
40
40
|
{
|
|
@@ -45,7 +45,7 @@ export const insertButtonsBetweenLabels = (
|
|
|
45
45
|
appendWhenMissing: true,
|
|
46
46
|
},
|
|
47
47
|
buttons,
|
|
48
|
-
|
|
48
|
+
slots
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
export const insertButtonsBetweenLabelContainers = (
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CollapsibleTextContainer } from "../index";
|
|
2
|
+
|
|
3
|
+
const getValue = (key: string) => {
|
|
4
|
+
const values: Record<string, unknown> = {
|
|
5
|
+
text_alignment: "left",
|
|
6
|
+
margin_top: 0,
|
|
7
|
+
margin_right: 0,
|
|
8
|
+
margin_bottom: 0,
|
|
9
|
+
margin_left: 0,
|
|
10
|
+
padding_top: 0,
|
|
11
|
+
padding_right: 0,
|
|
12
|
+
padding_bottom: 0,
|
|
13
|
+
padding_left: 0,
|
|
14
|
+
corner_radius: 0,
|
|
15
|
+
data_key: "title",
|
|
16
|
+
custom_data_key: undefined,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return values[key];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
describe("CollapsibleTextContainer view tree", () => {
|
|
23
|
+
it("stretches to the parent width so labels wrap using the cell width", () => {
|
|
24
|
+
const result = CollapsibleTextContainer({
|
|
25
|
+
getValue,
|
|
26
|
+
elements: [],
|
|
27
|
+
additionalStyles: { backgroundColor: "transparent" },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(result.style.alignSelf).toBe("stretch");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -3,7 +3,6 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
3
3
|
import {
|
|
4
4
|
getColorFromData,
|
|
5
5
|
getKeyForLabel,
|
|
6
|
-
mapSelfAlignment,
|
|
7
6
|
} from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
8
7
|
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
9
8
|
|
|
@@ -23,7 +22,7 @@ export const CollapsibleTextContainer = ({
|
|
|
23
22
|
return {
|
|
24
23
|
type: "CollapsibleTextContainer", // Collapsible Text Container,
|
|
25
24
|
style: {
|
|
26
|
-
alignSelf:
|
|
25
|
+
alignSelf: "stretch",
|
|
27
26
|
marginTop: toNumberWithDefaultZero(getValue("margin_top")),
|
|
28
27
|
marginRight: toNumberWithDefaultZero(getValue("margin_right")),
|
|
29
28
|
marginBottom: toNumberWithDefaultZero(getValue("margin_bottom")),
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useEntryActionState } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
3
|
+
import {
|
|
4
|
+
isActionAvailableFor,
|
|
5
|
+
RegisteredAction,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
7
|
+
|
|
8
|
+
import { Button } from "../Button";
|
|
9
|
+
|
|
10
|
+
export type ActionButtonProps = {
|
|
11
|
+
entry: ZappEntry;
|
|
12
|
+
item: RegisteredAction;
|
|
13
|
+
configuration: any;
|
|
14
|
+
width: number;
|
|
15
|
+
component?: ZappUIComponent & { parent?: ZappUIComponent };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Props = ActionButtonProps & {
|
|
19
|
+
onPress?: (item: any) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Unified action button for the modal bottom sheet.
|
|
24
|
+
*
|
|
25
|
+
* Every item is a `RegisteredAction` resolved from the registry (entry actions,
|
|
26
|
+
* registry actions and legacy context-provider actions alike), so the button
|
|
27
|
+
* simply reads `item.action` and drives it through `useEntryActionState`
|
|
28
|
+
* (backed by the action's observable / `addListener`).
|
|
29
|
+
*/
|
|
30
|
+
export function ActionButton(props: Props) {
|
|
31
|
+
const { item, entry, onPress: onItemPress, component } = props;
|
|
32
|
+
|
|
33
|
+
const action = item?.action;
|
|
34
|
+
|
|
35
|
+
const { state, invokeAction } = useEntryActionState(action, entry);
|
|
36
|
+
|
|
37
|
+
const onPress = React.useCallback(
|
|
38
|
+
(_item) => {
|
|
39
|
+
invokeAction({
|
|
40
|
+
context: "toast",
|
|
41
|
+
dismiss: () => onItemPress?.(item),
|
|
42
|
+
...(component ? { component } : {}),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
[invokeAction, item, onItemPress, component]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (!isActionAvailableFor(action, entry as ZappEntry)) return null;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Button {...props} item={state} onPress={onPress} label={state?.label} />
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Explicitly set display name for the component
|
|
56
|
+
ActionButton.displayName = "ActionButton";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
2
|
+
import { boundActionButton } from "../boundActionButton";
|
|
3
|
+
import { openActionsBottomSheet } from "../openActionsBottomSheet";
|
|
4
|
+
|
|
5
|
+
jest.mock("@applicaster/zapp-react-native-utils/modalState", () => ({
|
|
6
|
+
openBottomSheetModal: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
jest.mock("../boundActionButton", () => ({
|
|
10
|
+
boundActionButton: jest.fn(() => jest.fn()),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe("openActionsBottomSheet", () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("binds the List component into the sheet row button", () => {
|
|
19
|
+
const entry = { id: "entry-1" } as ZappEntry;
|
|
20
|
+
|
|
21
|
+
const component = {
|
|
22
|
+
data: { source: "https://example.com/user/collections/abc" },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const actions = [
|
|
26
|
+
{ identifier: "entry_action_0", action: { invokeAction: jest.fn() } },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
openActionsBottomSheet({
|
|
30
|
+
entry,
|
|
31
|
+
actions: actions as any,
|
|
32
|
+
component: component as any,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
expect(boundActionButton).toHaveBeenCalledWith(entry, component);
|
|
36
|
+
expect(openBottomSheetModal).toHaveBeenCalledTimes(1);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { ActionButton, ActionButtonProps } from "./ActionButton";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Binds an entry to the sheet's row button.
|
|
7
|
+
*
|
|
8
|
+
* `BottomSheetModalContent` renders `buttonComponent` per item and does not
|
|
9
|
+
* know about entries, so the entry is closed over here instead.
|
|
10
|
+
*/
|
|
11
|
+
export const boundActionButton = (
|
|
12
|
+
entry: ZappEntry | ZappFeed,
|
|
13
|
+
component?: ZappUIComponent & { parent?: ZappUIComponent }
|
|
14
|
+
) => {
|
|
15
|
+
const ActionButtonWithEntry = (props: ActionButtonProps) => (
|
|
16
|
+
<ActionButton {...props} entry={entry as ZappEntry} component={component} />
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
ActionButtonWithEntry.displayName = "ActionButtonWithEntry";
|
|
20
|
+
|
|
21
|
+
return ActionButtonWithEntry;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
boundActionButton.displayName = "boundActionButton";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { ActionButton } from "./ActionButton";
|
|
2
|
+
|
|
3
|
+
export type { ActionButtonProps } from "./ActionButton";
|
|
4
|
+
|
|
5
|
+
export { boundActionButton } from "./boundActionButton";
|
|
6
|
+
|
|
7
|
+
export { openActionsBottomSheet } from "./openActionsBottomSheet";
|
|
8
|
+
|
|
9
|
+
export type { OpenActionsBottomSheetArgs } from "./openActionsBottomSheet";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
2
|
+
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
3
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
4
|
+
import { RegisteredAction } from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
5
|
+
|
|
6
|
+
import { boundActionButton } from "./boundActionButton";
|
|
7
|
+
|
|
8
|
+
const { log_warning } = createLogger({
|
|
9
|
+
subsystem: "ActionsBottomSheet",
|
|
10
|
+
category: "Presentation",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type OpenActionsBottomSheetArgs = {
|
|
14
|
+
/** Entry the actions act on; bound into every row button. */
|
|
15
|
+
entry: ZappEntry | ZappFeed;
|
|
16
|
+
/** Already resolved and merged actions, in the order they should appear. */
|
|
17
|
+
actions: RegisteredAction[];
|
|
18
|
+
title?: string;
|
|
19
|
+
summary?: string;
|
|
20
|
+
/** List that opened the sheet; forwarded into row invokeAction context. */
|
|
21
|
+
component?: ZappUIComponent & { parent?: ZappUIComponent };
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Presents a list of resolved actions in the shared bottom sheet.
|
|
26
|
+
*
|
|
27
|
+
* This is the core entry point for "show these actions in a sheet": the
|
|
28
|
+
* open-modal-bottom-sheet plugin uses it for its configured list, and the
|
|
29
|
+
* player overflow uses it for the actions that did not fit on the overlay.
|
|
30
|
+
* Neither has to know about the other, and neither needs the plugin installed.
|
|
31
|
+
*/
|
|
32
|
+
export function openActionsBottomSheet({
|
|
33
|
+
entry,
|
|
34
|
+
actions,
|
|
35
|
+
title,
|
|
36
|
+
summary,
|
|
37
|
+
component,
|
|
38
|
+
}: OpenActionsBottomSheetArgs): void {
|
|
39
|
+
if (!actions?.length) {
|
|
40
|
+
// Every action resolved away - unavailable for this entry, or not
|
|
41
|
+
// invokable. An empty sheet looks broken, so say why and stay put.
|
|
42
|
+
log_warning(
|
|
43
|
+
"openActionsBottomSheet: nothing to present - not opening the sheet",
|
|
44
|
+
{ entryId: (entry as ZappEntry)?.id }
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
openBottomSheetModal({
|
|
51
|
+
modalBottomSheetContentProps: {
|
|
52
|
+
// TODO: should be optional - the button handles its own tap, but
|
|
53
|
+
// BottomSheetModalContent still requires an onPress.
|
|
54
|
+
onPress: noop,
|
|
55
|
+
items: actions,
|
|
56
|
+
buttonComponent: boundActionButton(entry, component),
|
|
57
|
+
title,
|
|
58
|
+
summary,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|