@applicaster/zapp-react-native-ui-components 16.0.0-alpha.2529997432 → 16.0.0-alpha.2663208063

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.
Files changed (42) hide show
  1. package/Components/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
  2. package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
  3. package/Components/AudioPlayer/tv/index.tsx +5 -1
  4. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  5. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  6. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  7. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -18
  8. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +17 -24
  9. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +25 -73
  10. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +0 -18
  11. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +75 -79
  12. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
  13. package/Components/ModalComponent/AudioPlayer/Components/index.ts +3 -1
  14. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +199 -0
  15. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  16. package/Components/ModalComponent/BottomSheetModalContent.tsx +385 -60
  17. package/Components/ModalComponent/Button/index.tsx +5 -3
  18. package/Components/ModalComponent/Header/index.tsx +20 -7
  19. package/Components/ModalComponent/Header/utils.ts +1 -1
  20. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  21. package/Components/ModalComponent/SortableList.tsx +142 -0
  22. package/Components/ModalComponent/SortableList.web.tsx +102 -0
  23. package/Components/ModalComponent/TextInputContent.tsx +100 -0
  24. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  25. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
  26. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
  27. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  28. package/Components/ModalComponent/index.tsx +11 -0
  29. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
  30. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  31. package/Components/ModalComponent/presets/index.ts +27 -0
  32. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  33. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  34. package/Components/ModalComponent/presets/types.ts +35 -0
  35. package/Components/ModalComponent/showTextInput.ts +43 -0
  36. package/Components/ModalComponent/utils.ts +76 -20
  37. package/Components/PlayerContainer/PlayerContainer.tsx +11 -7
  38. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  39. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +66 -13
  40. package/Components/VideoLive/LiveImageManager.ts +1 -1
  41. package/package.json +6 -5
  42. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -1,4 +1,8 @@
1
1
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
2
+ import {
3
+ toNumberWithDefault,
4
+ toNumberWithDefaultZero,
5
+ } from "@applicaster/zapp-react-native-utils/numberUtils";
2
6
  import { PluginConfiguration } from "./";
3
7
  import { ItemIconProps } from "./Button/ItemIcon";
4
8
  import { ItemLabelProps } from "./Button/ItemLabel";
@@ -6,7 +10,8 @@ import { ItemProps } from "./Button/Item";
6
10
 
