@applicaster/zapp-react-native-ui-components 16.0.0-rc.10 → 16.0.0-rc.101

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 (155) 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/Cell/Cell.tsx +3 -6
  5. package/Components/Cell/TvOSCellComponent.tsx +0 -1
  6. package/Components/CellRendererResolver/index.ts +2 -2
  7. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
  9. package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
  10. package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
  11. package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
  12. package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
  13. package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
  14. package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
  15. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
  16. package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
  17. package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
  18. package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
  19. package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
  20. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
  21. package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
  22. package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
  23. package/Components/GeneralContentScreen/index.ts +2 -0
  24. package/Components/Layout/FullWidthRow.tsx +38 -0
  25. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  26. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  28. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  29. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  30. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  31. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  32. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  33. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  34. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  35. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  36. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  37. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
  38. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  39. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  40. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  41. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  42. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  43. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  44. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  45. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  46. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  47. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  48. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  49. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  50. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  52. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  53. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  54. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  55. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -2
  56. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  57. package/Components/MasterCell/dataAdapter.ts +15 -5
  58. package/Components/MasterCell/hooks/index.ts +2 -0
  59. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  60. package/Components/MasterCell/index.tsx +30 -5
  61. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  62. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  63. package/Components/MasterCell/utils/index.ts +85 -46
  64. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
  65. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  66. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
  67. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  68. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
  69. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
  70. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
  71. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
  72. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1007 -0
  73. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
  74. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
  75. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  76. package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
  77. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +356 -0
  78. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +521 -0
  79. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  80. package/Components/ModalComponent/BottomSheetModalContent.tsx +505 -50
  81. package/Components/ModalComponent/Button/index.tsx +5 -3
  82. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  83. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  84. package/Components/ModalComponent/Header/index.tsx +20 -7
  85. package/Components/ModalComponent/Header/utils.ts +1 -1
  86. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  87. package/Components/ModalComponent/SortableList.tsx +156 -0
  88. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  89. package/Components/ModalComponent/TextInputContent.tsx +135 -0
  90. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  91. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
  92. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  93. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
  94. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  95. package/Components/ModalComponent/index.tsx +18 -9
  96. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
  97. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  98. package/Components/ModalComponent/presets/index.ts +27 -0
  99. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  100. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  101. package/Components/ModalComponent/presets/types.ts +35 -0
  102. package/Components/ModalComponent/showTextInput.ts +52 -0
  103. package/Components/ModalComponent/utils.ts +82 -21
  104. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  105. package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
  106. package/Components/OfflineHandler/hooks.ts +111 -0
  107. package/Components/OfflineHandler/index.tsx +51 -73
  108. package/Components/OfflineHandler/utils/index.ts +1 -13
  109. package/Components/PlayerContainer/PlayerContainer.tsx +25 -17
  110. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  111. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
  112. package/Components/PreloaderWrapper/index.tsx +1 -1
  113. package/Components/River/ComponentsMap/ComponentsMap.tsx +87 -61
  114. package/Components/River/River.tsx +4 -0
  115. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -89
  116. package/Components/River/__tests__/componentsMap.test.js +8 -3
  117. package/Components/River/__tests__/resultCallback.test.tsx +47 -0
  118. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  119. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  120. package/Components/Screen/index.tsx +13 -4
  121. package/Components/Screen/navigationHandler.ts +8 -8
  122. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  123. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  124. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  125. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  126. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  127. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
  128. package/Components/TopCutoffOverlay/index.tsx +2 -2
  129. package/Components/Transitioner/Transitioner.tsx +30 -20
  130. package/Components/Transitioner/__tests__/transitioner.test.js +83 -2
  131. package/Components/VideoLive/LiveImageManager.ts +9 -3
  132. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  133. package/Components/VideoModal/utils.ts +6 -1
  134. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
  135. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  136. package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
  137. package/Contexts/CachedDimensionsContext/index.ts +17 -2
  138. package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  139. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  140. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  141. package/Helpers/index.js +0 -39
  142. package/Hooks/useEntryActionsExpander.ts +63 -0
  143. package/assets/empty-Info.png +0 -0
  144. package/package.json +6 -5
  145. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  146. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  147. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  148. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  149. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  150. package/Components/Screen/utils.ts +0 -16
  151. package/Helpers/Analytics/index.js +0 -95
  152. /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
  153. /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
  154. /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
  155. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -0,0 +1,205 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { StyleSheet, Text, View } from "react-native";
