@applicaster/zapp-react-native-ui-components 16.0.0-rc.33 → 16.0.0-rc.34
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/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +3 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +40 -2
- 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 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +1 -1
- 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/ModalComponent/AudioPlayer/Components/Action.tsx +368 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +424 -0
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +728 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +709 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +7 -0
- package/package.json +5 -5
package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts
CHANGED
|
@@ -6,28 +6,54 @@ import {
|
|
|
6
6
|
describe("ActionButtonsCore placement", () => {
|
|
7
7
|
const buttons = { type: "View", name: "buttons" };
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
{ name: "
|
|
11
|
-
{ name: "
|
|
12
|
-
{ name: "
|
|
9
|
+
const slots = [
|
|
10
|
+
{ name: "text_label_1", element: { type: "View", id: "label_1" } },
|
|
11
|
+
{ name: "text_label_2", element: { type: "View", id: "label_2" } },
|
|
12
|
+
{ name: "text_label_3", element: { type: "View", id: "label_3" } },
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
{ name: "below_label_1" },
|
|
17
|
-
{ name: "below_label_2" },
|
|
18
|
-
{ name: "below_label_3" },
|
|
19
|
-
];
|
|
15
|
+
const labels = slots.map((slot) => slot.element);
|
|
20
16
|
|
|
21
17
|
it("inserts buttons after the matching label", () => {
|
|
22
18
|
expect(
|
|
23
|
-
insertBetweenLabels({ position: "
|
|
24
|
-
).toEqual([
|
|
19
|
+
insertBetweenLabels({ position: "below_text_label_2" }, buttons, slots)
|
|
20
|
+
).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
25
21
|
});
|
|
26
22
|
|
|
27
23
|
it("inserts buttons before the matching label", () => {
|
|
28
24
|
expect(
|
|
29
|
-
insertBetweenLabels({ position: "
|
|
30
|
-
).toEqual([
|
|
25
|
+
insertBetweenLabels({ position: "above_text_label_2" }, buttons, slots)
|
|
26
|
+
).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("inserts buttons after the matching label on a plain name match", () => {
|
|
30
|
+
expect(
|
|
31
|
+
insertBetweenLabels({ position: "text_label_2" }, buttons, slots)
|
|
32
|
+
).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("keeps the slot when its label is empty (null element)", () => {
|
|
36
|
+
const slotsWithEmpty = [
|
|
37
|
+
{ name: "text_label_1", element: { id: "label_1" } },
|
|
38
|
+
{ name: "text_label_2", element: null },
|
|
39
|
+
{ name: "text_label_3", element: { id: "label_3" } },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
expect(
|
|
43
|
+
insertBetweenLabels(
|
|
44
|
+
{ position: "above_text_label_2" },
|
|
45
|
+
buttons,
|
|
46
|
+
slotsWithEmpty
|
|
47
|
+
)
|
|
48
|
+
).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
49
|
+
|
|
50
|
+
expect(
|
|
51
|
+
insertBetweenLabels(
|
|
52
|
+
{ position: "below_text_label_2" },
|
|
53
|
+
buttons,
|
|
54
|
+
slotsWithEmpty
|
|
55
|
+
)
|
|
56
|
+
).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
31
57
|
});
|
|
32
58
|
|
|
33
59
|
it("prepends buttons only when on_top is allowed", () => {
|
|
@@ -35,17 +61,17 @@ describe("ActionButtonsCore placement", () => {
|
|
|
35
61
|
insertBetweenLabels(
|
|
36
62
|
{ position: "on_top", allowOnTop: true },
|
|
37
63
|
buttons,
|
|
38
|
-
|
|
64
|
+
slots
|
|
39
65
|
)
|
|
40
|
-
).toEqual([buttons, ...
|
|
66
|
+
).toEqual([buttons, ...labels]);
|
|
41
67
|
|
|
42
68
|
expect(
|
|
43
69
|
insertBetweenLabels(
|
|
44
70
|
{ position: "on_top", allowOnTop: false },
|
|
45
71
|
buttons,
|
|
46
|
-
|
|
72
|
+
slots
|
|
47
73
|
)
|
|
48
|
-
).toEqual(
|
|
74
|
+
).toEqual(labels);
|
|
49
75
|
});
|
|
50
76
|
|
|
51
77
|
it("appends buttons when appendWhenMissing is enabled", () => {
|
|
@@ -53,9 +79,9 @@ describe("ActionButtonsCore placement", () => {
|
|
|
53
79
|
insertBetweenLabels(
|
|
54
80
|
{ position: "unknown", appendWhenMissing: true },
|
|
55
81
|
buttons,
|
|
56
|
-
|
|
82
|
+
slots
|
|
57
83
|
)
|
|
58
|
-
).toEqual([...
|
|
84
|
+
).toEqual([...labels, buttons]);
|
|
59
85
|
});
|
|
60
86
|
|
|
61
87
|
it("returns labels unchanged when appendWhenMissing is disabled", () => {
|
|
@@ -63,9 +89,9 @@ describe("ActionButtonsCore placement", () => {
|
|
|
63
89
|
insertBetweenLabels(
|
|
64
90
|
{ position: "unknown", appendWhenMissing: false },
|
|
65
91
|
buttons,
|
|
66
|
-
|
|
92
|
+
slots
|
|
67
93
|
)
|
|
68
|
-
).toEqual(
|
|
94
|
+
).toEqual(labels);
|
|
69
95
|
});
|
|
70
96
|
|
|
71
97
|
const labelContainers = [
|
|
@@ -17,6 +17,11 @@ type InsertOptions = {
|
|
|
17
17
|
appendWhenMissing?: boolean;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
type Slot = {
|
|
21
|
+
name: string;
|
|
22
|
+
element?: unknown;
|
|
23
|
+
};
|
|
24
|
+
|
|
20
25
|
const hasLabelName = (value: unknown): value is Label =>
|
|
21
26
|
!!value &&
|
|
22
27
|
typeof value === "object" &&
|
|
@@ -100,8 +105,14 @@ const containsNestedLabel = (
|
|
|
100
105
|
export const insertBetweenLabels = (
|
|
101
106
|
{ position, allowOnTop = false, appendWhenMissing = false }: InsertOptions,
|
|
102
107
|
buttons: unknown,
|
|
103
|
-
|
|
108
|
+
slots: Slot[] = []
|
|
104
109
|
) => {
|
|
110
|
+
// Slots are defined by the canonical label list, so an empty (null) label
|
|
111
|
+
// still keeps its position — buttons placed above/below it survive.
|
|
112
|
+
const labels = slots
|
|
113
|
+
.map((slot) => slot.element)
|
|
114
|
+
.filter((element) => element != null);
|
|
115
|
+
|
|
105
116
|
if (buttons == null) {
|
|
106
117
|
return labels;
|
|
107
118
|
}
|
|
@@ -110,14 +121,31 @@ export const insertBetweenLabels = (
|
|
|
110
121
|
return [buttons, ...labels];
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
const
|
|
124
|
+
let inserted = false;
|
|
125
|
+
const result: unknown[] = [];
|
|
126
|
+
|
|
127
|
+
for (const { name, element } of slots) {
|
|
128
|
+
if (position === `above_${name}`) {
|
|
129
|
+
result.push(buttons);
|
|
130
|
+
inserted = true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (element != null) {
|
|
134
|
+
result.push(element);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Insert after on `below_*` or a plain label-name match.
|
|
138
|
+
if (position === `below_${name}` || position === name) {
|
|
139
|
+
result.push(buttons);
|
|
140
|
+
inserted = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
115
143
|
|
|
116
|
-
if (!inserted
|
|
117
|
-
return [...labels, buttons];
|
|
144
|
+
if (!inserted) {
|
|
145
|
+
return appendWhenMissing ? [...labels, buttons] : labels;
|
|
118
146
|
}
|
|
119
147
|
|
|
120
|
-
return
|
|
148
|
+
return result;
|
|
121
149
|
};
|
|
122
150
|
|
|
123
151
|
export const insertBetweenLabelContainers = (
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
2
|
import { isVideoPreviewEnabled } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/utils";
|
|
3
3
|
import { LiveImage } from "../LiveImage";
|
|
4
4
|
import PureImage from "../Image";
|
|
5
5
|
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
6
|
|
|
7
|
-
type Props = {
|
|
7
|
+
type Props = PropsWithChildren<{
|
|
8
8
|
enable_video_preview: boolean;
|
|
9
9
|
player_screen_id: string;
|
|
10
|
-
|
|
10
|
+
uri?: string;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}>;
|
|
11
13
|
|
|
12
14
|
export const ImageContainer = (props: Props) => {
|
|
13
15
|
const isActive = useIsScreenActive();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { TouchableOpacity } from "react-native";
|
|
2
|
+
import { TouchableOpacity, ViewStyle } from "react-native";
|
|
3
3
|
|
|
4
4
|
type Props = {
|
|
5
5
|
children?: React.ReactNode;
|
|
6
|
-
style?:
|
|
6
|
+
style?: ViewStyle | ViewStyle[];
|
|
7
7
|
testID?: string;
|
|
8
8
|
accessibilityLabel?: string;
|
|
9
9
|
accessibilityHint?: string;
|
|
@@ -12,7 +12,7 @@ type Props = {
|
|
|
12
12
|
|
|
13
13
|
export function PressableView({
|
|
14
14
|
children,
|
|
15
|
-
style
|
|
15
|
+
style,
|
|
16
16
|
testID,
|
|
17
17
|
accessibilityLabel,
|
|
18
18
|
accessibilityHint,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
2
3
|
import { PressableView } from "../../PressableView";
|
|
3
4
|
|
|
4
5
|
import { ActionButtonController } from "../../ActionButtonsCore/components";
|
|
@@ -15,6 +16,22 @@ type ChildElementProps = {
|
|
|
15
16
|
entry?: any;
|
|
16
17
|
};
|
|
17
18
|
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
pressableView: {
|
|
21
|
+
flexDirection: "row",
|
|
22
|
+
overflow: "hidden",
|
|
23
|
+
},
|
|
24
|
+
maxWidthFull: {
|
|
25
|
+
width: "100%",
|
|
26
|
+
},
|
|
27
|
+
innerWrapper: {
|
|
28
|
+
flexDirection: "row",
|
|
29
|
+
flexGrow: 0,
|
|
30
|
+
flexShrink: 1,
|
|
31
|
+
overflow: "hidden",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
18
35
|
const isValidElement = (
|
|
19
36
|
child: React.ReactNode
|
|
20
37
|
): child is React.ReactElement<ChildElementProps> =>
|
|
@@ -121,12 +138,33 @@ export const ActionButton = ({ style, children, action, entry, ...props }) => {
|
|
|
121
138
|
return (
|
|
122
139
|
<PressableView
|
|
123
140
|
testID={props.testID || `${entry?.id}`}
|
|
124
|
-
style={
|
|
141
|
+
style={[
|
|
142
|
+
isActive
|
|
143
|
+
? {
|
|
144
|
+
...(style as ViewStyle),
|
|
145
|
+
...(props.focusedStyles as ViewStyle),
|
|
146
|
+
}
|
|
147
|
+
: (style as ViewStyle),
|
|
148
|
+
styles.pressableView,
|
|
149
|
+
]}
|
|
125
150
|
onPress={onPress}
|
|
126
151
|
accessibilityLabel={props.accessibilityLabel || `${entry?.id}`}
|
|
127
152
|
accessibilityHint={props.accessibilityHint}
|
|
128
153
|
>
|
|
129
|
-
|
|
154
|
+
<View
|
|
155
|
+
// eslint-disable-next-line react-native/no-inline-styles
|
|
156
|
+
style={{
|
|
157
|
+
width: props.displayMode === "fill" ? "100%" : undefined,
|
|
158
|
+
maxWidth: (style as ViewStyle).maxWidth,
|
|
159
|
+
...((style as ViewStyle).maxWidth
|
|
160
|
+
? styles.maxWidthFull
|
|
161
|
+
: undefined),
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
<View style={[styles.innerWrapper, props.alignment]}>
|
|
165
|
+
{_cloneChildrenWithState(children)}
|
|
166
|
+
</View>
|
|
167
|
+
</View>
|
|
130
168
|
</PressableView>
|
|
131
169
|
);
|
|
132
170
|
}}
|
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
|
};
|
|
@@ -267,7 +267,7 @@ describe("MobileActionButton", () => {
|
|
|
267
267
|
expect(pressable.props.testID).toBe("mobile_action_button_1");
|
|
268
268
|
expect(pressable.props.accessibilityLabel).toBe("entry-1");
|
|
269
269
|
|
|
270
|
-
expect(pressable.props.style).toMatchObject({
|
|
270
|
+
expect(pressable.props.style[0]).toMatchObject({
|
|
271
271
|
backgroundColor: "rgba(1,1,1,1)",
|
|
272
272
|
borderColor: "rgba(2,2,2,1)",
|
|
273
273
|
borderWidth: 1,
|
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(
|
|
@@ -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 = (
|