7
11
  export function defaultItemProps(
8
12
  config: PluginConfiguration,
9
- maxWidth: number
13
+ maxWidth: number,
14
+ blockItemStyle?: Record<string, any>
10
15
  ): ItemProps {
11
16
  const {
12
17
  modal_bottom_sheet_item_background_color,
@@ -24,19 +29,31 @@ export function defaultItemProps(
24
29
  modal_bottom_sheet_item_padding_top,
25
30
  } = config;
26
31
 
32
+ const bgDefault = blockItemStyle?.background?.default;
33
+
27
34
  return {
28
- backgroundColor: modal_bottom_sheet_item_background_color,
35
+ backgroundColor:
36
+ bgDefault?.backgroundColor || modal_bottom_sheet_item_background_color,
29
37
  focusedBackgroundColor: modal_bottom_sheet_item_focus_background_color,
30
38
  selectedBackgroundColor: modal_bottom_sheet_item_selected_background_color,
31
39
  focusedSelectedBackgroundColor:
32
40
  modal_bottom_sheet_item_focused_selected_background_color,
33
- borderRadius: modal_bottom_sheet_item_corner_radius,
41
+ borderRadius: toNumberWithDefault(
42
+ modal_bottom_sheet_item_corner_radius,
43
+ bgDefault?.borderRadius
44
+ ),
34
45
  marginBottom: modal_bottom_sheet_item_margin_bottom,
35
46
  marginTop: modal_bottom_sheet_item_margin_top,
36
47
  marginLeft: modal_bottom_sheet_item_margin_left,
37
48
  marginRight: modal_bottom_sheet_item_margin_right,
38
- paddingTop: modal_bottom_sheet_item_padding_top,
39
- paddingBottom: modal_bottom_sheet_item_padding_bottom,
49
+ paddingTop: toNumberWithDefault(
50
+ modal_bottom_sheet_item_padding_top,
51
+ bgDefault?.paddingTop
52
+ ),
53
+ paddingBottom: toNumberWithDefault(
54
+ modal_bottom_sheet_item_padding_bottom,
55
+ bgDefault?.paddingBottom
56
+ ),
40
57
  paddingRight: modal_bottom_sheet_item_padding_right,
41
58
  paddingLeft: modal_bottom_sheet_item_padding_left,
42
59
  maxWidth,
@@ -45,7 +62,8 @@ export function defaultItemProps(
45
62
 
46
63
  export function defaultItemLabelProps(
47
64
  config: PluginConfiguration,
48
- sheetWidth: number
65
+ sheetWidth: number,
66
+ blockItemStyle?: Record<string, any>
49
67
  ): ItemLabelProps {
50
68
  const {
51
69
  modal_bottom_sheet_item_label_android_letter_spacing,
@@ -72,15 +90,48 @@ export function defaultItemLabelProps(
72
90
  modal_bottom_sheet_item_padding_right,
73
91
  } = config;
74
92
 
75
- const maxWidth =
93
+ const iconWidth = toNumberWithDefaultZero(modal_bottom_sheet_item_icon_width);
94
+
95
+ const iconMarginLeft = toNumberWithDefaultZero(
96
+ modal_bottom_sheet_item_icon_margin_left
97
+ );
98
+
99
+ const iconMarginRight = toNumberWithDefaultZero(
100
+ modal_bottom_sheet_item_icon_margin_right
101
+ );
102
+
103
+ const itemMarginLeft = toNumberWithDefaultZero(
104
+ modal_bottom_sheet_item_margin_left
105
+ );
106
+
107
+ const itemMarginRight = toNumberWithDefaultZero(
108
+ modal_bottom_sheet_item_margin_right
109
+ );
110
+
111
+ const itemPaddingLeft = toNumberWithDefaultZero(
112
+ modal_bottom_sheet_item_padding_left
113
+ );
114
+
115
+ const itemPaddingRight = toNumberWithDefaultZero(
116
+ modal_bottom_sheet_item_padding_right
117
+ );
118
+
119
+ const calculatedMaxWidth =
76
120
  sheetWidth -
77
- (modal_bottom_sheet_item_icon_width +
78
- modal_bottom_sheet_item_icon_margin_left +
79
- modal_bottom_sheet_item_icon_margin_right +
80
- modal_bottom_sheet_item_margin_left +
81
- modal_bottom_sheet_item_margin_right +
82
- modal_bottom_sheet_item_padding_left +
83
- modal_bottom_sheet_item_padding_right);
121
+ (iconWidth +
122
+ iconMarginLeft +
123
+ iconMarginRight +
124
+ itemMarginLeft +
125
+ itemMarginRight +
126
+ itemPaddingLeft +
127
+ itemPaddingRight);
128
+
129
+ const maxWidth =
130
+ Number.isNaN(calculatedMaxWidth) || calculatedMaxWidth <= 0
131
+ ? sheetWidth
132
+ : calculatedMaxWidth;
133
+
134
+ const label1Default = blockItemStyle?.textLabel1?.default;
84
135
 
85
136
  return {
86
137
  fontFamily: platformSelect({
@@ -91,8 +142,11 @@ export function defaultItemLabelProps(
91
142
  ios: modal_bottom_sheet_item_label_ios_letter_spacing,
92
143
  android: modal_bottom_sheet_item_label_android_letter_spacing,
93
144
  }),
94
- fontSize: modal_bottom_sheet_item_label_font_size,
95
- color: modal_bottom_sheet_item_label_font_color,
145
+ fontSize: toNumberWithDefault(
146
+ modal_bottom_sheet_item_label_font_size,
147
+ label1Default?.fontSize
148
+ ),
149
+ color: label1Default?.fontColor || modal_bottom_sheet_item_label_font_color,
96
150
  focusColor: modal_bottom_sheet_item_label_focus_font_color,
97
151
  hoverSelectedColor: modal_bottom_sheet_item_label_hover_selected_font_color,
98
152
  selectedColor: modal_bottom_sheet_item_label_selected_font_color,
@@ -146,7 +200,8 @@ export function getItemLabelProps(
146
200
  width: number,
147
201
  labelProps?:
148
202
  | ((theme: PluginConfiguration, width: number) => ItemLabelProps)
149
- | ItemLabelProps
203
+ | ItemLabelProps,
204
+ blockItemStyle?: Record<string, any>
150
205
  ) {
151
206
  if (labelProps) {
152
207
  return typeof labelProps === "function"
@@ -154,7 +209,7 @@ export function getItemLabelProps(
154
209
  : labelProps;
155
210
  }
156
211
 
157
- return defaultItemLabelProps(theme, width);
212
+ return defaultItemLabelProps(theme, width, blockItemStyle);
158
213
  }
159
214
 
160
215
  export function getItemProps(
@@ -162,7 +217,8 @@ export function getItemProps(
162
217
  width: number,
163
218
  itemProps?:
164
219
  | ((theme: PluginConfiguration, width: number) => ItemProps)
165
- | ItemProps
220
+ | ItemProps,
221
+ blockItemStyle?: Record<string, any>
166
222
  ) {
167
223
  if (itemProps) {
168
224
  return typeof itemProps === "function"
@@ -170,5 +226,5 @@ export function getItemProps(
170
226
  : itemProps;
171
227
  }
172
228
 
173
- return defaultItemProps(theme, width);
229
+ return defaultItemProps(theme, width, blockItemStyle);
174
230
  }
@@ -9,6 +9,7 @@ import {
9
9
  platformSelect,
10
10
  isAndroidTVPlatform,
11
11
  isTvOSPlatform,
12
+ isApplePlatform,
12
13
  } from "@applicaster/zapp-react-native-utils/reactUtils";
13
14
  import {
14
15
  isAudioItem,
@@ -60,6 +61,7 @@ import {
60
61
  PlayerNativeSendCommand,
61
62
  } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
62
63
  import { useAppData } from "@applicaster/zapp-react-native-redux";
64
+ import { PLAYER_EVENTS } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/const";
63
65
 
64
66
  type Props = {
65
67
  Player: React.ComponentType<any>;
@@ -188,12 +190,10 @@ const renderApplePlayer = ({
188
190
  return null;
189
191
  }
190
192
 
191
- const { title, summary } = item || {};
192
-
193
+ // Title/Subtitle are not resolved here: `ProgramInfo` reads them from the
194
+ // player manager's content channel via `usePlayerContent`.
193
195
  return (
194
196
  <ProgramInfo
195
- title={title}
196
- subtitle={summary}
197
197
  plugin_configuration={pluginConfiguration}
198
198
  videoStyle={videoStyle}
199
199
  />
@@ -282,12 +282,16 @@ const PlayerContainerComponent = (props: Props) => {
282
282
  }
283
283
 
284
284
  log_debug(
285
- `onPlayNextPerformNextVideoPlay: delay completed, replaceTop to item: ${playNextOverlayState.entry.title}, id: ${playNextOverlayState.entry.id}`
285
+ `onPlayNextPerformNextVideoPlay: delay completed, replaceTop to item: ${playNextOverlayState.entry.title}, id: ${playNextOverlayState.entry.id}, outgoing item id: ${item?.id}`
286
286
  );
287
287
 
288
+ playNextOverlayState.hidePlayNext();
289
+
290
+ playerEvent(PLAYER_EVENTS.PlayNextTriggered, { id: item?.id });
291
+
288
292
  setIsLoadingNextVideo(true);
289
293
  playEntry(playNextOverlayState.entry);
290
- }, [playNextOverlayState]);
294
+ }, [playNextOverlayState, item?.id]);
291
295
 
292
296
  const playNextData: Nullable<PlayNextData> = React.useMemo(() => {
293
297
  if (!playNextOverlayState) {
@@ -495,7 +499,7 @@ const PlayerContainerComponent = (props: Props) => {
495
499
  const isAudioContent = isAudioItem(item);
496
500
 
497
501
  useEffect(() => {
498
- if (!isAudioContent) {
502
+ if (!isAudioContent && isApplePlatform()) {
499
503
  sendQuickBrickEvent(
500
504
  QUICK_BRICK_EVENTS.IDLE_TIMER_DISABLED as QuickBrickEvent,
501
505
  {
@@ -7,12 +7,11 @@ import * as React from "react";
7
7
  import { Text, TextStyle, View, ViewStyle } from "react-native";
8
8
  import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
9
9
 
10
+ import { usePlayerContent } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerContent";
10
11
  import * as programStyles from "./styles";
11
12
 
12
13
  type Props = {
13
14
  logo?: string;
14
- title: string;
15
- subtitle: string;
16
15
  isAudioContent: boolean;
17
16
  styles: {};
18
17
  plugin_configuration: {
@@ -28,13 +27,13 @@ const defaultColor = "#EFEFEF";
28
27
 
29
28
  function ProgramInfoComponent({
30
29
  logo,
31
- title = "",
32
- subtitle = "",
33
30
  isAudioContent,
34
31
  styles,
35
32
  plugin_configuration = {},
36
33
  videoStyle = {},
37
34
  }: Props) {
35
+ const { title = "", summary: subtitle = "" } = usePlayerContent();
36
+
38
37
  const platformKey = styleKeys.style_namespace;
39
38
 
40
39
  const colorTitle =
@@ -17,16 +17,37 @@ jest.mock(
17
17
  );
18
18
 
19
19
  jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
20
+ // Defaults to `false` for the hardware-back-handling tests below, which
21
+ // key off `isTV`. The ProgramInfo/content-context describe block below
22
+ // overrides this per test (`isTV()` is also what PlayerContainer's
23
+ // `playerContentValue` uses to pick TV vs mobile data keys, decoupled
24
+ // from `isTvOSPlatform` below).
20
25
  isTV: jest.fn(() => false),
21
26
  isAndroidTVPlatform: jest.fn(() => false),
22
- isTvOSPlatform: jest.fn(() => false),
27
+ // `isTvOSPlatform` backs a module-level constant in PlayerContainer.tsx that
28
+ // is read once at import time, so it must already be `true` here in order
29
+ // to exercise `renderApplePlayer`'s tvOS-only ProgramInfo branch in this
30
+ // test file. It does not affect the hardware-back-handling tests below,
31
+ // which key off `isTV` instead.
32
+ isTvOSPlatform: jest.fn(() => true),
33
+ isApplePlatform: jest.fn(() => true),
23
34
  platformSelect: jest.fn(({ native }) => native),
24
35
  }));
25
36
 
26
- jest.mock("@applicaster/zapp-react-native-utils/playerUtils", () => ({
27
- isAudioItem: jest.fn(() => false),
28
- isInlineTV: jest.fn(() => false),
29
- }));
37
+ jest.mock("@applicaster/zapp-react-native-utils/playerUtils", () => {
38
+ // Keep the real data-key resolver (createConfigValueGetter,
39
+ // resolvePlayerContentText, VIDEO_PLAYER_CONTENT_DATA_KEYS) so the tvOS
40
+ // ProgramInfo data-key tests exercise actual resolution logic, not a stub.
41
+ const actual = jest.requireActual(
42
+ "@applicaster/zapp-react-native-utils/playerUtils"
43
+ );
44
+
45
+ return {
46
+ ...actual,
47
+ isAudioItem: jest.fn(() => false),
48
+ isInlineTV: jest.fn(() => false),
49
+ };
50
+ });
30
51
 
31
52
  jest.mock(
32
53
  "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent",
@@ -75,6 +96,11 @@ jest.mock("@applicaster/zapp-react-native-bridge/QuickBrick", () => ({
75
96
  sendQuickBrickEvent: jest.fn(),
76
97
  }));
77
98
 
99
+ // Stubbed so PlayerContainer can render without ProgramInfo's own
100
+ // redux/style plumbing. It no longer needs to capture Title/Subtitle: those
101
+ // come from the player manager's content channel, and the key-set selection
102
+ // they depend on is covered directly in
103
+ // `playerManager/__tests__/playerContent.test.ts`.
78
104
  jest.mock("../ProgramInfo", () => ({
79
105
  ProgramInfo: () => null,
80
106
  }));
@@ -142,14 +168,33 @@ jest.mock(
142
168
  jest.mock("../PlayerContainerContext", () => {
143
169
  const ReactActual = require("react");
144
170
 
171
+ const PlayerContainerContext = ReactActual.createContext({
172
+ isLanguageOverlayVisible: false,
173
+ bottomFocusableId: "bottom",
174
+ showComponentsContainer: false,
175
+ refs: null,
176
+ });
177
+
145
178
  return {
146
- PlayerContainerContext: ReactActual.createContext({
147
- isLanguageOverlayVisible: false,
148
- bottomFocusableId: "bottom",
149
- showComponentsContainer: false,
150
- refs: null,
151
- }),
152
- PlayerContainerContextProvider: ({ children }) => children,
179
+ PlayerContainerContext,
180
+ // Mirrors just enough of the real provider for these tests: renders an
181
+ // actual `PlayerContainerContext.Provider` so the real
182
+ // `PlayerContainerContext.Consumer` inside PlayerContainer.tsx sees the
183
+ // container fields a real provider would give it, instead of a bare
184
+ // `({ children }) => children` passthrough.
185
+ PlayerContainerContextProvider: ({ children }: any) =>
186
+ ReactActual.createElement(
187
+ PlayerContainerContext.Provider,
188
+ {
189
+ value: {
190
+ isLanguageOverlayVisible: false,
191
+ bottomFocusableId: "bottom",
192
+ showComponentsContainer: false,
193
+ refs: null,
194
+ },
195
+ },
196
+ children
197
+ ),
153
198
  };
154
199
  });
155
200
 
@@ -200,7 +245,14 @@ const { __player: mockPlayer } = jest.requireMock(
200
245
  "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer"
201
246
  );
202
247
 
203
- const Player = React.forwardRef(() => null);
248
+ const { isTV: mockIsTV } = jest.requireMock(
249
+ "@applicaster/zapp-react-native-utils/reactUtils"
250
+ );
251
+
252
+ // Renders children so that `renderApplePlayer`'s returned <ProgramInfo>
253
+ // element (passed as this component's `children` prop) actually mounts —
254
+ // otherwise React never invokes the ProgramInfo function component at all.
255
+ const Player = React.forwardRef((props: any, _ref) => props.children ?? null);
204
256
 
205
257
  const item = {
206
258
  id: "entry-1",
@@ -234,6 +286,7 @@ const pressHardwareBack = () => {
234
286
  describe("PlayerContainer hardware back handling", () => {
235
287
  beforeEach(() => {
236
288
  jest.clearAllMocks();
289
+ mockIsTV.mockReturnValue(false);
237
290
  mockBackHandlerRef.current = null;
238
291
  mockPlayer.getPluginConfiguration.mockReturnValue({});
239
292
  mockPlayer.isPaused.mockReturnValue(false);
@@ -5,7 +5,7 @@ import {
5
5
  } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
6
6
  import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
7
7
  import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
8
- import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
8
+ import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/const";
9
9
  import { loggerLiveImageManager } from "./loggerHelper";
10
10
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
11
11
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "16.0.0-alpha.2529997432",
3
+ "version": "16.0.0-alpha.2663208063",
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",
@@ -28,12 +28,13 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "16.0.0-alpha.2529997432",
32
- "@applicaster/zapp-react-native-bridge": "16.0.0-alpha.2529997432",
33
- "@applicaster/zapp-react-native-redux": "16.0.0-alpha.2529997432",
34
- "@applicaster/zapp-react-native-utils": "16.0.0-alpha.2529997432",
31
+ "@applicaster/applicaster-types": "16.0.0-alpha.2663208063",
32
+ "@applicaster/zapp-react-native-bridge": "16.0.0-alpha.2663208063",
33
+ "@applicaster/zapp-react-native-redux": "16.0.0-alpha.2663208063",
34
+ "@applicaster/zapp-react-native-utils": "16.0.0-alpha.2663208063",
35
35
  "fast-json-stable-stringify": "^2.1.0",
36
36
  "promise": "^8.3.0",
37
+ "react-native-sortables": "1.7.1",
37
38
  "url": "^0.11.0",
38
39
  "uuid": "^3.3.2"
39
40
  },