3
+ import {
4
+ AudioPlayerTrackItem,
5
+ VARIANT_NOW_PLAYING,
6
+ mapMenuItemToNowPlayingData,
7
+ } from "./Item";
8
+ import { AudioPlayerHeader, VARIANT_SECTION_HEADER } from "./Header";
9
+ import type { MenuItem } from "@applicaster/zapp-react-native-utils/modalState/types";
10
+ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
11
+ import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/const";
12
+ import type { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
13
+
14
+ const DEFAULT_EMPTY_MESSAGE = "Queued items will be added here";
15
+
16
+ const styles = StyleSheet.create({
17
+ divider: {
18
+ height: StyleSheet.hairlineWidth,
19
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
20
+ marginHorizontal: 20,
21
+ marginVertical: 8,
22
+ },
23
+ emptyMessage: {
24
+ paddingTop: 32,
25
+ paddingBottom: 32,
26
+ paddingHorizontal: 40,
27
+ textAlign: "center",
28
+ color: "#999999",
29
+ fontSize: 13,
30
+ lineHeight: 16,
31
+ },
32
+ });
33
+
34
+ const isPrimaryOrCastingPlayer = (player?: Player | null): boolean => {
35
+ if (!player) {
36
+ return false;
37
+ }
38
+
39
+ return (
40
+ player.playerRole === PlayerRole.Primary ||
41
+ player.playerRole === PlayerRole.Chromecast
42
+ );
43
+ };
44
+
45
+ const getTargetPlayer = (): Player | null => {
46
+ if (playerManager.isCasting()) {
47
+ return playerManager.getCastingReceiver() || null;
48
+ }
49
+
50
+ const active = playerManager.getActivePlayer();
51
+
52
+ return isPrimaryOrCastingPlayer(active) ? active : null;
53
+ };
54
+
55
+ type NowPlayingHeaderSectionProps = {
56
+ onClear?: () => void;
57
+ nextUpTitle?: string;
58
+ nowPlayingTitle?: string;
59
+ isEmpty?: boolean;
60
+ emptyMessage?: string;
61
+ clearLabel?: string;
62
+ };
63
+
64
+ export function NowPlayingHeaderSection({
65
+ onClear,
66
+ nextUpTitle = "Next Up",
67
+ nowPlayingTitle = "Now Playing",
68
+ isEmpty = false,
69
+ emptyMessage = DEFAULT_EMPTY_MESSAGE,
70
+ clearLabel,
71
+ }: NowPlayingHeaderSectionProps) {
72
+ const [activePlayer, setActivePlayer] = useState<Player | null>(
73
+ getTargetPlayer
74
+ );
75
+
76
+ const [currentEntry, setCurrentEntry] = useState<ZappEntry | null>(
77
+ () => getTargetPlayer()?.entry || null
78
+ );
79
+
80
+ const [isPaused, setIsPaused] = useState<boolean>(() =>
81
+ Boolean(getTargetPlayer()?.isPaused())
82
+ );
83
+
84
+ useEffect(() => {
85
+ const handleActivePlayerUpdate = () => {
86
+ const player = getTargetPlayer();
87
+
88
+ if (player) {
89
+ setActivePlayer(player);
90
+
91
+ if (player.entry) {
92
+ setCurrentEntry(player.entry);
93
+ }
94
+
95
+ setIsPaused(Boolean(player.isPaused()));
96
+ }
97
+ };
98
+
99
+ handleActivePlayerUpdate();
100
+
101
+ const removeLifecycle = playerManager.addLifecycleListener({
102
+ onRegistered: (registeredPlayer) => {
103
+ if (isPrimaryOrCastingPlayer(registeredPlayer)) {
104
+ handleActivePlayerUpdate();
105
+ }
106
+ },
107
+ onCastingChanged: handleActivePlayerUpdate,
108
+ });
109
+
110
+ return () => {
111
+ removeLifecycle?.();
112
+ };
113
+ }, []);
114
+
115
+ useEffect(() => {
116
+ if (!activePlayer) {
117
+ return;
118
+ }
119
+
120
+ const syncPlayerState = () => {
121
+ if (activePlayer.entry) {
122
+ setCurrentEntry(activePlayer.entry);
123
+ }
124
+
125
+ setIsPaused(Boolean(activePlayer.isPaused()));
126
+ };
127
+
128
+ syncPlayerState();
129
+
130
+ const removeListener = activePlayer.addListener({
131
+ id: "queue-now-playing-header",
132
+ listener: {
133
+ onPlayerPause: () => setIsPaused(true),
134
+ onPlayerResume: () => setIsPaused(false),
135
+ onVideoLoad: syncPlayerState,
136
+ onLoad: syncPlayerState,
137
+ },
138
+ });
139
+
140
+ return () => {
141
+ removeListener?.();
142
+ };
143
+ }, [activePlayer]);
144
+
145
+ const handlePlayPause = () => {
146
+ if (!activePlayer) {
147
+ return;
148
+ }
149
+
150
+ if (isPaused) {
151
+ activePlayer.play();
152
+ setIsPaused(false);
153
+ } else {
154
+ activePlayer.pause();
155
+ setIsPaused(true);
156
+ }
157
+ };
158
+
159
+ const renderNowPlayingTrack = () => {
160
+ if (!currentEntry) {
161
+ return null;
162
+ }
163
+
164
+ const imageGroup = Array.isArray(currentEntry.media_group)
165
+ ? currentEntry.media_group.find((g: any) => g.type === "image")
166
+ : null;
167
+
168
+ const firstImage = Array.isArray(imageGroup?.media_item)
169
+ ? imageGroup.media_item[0]?.src
170
+ : imageGroup?.media_item?.src;
171
+
172
+ const nowPlayingItem: MenuItem = {
173
+ id: String(currentEntry.id ?? "now_playing"),
174
+ title: (currentEntry.title as string) || String(currentEntry.id),
175
+ summary: (currentEntry.summary as string) ?? "",
176
+ icon: firstImage,
177
+ };
178
+
179
+ const data = mapMenuItemToNowPlayingData(
180
+ nowPlayingItem,
181
+ isPaused,
182
+ nowPlayingTitle
183
+ );
184
+
185
+ return (
186
+ <AudioPlayerTrackItem
187
+ configuration={VARIANT_NOW_PLAYING}
188
+ data={data}
189
+ onTrailingButtonPress={handlePlayPause}
190
+ />
191
+ );
192
+ };
193
+
194
+ return (
195
+ <View>
196
+ {renderNowPlayingTrack()}
197
+ <AudioPlayerHeader
198
+ configuration={VARIANT_SECTION_HEADER}
199
+ data={{ title: nextUpTitle, clearLabel }}
200
+ onClear={onClear}
201
+ />
202
+ {isEmpty ? <Text style={styles.emptyMessage}>{emptyMessage}</Text> : null}
203
+ </View>
204
+ );
205
+ }
@@ -0,0 +1,113 @@
1
+ import React from "react";
2
+ import { Pressable } from "react-native";
3
+ import { fireEvent, render, screen } from "@testing-library/react-native";
4
+ import {
5
+ AudioPlayerTrackItem,
6
+ VARIANT_PLAYLIST_ITEM,
7
+ mapMenuItemToNowPlayingData,
8
+ } from "../Item";
9
+
10
+ const playlistItemData = {
11
+ textLabel1: "Queue",
12
+ textLabel2: "",
13
+ trailingButton: "multiSelect" as const,
14
+ isSelected: false,
15
+ };
16
+
17
+ describe("AudioPlayerTrackItem multiSelect checkbox", () => {
18
+ it("invokes onPress when the checkbox is pressed even if onTrailingButtonPress is omitted", () => {
19
+ const onPress = jest.fn();
20
+
21
+ render(
22
+ <AudioPlayerTrackItem
23
+ configuration={VARIANT_PLAYLIST_ITEM}
24
+ data={playlistItemData}
25
+ onPress={onPress}
26
+ />
27
+ );
28
+
29
+ const pressables = screen.UNSAFE_getAllByType(Pressable);
30
+ fireEvent.press(pressables[pressables.length - 1]);
31
+
32
+ expect(onPress).toHaveBeenCalledTimes(1);
33
+ });
34
+
35
+ it("invokes onTrailingButtonPress instead of onPress when a dedicated trailing handler is provided", () => {
36
+ const onPress = jest.fn();
37
+ const onTrailingButtonPress = jest.fn();
38
+
39
+ render(
40
+ <AudioPlayerTrackItem
41
+ configuration={VARIANT_PLAYLIST_ITEM}
42
+ data={playlistItemData}
43
+ onPress={onPress}
44
+ onTrailingButtonPress={onTrailingButtonPress}
45
+ />
46
+ );
47
+
48
+ const pressables = screen.UNSAFE_getAllByType(Pressable);
49
+ fireEvent.press(pressables[pressables.length - 1]);
50
+
51
+ expect(onTrailingButtonPress).toHaveBeenCalledTimes(1);
52
+ expect(onPress).not.toHaveBeenCalled();
53
+ });
54
+
55
+ it("invokes onPress when the row is pressed", () => {
56
+ const onPress = jest.fn();
57
+
58
+ render(
59
+ <AudioPlayerTrackItem
60
+ configuration={VARIANT_PLAYLIST_ITEM}
61
+ data={playlistItemData}
62
+ onPress={onPress}
63
+ />
64
+ );
65
+
66
+ fireEvent.press(screen.UNSAFE_getAllByType(Pressable)[0]);
67
+
68
+ expect(onPress).toHaveBeenCalledTimes(1);
69
+ });
70
+
71
+ it("renders only textLabel1 Text element when textLabel2 is missing or empty", () => {
72
+ const { UNSAFE_getAllByType, queryByText } = render(
73
+ <AudioPlayerTrackItem
74
+ configuration={VARIANT_PLAYLIST_ITEM}
75
+ data={{
76
+ textLabel1: "Only Title",
77
+ textLabel2: "",
78
+ }}
79
+ />
80
+ );
81
+
82
+ const { Text } = require("react-native");
83
+ const textNodes = UNSAFE_getAllByType(Text);
84
+ expect(textNodes).toHaveLength(1);
85
+ expect(queryByText("Only Title")).toBeTruthy();
86
+ });
87
+ });
88
+
89
+ describe("mapMenuItemToNowPlayingData", () => {
90
+ const item = {
91
+ id: "item_1",
92
+ title: "Track Title",
93
+ summary: "Artist Name",
94
+ icon: "https://example.com/cover.png",
95
+ };
96
+
97
+ it("uses default 'Now Playing' label when omitted", () => {
98
+ const data = mapMenuItemToNowPlayingData(item as any);
99
+ expect(data.nowPlayingLabel).toBe("Now Playing");
100
+ expect(data.textLabel1).toBe("Track Title");
101
+ expect(data.textLabel2).toBe("Artist Name");
102
+ });
103
+
104
+ it("uses custom nowPlayingLabel when provided", () => {
105
+ const data = mapMenuItemToNowPlayingData(
106
+ item as any,
107
+ false,
108
+ "En cours de lecture"
109
+ );
110
+
111
+ expect(data.nowPlayingLabel).toBe("En cours de lecture");
112
+ });
113
+ });
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { render, screen } from "@testing-library/react-native";
3
+ import { NowPlayingHeaderSection } from "../NowPlayingHeaderSection";
4
+
5
+ jest.mock(
6
+ "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer",
7
+ () => ({
8
+ usePlayer: () => null,
9
+ })
10
+ );
11
+
12
+ jest.mock(
13
+ "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState",
14
+ () => ({
15
+ usePlayerState: () => ({ isPaused: true }),
16
+ })
17
+ );
18
+
19
+ const EMPTY_COPY = "Queued items will be added here";
20
+
21
+ describe("NowPlayingHeaderSection empty queue", () => {
22
+ it("renders the empty message under Next Up when the list is empty", () => {
23
+ render(<NowPlayingHeaderSection isEmpty emptyMessage={EMPTY_COPY} />);
24
+
25
+ expect(screen.getByText("Next Up")).toBeTruthy();
26
+ expect(screen.getByText(EMPTY_COPY)).toBeTruthy();
27
+ });
28
+
29
+ it("does not render the empty message when the list has items", () => {
30
+ render(
31
+ <NowPlayingHeaderSection isEmpty={false} emptyMessage={EMPTY_COPY} />
32
+ );
33
+
34
+ expect(screen.queryByText(EMPTY_COPY)).toBeNull();
35
+ });
36
+ });
@@ -0,0 +1,9 @@
1
+ export { AudioPlayerButton, VARIANT_WITH_ICON } from "./Button";
2
+
3
+ export { AudioPlayerHeader } from "./Header";
4
+
5
+ export { AudioPlayerTrackItem } from "./Item";
6
+
7
+ export { NowPlayingHeaderSection } from "./NowPlayingHeaderSection";
8
+
9
+ export { AudioPlayerInput } from "./Input";