@applicaster/zapp-react-native-ui-components 16.0.0-alpha.1593888345 → 16.0.0-alpha.1701179921

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 (48) hide show
  1. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  2. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  3. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  4. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  5. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  6. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
  7. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  8. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -2
  9. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +4 -2
  10. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  11. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +5 -2
  12. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +4 -1
  13. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +58 -73
  14. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +65 -56
  15. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +140 -65
  16. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +93 -46
  17. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +148 -32
  18. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
  19. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  20. package/Components/ModalComponent/AudioPlayer/Components/index.ts +0 -2
  21. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +132 -6
  22. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +202 -13
  23. package/Components/ModalComponent/BottomSheetModalContent.tsx +187 -73
  24. package/Components/ModalComponent/SortableList.tsx +36 -22
  25. package/Components/ModalComponent/TextInputContent.tsx +42 -7
  26. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +111 -6
  27. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +50 -1
  28. package/Components/ModalComponent/index.tsx +7 -9
  29. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +24 -0
  30. package/Components/ModalComponent/presets/selectableCell.tsx +1 -1
  31. package/Components/ModalComponent/showTextInput.ts +11 -2
  32. package/Components/PlayerContainer/PlayerContainer.tsx +8 -1
  33. package/Components/River/ComponentsMap/ComponentsMap.tsx +10 -12
  34. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +138 -75
  35. package/Components/River/__tests__/componentsMap.test.js +8 -3
  36. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  37. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  38. package/Components/Screen/index.tsx +5 -0
  39. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +1 -1
  40. package/Components/Transitioner/Transitioner.tsx +2 -3
  41. package/Components/Transitioner/__tests__/transitioner.test.js +83 -2
  42. package/Components/VideoLive/LiveImageManager.ts +8 -2
  43. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  44. package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  45. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  46. package/assets/empty-Info.png +0 -0
  47. package/package.json +5 -5
  48. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -314
@@ -82,18 +82,26 @@ jest.mock("../AudioPlayer/Components/Item", () => ({
82
82
  VARIANT_PLAYLIST_ITEM: {},
83
83
  }));
84
84
 
85
+ const mockAudioPlayerButtonProps: Array<any> = [];
86
+ const mockNowPlayingHeaderProps: Array<any> = [];
87
+
85
88
  jest.mock("../AudioPlayer/Components", () => ({
86
- NowPlayingHeaderSection: () => null,
87
- AudioPlayerButton: ({ data, onPress }: any) => {
89
+ NowPlayingHeaderSection: (props: any) => {
90
+ mockNowPlayingHeaderProps.push(props);
91
+
92
+ return null;
93
+ },
94
+ AudioPlayerButton: (props: any) => {
88
95
  const { Text } = require("react-native");
89
96
 
97
+ mockAudioPlayerButtonProps.push(props);
98
+
90
99
  return (
91
- <Text testID="create-playlist-button" onPress={onPress}>
92
- {data.title}
100
+ <Text testID="create-playlist-button" onPress={props.onPress}>
101
+ {props.data?.title}
93
102
  </Text>
94
103
  );
95
104
  },
96
- VARIANT_WITH_ICON: {},
97
105
  }));
98
106
 
99
107
  const baseProps = {
@@ -171,6 +179,8 @@ describe("BottomSheetModalContent role/behavior cells", () => {
171
179
  });
172
180
 
173
181
  it("renders create playlist button when operations include add and calls editableCollection.add on press", () => {
182
+ mockAudioPlayerButtonProps.length = 0;
183
+
174
184
  const addMock = jest.fn();
175
185
  const { BehaviorSubject } = require("rxjs");
176
186
 
@@ -192,13 +202,91 @@ describe("BottomSheetModalContent role/behavior cells", () => {
192
202
  const createBtn = screen.getByTestId("create-playlist-button");
193
203
  expect(createBtn).toBeTruthy();
194
204
 
205
+ // The button is rendered bare: styling comes from the modal blocks theme
206
+ // and the title from the button block, so no configuration/data is passed.
207
+ expect(mockAudioPlayerButtonProps.length).toBeGreaterThan(0);
208
+
209
+ for (const props of mockAudioPlayerButtonProps) {
210
+ expect(props.configuration).toBeUndefined();
211
+ expect(props.data).toBeUndefined();
212
+ expect(typeof props.onPress).toBe("function");
213
+ }
214
+
195
215
  const { fireEvent } = require("@testing-library/react-native");
196
216
  fireEvent.press(createBtn);
197
217
 
198
218
  expect(addMock).toHaveBeenCalledWith({
199
219
  id: "create_new_playlist",
200
- title: "Create New Playlist",
220
+ title: "unknown title",
221
+ });
222
+ });
223
+
224
+ it("shows the empty Next Up message only when now playing is on and the list is empty", () => {
225
+ mockNowPlayingHeaderProps.length = 0;
226
+ const { BehaviorSubject } = require("rxjs");
227
+
228
+ const emptyQueue = new ContentViewModel({
229
+ title: "Queue",
230
+ items: [],
231
+ role: "dynamic_collection",
232
+ dynamicCollection: {
233
+ operations: ["nowPlaying", "remove", "reorder", "clearAll"],
234
+ },
235
+ });
236
+
237
+ emptyQueue.editableCollection = {
238
+ items$: new BehaviorSubject([]),
239
+ operations: ["nowPlaying", "remove", "reorder", "clearAll"],
240
+ move: jest.fn(),
241
+ };
242
+
243
+ const { rerender } = render(
244
+ <BottomSheetModalContent
245
+ {...baseProps}
246
+ items={[]}
247
+ emptyMessage="Queued items will be added here"
248
+ viewModel={emptyQueue}
249
+ />
250
+ );
251
+
252
+ expect(mockNowPlayingHeaderProps.at(-1)).toMatchObject({
253
+ isEmpty: true,
254
+ emptyMessage: "Queued items will be added here",
255
+ });
256
+
257
+ const withItem = new ContentViewModel({
258
+ title: "Queue",
259
+ items: [{ id: "t1", title: "Track 1" }],
260
+ role: "dynamic_collection",
261
+ dynamicCollection: {
262
+ operations: ["nowPlaying", "remove", "reorder", "clearAll"],
263
+ },
201
264
  });
265
+
266
+ withItem.editableCollection = {
267
+ items$: new BehaviorSubject([{ id: "t1", title: "Track 1" }]),
268
+ operations: ["nowPlaying", "remove", "reorder", "clearAll"],
269
+ move: jest.fn(),
270
+ };
271
+
272
+ rerender(
273
+ <BottomSheetModalContent
274
+ {...baseProps}
275
+ items={[{ id: "t1", title: "Track 1", label: "Track 1" }]}
276
+ emptyMessage="Queued items will be added here"
277
+ viewModel={withItem}
278
+ />
279
+ );
280
+
281
+ expect(mockNowPlayingHeaderProps.at(-1)).toMatchObject({
282
+ isEmpty: false,
283
+ });
284
+
285
+ mockNowPlayingHeaderProps.length = 0;
286
+
287
+ render(<BottomSheetModalContent {...baseProps} />);
288
+
289
+ expect(mockNowPlayingHeaderProps).toHaveLength(0);
202
290
  });
203
291
 
204
292
  it("honors disableScrollViewWrap in contentComponentProps to bypass ScrollView wrapping", () => {
@@ -235,4 +323,21 @@ describe("BottomSheetModalContent role/behavior cells", () => {
235
323
  const { ScrollView } = require("react-native");
236
324
  expect(() => UNSAFE_getByType(ScrollView)).toThrow();
237
325
  });
326
+
327
+ it("sets keyboardShouldPersistTaps='handled' on ScrollView wrapping contentComponent", () => {
328
+ const CustomComponent = () => (
329
+ <React.Fragment>Custom Content</React.Fragment>
330
+ );
331
+
332
+ const { UNSAFE_getByType } = render(
333
+ <BottomSheetModalContent
334
+ {...baseProps}
335
+ contentComponent={CustomComponent}
336
+ />
337
+ );
338
+
339
+ const { ScrollView } = require("react-native");
340
+ const scrollView = UNSAFE_getByType(ScrollView);
341
+ expect(scrollView.props.keyboardShouldPersistTaps).toBe("handled");
342
+ });
238
343
  });
@@ -19,7 +19,7 @@ jest.mock(
19
19
  );
20
20
 
21
21
  jest.mock("../AudioPlayer/Components/Input", () => ({
22
- AudioPlayerInput: ({ value, onChangeText, data }: any) => {
22
+ AudioPlayerInput: ({ value, onChangeText, data, validationMessage }: any) => {
23
23
  const { TextInput, Text } = require("react-native");
24
24
 
25
25
  return (
@@ -31,6 +31,9 @@ jest.mock("../AudioPlayer/Components/Input", () => ({
31
31
  onChangeText={onChangeText}
32
32
  placeholder={data?.placeholder}
33
33
  />
34
+ {validationMessage ? (
35
+ <Text testID="input-validation-message">{validationMessage}</Text>
36
+ ) : null}
34
37
  </>
35
38
  );
36
39
  },
@@ -87,6 +90,16 @@ describe("TextInputContent", () => {
87
90
  expect(screen.getByText("Update")).toBeTruthy();
88
91
  });
89
92
 
93
+ it("shows validation below the input when its value is too long", () => {
94
+ render(<TextInputContent maxLength={100} {...baseProps} />);
95
+
96
+ fireEvent.changeText(screen.getByTestId("playlist-input"), "x".repeat(101));
97
+
98
+ expect(screen.getByTestId("input-validation-message")).toHaveTextContent(
99
+ "Too many characters"
100
+ );
101
+ });
102
+
90
103
  it("on submit merges name into sendCloudEvent data then dismisses", async () => {
91
104
  render(<TextInputContent {...baseProps} />);
92
105
 
@@ -117,4 +130,40 @@ describe("TextInputContent", () => {
117
130
  type: "dismissBottomSheet",
118
131
  });
119
132
  });
133
+
134
+ it("forwards actionContext into handleActions so rename can refresh the List", async () => {
135
+ const actionContext = {
136
+ component: {
137
+ id: "list-1",
138
+ data: { source: "https://example.com/user/collections/abc" },
139
+ },
140
+ screenData: { id: "playlist-screen" },
141
+ };
142
+
143
+ render(<TextInputContent {...baseProps} actionContext={actionContext} />);
144
+
145
+ fireEvent.press(screen.getByTestId("submit-button"));
146
+
147
+ await waitFor(() => {
148
+ expect(actionExecutor.handleActions).toHaveBeenCalledTimes(1);
149
+ });
150
+
151
+ expect(actionExecutor.handleActions).toHaveBeenCalledWith(
152
+ [
153
+ {
154
+ type: "sendCloudEvent",
155
+ options: {
156
+ url: "https://server.com/cloud-events",
157
+ type: "com.applicaster.collection.create.v1",
158
+ subject: "edit_collection",
159
+ data: {
160
+ collectionId: "playlist-123",
161
+ name: "Summer Hits",
162
+ },
163
+ },
164
+ },
165
+ ],
166
+ actionContext
167
+ );
168
+ });
120
169
  });
@@ -26,20 +26,18 @@ type Props = {
26
26
  export function ModalComponent(props: ModalBottomSheetContentProps & Props) {
27
27
  const [height, setHeight] = useState(0);
28
28
 
29
- const onLayout = useCallback(
30
- ({ nativeEvent }) => {
31
- if (height === 0) {
32
- setHeight(nativeEvent.layout.height);
33
- }
34
- },
35
- [height]
36
- );
29
+ const onLayout = useCallback(({ nativeEvent }) => {
30
+ setHeight((value) => (value === 0 ? nativeEvent.layout.height : value));
31
+ }, []);
37
32
 
38
33
  if (height === 0) {
39
34
  return (
40
35
  <MeasurementsPortal
41
36
  Component={BottomSheetModalContent}
42
- componentProps={props}
37
+ componentProps={{
38
+ ...props,
39
+ measurementPhase: true,
40
+ }}
43
41
  onLayout={onLayout}
44
42
  />
45
43
  );
@@ -1,3 +1,6 @@
1
+ import React from "react";
2
+ import { Pressable } from "react-native";
3
+ import { fireEvent, render, screen } from "@testing-library/react-native";
1
4
  import { getCell } from "../index";
2
5
  import { standardCell } from "../standardCell";
3
6
  import { selectableCell } from "../selectableCell";
@@ -64,3 +67,24 @@ describe("mapMenuItemToPlaylistData", () => {
64
67
  expect(data.trailingButton).toBeUndefined();
65
68
  });
66
69
  });
70
+
71
+ describe("selectableCell checkbox press", () => {
72
+ it("invokes onPress with the playlist item when the checkbox is pressed", () => {
73
+ const onPress = jest.fn();
74
+ const item = { id: "queue", title: "Queue" };
75
+
76
+ render(
77
+ selectableCell.renderItem({
78
+ item,
79
+ index: 0,
80
+ onPress,
81
+ context: { behavior: { selectMode: "multi" } } as any,
82
+ }) as React.ReactElement
83
+ );
84
+
85
+ const pressables = screen.UNSAFE_getAllByType(Pressable);
86
+ fireEvent.press(pressables[pressables.length - 1]);
87
+
88
+ expect(onPress).toHaveBeenCalledWith(item);
89
+ });
90
+ });
@@ -21,7 +21,7 @@ export const selectableCell: CellRenderer = {
21
21
  title: item.title,
22
22
  action: item.secondaryAction!.action,
23
23
  })
24
- : undefined
24
+ : () => onPress(item)
25
25
  }
26
26
  />
27
27
  ),
@@ -13,8 +13,15 @@ export async function showTextInputAction(
13
13
  action: ActionType,
14
14
  context?: Record<string, any>
15
15
  ): Promise<ActionResult> {
16
- const { headerTitle, inputLabel, defaultValue, buttonLabel, actions } =
17
- action.options || {};
16
+ const {
17
+ headerTitle,
18
+ inputLabel,
19
+ defaultValue,
20
+ buttonLabel,
21
+ validationLabel,
22
+ actions,
23
+ maxLength,
24
+ } = action.options || {};
18
25
 
19
26
  if (!headerTitle || !buttonLabel || !actions || !actions.length) {
20
27
  return ActionResult.Error;
@@ -30,10 +37,12 @@ export async function showTextInputAction(
30
37
  content: {
31
38
  component: TextInputContent,
32
39
  props: {
40
+ maxLength,
33
41
  inputLabel,
34
42
  defaultValue: defaultValue ?? "",
35
43
  buttonLabel,
36
44
  actions,
45
+ validationLabel,
37
46
  },
38
47
  },
39
48
  },
@@ -404,10 +404,17 @@ const PlayerContainerComponent = (props: Props) => {
404
404
  const { eventType } = event;
405
405
 
406
406
  if (!isLanguageOverlayVisible && eventType === "menu") {
407
+ // First Back dismisses Play Next, the next one closes the player
408
+ if (playNextOverlayState) {
409
+ playNextOverlayState.handleUserCancelPlayNext();
410
+
411
+ return;
412
+ }
413
+
407
414
  close();
408
415
  }
409
416
  },
410
- [close]
417
+ [close, playNextOverlayState]
411
418
  );
412
419
 
413
420
  // Effects
@@ -1,5 +1,4 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
3
2
  import { FlatList, StyleSheet, View } from "react-native";
4
3
  import { SafeAreaView, EdgeMode, Edge } from "react-native-safe-area-context";
5
4
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
@@ -59,7 +58,7 @@ const getNearestValue = (value, optionA, optionB) =>
59
58
  Math.abs(value - optionA) < Math.abs(value - optionB) ? optionA : optionB;
60
59
 
61
60
  const scrollIndicatorInsets = { right: 1 };
62
- const keyExtractor = R.compose(String, R.prop("id"));
61
+ const keyExtractor = (item) => item.id.toString();
63
62
 
64
63
  function ComponentsMapComponent(props: Props) {
65
64
  const {
@@ -85,7 +84,7 @@ function ComponentsMapComponent(props: Props) {
85
84
 
86
85
  const riverComponents = React.useMemo(() => {
87
86
  if (feed?.entry?.length < components.length) {
88
- return R.slice(0, feed?.entry?.length, components);
87
+ return components.slice(0, feed?.entry?.length);
89
88
  }
90
89
 
91
90
  return components;
@@ -100,7 +99,7 @@ function ComponentsMapComponent(props: Props) {
100
99
  const { loadingState, onLoadFinished, onLoadFailed, shouldShowLoadingError } =
101
100
  useLoadingState(riverComponents.length, onLoadDone);
102
101
 
103
- const theme = useTheme();
102
+ const theme = useTheme<BaseThemePropertiesMobile>();
104
103
 
105
104
  const renderRiverItem = React.useCallback(
106
105
  ({ item, index }) => {
@@ -131,11 +130,11 @@ function ComponentsMapComponent(props: Props) {
131
130
  () => ({
132
131
  paddingLeft: ifEmptyUseFallback(
133
132
  screenConfig.paddingLeft,
134
- R.prop("screen_padding_left")(theme)
133
+ theme.screen_padding_left
135
134
  ),
136
135
  paddingRight: ifEmptyUseFallback(
137
136
  screenConfig.paddingRight,
138
- R.prop("screen_padding_right")(theme)
137
+ theme.screen_padding_right
139
138
  ),
140
139
  }),
141
140
  [riverId]
@@ -270,11 +269,11 @@ function ComponentsMapComponent(props: Props) {
270
269
  <FlatList
271
270
  ListHeaderComponent={
272
271
  <SafeAreaView
273
- mode="margin"
272
+ mode={safeArea?.mode ?? "margin"}
274
273
  style={{
275
274
  paddingTop: ifEmptyUseFallback(
276
275
  screenConfig.paddingTop,
277
- R.prop("screen_padding_top")(theme)
276
+ theme.screen_padding_top
278
277
  ),
279
278
  height: StyleSheet.hairlineWidth,
280
279
  }}
@@ -307,11 +306,11 @@ function ComponentsMapComponent(props: Props) {
307
306
  loadingState={loadingState}
308
307
  />
309
308
  <SafeAreaView
310
- mode="margin"
309
+ mode={safeArea?.mode ?? "margin"}
311
310
  style={{
312
311
  paddingBottom: ifEmptyUseFallback(
313
312
  screenConfig.paddingBottom,
314
- R.prop("screen_padding_bottom")(theme)
313
+ theme.screen_padding_bottom
315
314
  ),
316
315
  height: StyleSheet.hairlineWidth,
317
316
  }}
@@ -348,6 +347,5 @@ function ComponentsMapComponent(props: Props) {
348
347
  }
349
348
 
350
349
  export const ComponentsMap = React.memo(
351
- withComponentsMapProvider(ComponentsMapComponent),
352
- R.equals
350
+ withComponentsMapProvider(ComponentsMapComponent)
353
351
  );
@@ -14,95 +14,125 @@ exports[`componentsMap renders renders components map correctly 1`] = `
14
14
  >
15
15
  <RCTScrollView
16
16
  ListFooterComponent={
17
- <Memo(RiverFooterComponent)
18
- flatListHeight={null}
19
- loadingState={
20
- BehaviorSubject {
21
- "_value": {
22
- "done": false,
23
- "index": -1,
24
- "waitForAllComponents": false,
25
- },
26
- "closed": false,
27
- "currentObservers": null,
28
- "hasError": false,
29
- "isStopped": false,
30
- "observers": [
31
- SafeSubscriber {
32
- "_finalizers": [
33
- Subscription {
34
- "_finalizers": null,
35
- "_parentage": [Circular],
36
- "closed": false,
37
- "initialTeardown": [Function],
38
- },
39
- ],
40
- "_parentage": null,
41
- "closed": false,
42
- "destination": ConsumerObserver {
43
- "partialObserver": {
44
- "complete": undefined,
45
- "error": undefined,
46
- "next": [Function],
47
- },
48
- },
49
- "initialTeardown": undefined,
50
- "isStopped": false,
17
+ <React.Fragment>
18
+ <Memo(RiverFooterComponent)
19
+ flatListHeight={null}
20
+ loadingState={
21
+ BehaviorSubject {
22
+ "_value": {
23
+ "done": false,
24
+ "index": -1,
25
+ "waitForAllComponents": false,
51
26
  },
52
- SafeSubscriber {
53
- "_finalizers": [
54
- Subscription {
55
- "_finalizers": null,
56
- "_parentage": [Circular],
57
- "closed": false,
58
- "initialTeardown": [Function],
59
- },
60
- ],
61
- "_parentage": null,
62
- "closed": false,
63
- "destination": ConsumerObserver {
64
- "partialObserver": {
65
- "complete": undefined,
66
- "error": undefined,
67
- "next": [Function],
27
+ "closed": false,
28
+ "currentObservers": null,
29
+ "hasError": false,
30
+ "isStopped": false,
31
+ "observers": [
32
+ SafeSubscriber {
33
+ "_finalizers": [
34
+ Subscription {
35
+ "_finalizers": null,
36
+ "_parentage": [Circular],
37
+ "closed": false,
38
+ "initialTeardown": [Function],
39
+ },
40
+ ],
41
+ "_parentage": null,
42
+ "closed": false,
43
+ "destination": ConsumerObserver {
44
+ "partialObserver": {
45
+ "complete": undefined,
46
+ "error": undefined,
47
+ "next": [Function],
48
+ },
68
49
  },
50
+ "initialTeardown": undefined,
51
+ "isStopped": false,
69
52
  },
70
- "initialTeardown": undefined,
71
- "isStopped": false,
72
- },
73
- SafeSubscriber {
74
- "_finalizers": [
75
- Subscription {
76
- "_finalizers": null,
77
- "_parentage": [Circular],
78
- "closed": false,
79
- "initialTeardown": [Function],
53
+ SafeSubscriber {
54
+ "_finalizers": [
55
+ Subscription {
56
+ "_finalizers": null,
57
+ "_parentage": [Circular],
58
+ "closed": false,
59
+ "initialTeardown": [Function],
60
+ },
61
+ ],
62
+ "_parentage": null,
63
+ "closed": false,
64
+ "destination": ConsumerObserver {
65
+ "partialObserver": {
66
+ "complete": undefined,
67
+ "error": undefined,
68
+ "next": [Function],
69
+ },
80
70
  },
81
- ],
82
- "_parentage": null,
83
- "closed": false,
84
- "destination": ConsumerObserver {
85
- "partialObserver": {
86
- "complete": undefined,
87
- "error": undefined,
88
- "next": [Function],
71
+ "initialTeardown": undefined,
72
+ "isStopped": false,
73
+ },
74
+ SafeSubscriber {
75
+ "_finalizers": [
76
+ Subscription {
77
+ "_finalizers": null,
78
+ "_parentage": [Circular],
79
+ "closed": false,
80
+ "initialTeardown": [Function],
81
+ },
82
+ ],
83
+ "_parentage": null,
84
+ "closed": false,
85
+ "destination": ConsumerObserver {
86
+ "partialObserver": {
87
+ "complete": undefined,
88
+ "error": undefined,
89
+ "next": [Function],
90
+ },
89
91
  },
92
+ "initialTeardown": undefined,
93
+ "isStopped": false,
90
94
  },
91
- "initialTeardown": undefined,
92
- "isStopped": false,
93
- },
94
- ],
95
- "thrownError": null,
95
+ ],
96
+ "thrownError": null,
97
+ }
98
+ }
99
+ />
100
+ <View
101
+ edges={
102
+ {
103
+ "bottom": "off",
104
+ }
105
+ }
106
+ mode="margin"
107
+ style={
108
+ {
109
+ "height": 0.5,
110
+ "paddingBottom": undefined,
111
+ }
112
+ }
113
+ />
114
+ </React.Fragment>
115
+ }
116
+ ListHeaderComponent={
117
+ <View
118
+ edges={
119
+ {
120
+ "top": "off",
121
+ }
122
+ }
123
+ mode="margin"
124
+ style={
125
+ {
126
+ "height": 0.5,
127
+ "paddingTop": undefined,
96
128
  }
97
129
  }
98
130
  />
99
131
  }
100
132
  contentContainerStyle={
101
133
  {
102
- "paddingBottom": undefined,
103
134
  "paddingLeft": undefined,
104
135
  "paddingRight": undefined,
105
- "paddingTop": undefined,
106
136
  }
107
137
  }
108
138
  data={
@@ -156,6 +186,25 @@ exports[`componentsMap renders renders components map correctly 1`] = `
156
186
  windowSize={12}
157
187
  >
158
188
  <View>
189
+ <View
190
+ collapsable={false}
191
+ onLayout={[Function]}
192
+ >
193
+ <View
194
+ edges={
195
+ {
196
+ "top": "off",
197
+ }
198
+ }
199
+ mode="margin"
200
+ style={
201
+ {
202
+ "height": 0.5,
203
+ "paddingTop": undefined,
204
+ }
205
+ }
206
+ />
207
+ </View>
159
208
  <View
160
209
  onFocusCapture={[Function]}
161
210
  onLayout={[Function]}
@@ -200,6 +249,20 @@ exports[`componentsMap renders renders components map correctly 1`] = `
200
249
  size="large"
201
250
  />
202
251
  </View>
252
+ <View
253
+ edges={
254
+ {
255
+ "bottom": "off",
256
+ }
257
+ }
258
+ mode="margin"
259
+ style={
260
+ {
261
+ "height": 0.5,
262
+ "paddingBottom": undefined,
263
+ }
264
+ }
265
+ />
203
266
  </View>
204
267
  </View>
205
268
  </RCTScrollView>