@applicaster/zapp-react-native-utils 13.0.0-alpha.1632352572 → 13.0.0-alpha.1673005505

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 (123) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +74 -9
  4. package/alertUtils/alert.ts +148 -0
  5. package/alertUtils/index.ts +1 -148
  6. package/analyticsUtils/AnalyticPlayerListener.ts +18 -1
  7. package/analyticsUtils/__tests__/__snapshots__/analyticsManagerNoModule.test.js.snap +9 -9
  8. package/analyticsUtils/helpers/hooks.ts +1 -1
  9. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  10. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +10 -8
  11. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  12. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  13. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  14. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  15. package/appUtils/HooksManager/{index.js → index.ts} +121 -112
  16. package/appUtils/HooksManager/types.ts +119 -0
  17. package/appUtils/RiverFocusManager/index.js +17 -12
  18. package/appUtils/accessibilityManager/index.ts +42 -1
  19. package/appUtils/contextKeysManager/contextResolver.ts +77 -0
  20. package/appUtils/contextKeysManager/index.ts +2 -2
  21. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  22. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +7 -6
  23. package/appUtils/focusManager/index.ts +100 -65
  24. package/appUtils/focusManager/treeDataStructure/Tree/index.js +25 -3
  25. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  26. package/appUtils/focusManager/utils/enums.ts +4 -0
  27. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  28. package/appUtils/{index.js → index.ts} +1 -1
  29. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
  30. package/appUtils/keyCodes/__tests__/keyCodes.test.js +4 -4
  31. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  32. package/appUtils/keyCodes/keys/index.ts +3 -0
  33. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  34. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  35. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  36. package/appUtils/keyCodes/keys/keys.ts +15 -0
  37. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +3 -3
  38. package/appUtils/keyCodes/keysByPlatform.ts +8 -0
  39. package/appUtils/orientationHelper.ts +1 -1
  40. package/appUtils/platform/const.ts +14 -0
  41. package/appUtils/platform/platformUtils.ts +47 -18
  42. package/appUtils/playerManager/player.ts +5 -4
  43. package/appUtils/playerManager/playerNative.ts +1 -1
  44. package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
  45. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  46. package/equalUtils/index.ts +10 -3
  47. package/focusManager/FocusManager.ts +11 -1
  48. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +4 -4
  49. package/functionUtils/index.ts +15 -11
  50. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  51. package/idleUtils/index.ts +1 -1
  52. package/idleUtils/withTimeout.ts +15 -2
  53. package/logger/const.ts +9 -67
  54. package/manifestUtils/__tests__/createConfig.test.js +16 -16
  55. package/modalState/index.ts +1 -5
  56. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +6 -6
  57. package/navigationUtils/__tests__/itemTypes.test.js +2 -2
  58. package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
  59. package/navigationUtils/index.ts +17 -8
  60. package/package.json +3 -2
  61. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  62. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -1
  63. package/reactHooks/cell-click/__tests__/index.test.js +10 -2
  64. package/reactHooks/cell-click/index.ts +7 -1
  65. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +4 -4
  66. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -11
  67. package/reactHooks/feed/useFeedLoader.tsx +1 -1
  68. package/reactHooks/feed/usePipesCacheReset.ts +5 -5
  69. package/reactHooks/flatList/__tests__/index.test.tsx +30 -21
  70. package/reactHooks/layout/__tests__/index.test.tsx +10 -10
  71. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +14 -28
  72. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  73. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  74. package/reactHooks/navigation/__tests__/index.test.tsx +0 -4
  75. package/reactHooks/navigation/index.ts +35 -236
  76. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +12 -0
  77. package/reactHooks/navigation/useGetNavBarTopBorderWidth.ts +14 -0
  78. package/reactHooks/navigation/useGetTabBarHeight.ts +10 -0
  79. package/reactHooks/navigation/useIsScreenActive.ts +17 -0
  80. package/reactHooks/navigation/useNavigationPluginData.ts +15 -0
  81. package/reactHooks/navigation/useNavigationType.ts +15 -0
  82. package/reactHooks/navigation/usePathname.ts +4 -0
  83. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  84. package/reactHooks/navigation/useRoute.ts +100 -0
  85. package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
  86. package/reactHooks/player/TVSeekControlller/ISeekController.ts +27 -2
  87. package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +23 -61
  88. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +143 -48
  89. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +29 -51
  90. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +115 -0
  91. package/reactHooks/player/__tests__/useTapSeek._test.ts +94 -0
  92. package/reactHooks/player/const.ts +1 -5
  93. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  94. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  95. package/reactHooks/usePluginConfiguration.ts +1 -1
  96. package/reactHooks/useSubscriberFor.ts +4 -3
  97. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  98. package/reactUtils/__tests__/reactUtils.test.js +10 -28
  99. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  100. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +13 -79
  101. package/reactUtils/createContext/__tests__/__snapshots__/index.test.js.snap +2 -2
  102. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  103. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  104. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  105. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  106. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  107. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  108. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  109. package/reactUtils/index.ts +0 -14
  110. package/screenState/index.ts +24 -10
  111. package/testUtils/index.tsx +0 -10
  112. package/theme/__mocks__/index.ts +4 -0
  113. package/theme/index.ts +1 -1
  114. package/time/Timer.ts +5 -2
  115. package/types.ts +1 -0
  116. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  117. package/appUtils/keyCodes/keys.ios.js +0 -46
  118. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  119. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  120. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  121. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  122. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  123. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -191,7 +191,6 @@ const toDistance = ({ target, direction, comparisonRect }) => {
191
191
  * Get target in shortest distance in specified direction
192
192
  * @private
193
193
  * @param {Object} direction of the navigation, which led to this focus change
194
- * @param {Object} excludedNode node which should be excluded from target group
195
194
  * @param {Array} targetNodes array of input target nodes
196
195
  * @param {Object} comparisonRect rectangle to compare sides in direction.
197
196
  * @returns {Object} target in direction.
@@ -300,8 +299,7 @@ export function findFocusableNode(direction, currentFocusNode) {
300
299
  * @public
301
300
  * @param {Object} direction of the navigation, which led to this focus change
302
301
  * @param {Object} component - object to check props.prioritiseFocusOn
303
- * @returns {Boolean} TRUE if object has priority in direction.
304
- * @returns {Boolean} FALSE if object has NO priority in direction.
302
+ * @returns {Boolean} TRUE if object has priority in direction. FALSE if object has NO priority in direction.
305
303
  */
306
304
  export function hasPriorityInDirection(direction, component) {
307
305
  const { prioritiseFocusOn = 0 } = component.props;
@@ -0,0 +1,4 @@
1
+ export enum ACTION {
2
+ FOCUS = "focus",
3
+ BLUR = "blur",
4
+ }
@@ -1,8 +1,8 @@
1
1
  import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
2
- import { find, last, startsWith, pathOr } from "ramda";
2
+ import { find, last, pathOr, startsWith } from "ramda";
3
3
  import {
4
- QUICK_BRICK_NAVBAR,
5
4
  QUICK_BRICK_CONTENT,
5
+ QUICK_BRICK_NAVBAR,
6
6
  } from "@applicaster/quick-brick-core/const";
7
7
 
8
8
  // run check each 300 ms
@@ -66,7 +66,8 @@ export const getContentNode = (focusableTree) => {
66
66
  const content = find(
67
67
  (child) =>
68
68
  startsWith(QUICK_BRICK_CONTENT, child.id) ||
69
- startsWith("player", child.id),
69
+ startsWith("player", child.id) ||
70
+ startsWith("/hooks", child?.parent?.id), // For startup hooks case
70
71
  getActiveScreenChildren(focusableTree)
71
72
  );
72
73
 
@@ -9,7 +9,7 @@ export { KEYS, ARROW_KEYS } from "./keyCodes/keys";
9
9
 
10
10
  export { playerManager } from "./playerManager";
11
11
 
12
- export { accessibilityManager } from "./accessibilityManager";
12
+ export { AccessibilityManager } from "./accessibilityManager";
13
13
 
14
14
  export function deprecationMessage(fn, replacement) {
15
15
  if (__DEV__ && process.env.NODE_ENV !== "test") {
@@ -1,11 +1,11 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`keyCodes keyCode returns an object for a given key event 1`] = `
4
- Object {
4
+ {
5
5
  "direction": [Function],
6
6
  "matches": [Function],
7
7
  "matchesAny": [Function],
8
- "value": Object {
8
+ "value": {
9
9
  "code": "Enter",
10
10
  "keyCode": 13,
11
11
  },
@@ -1,4 +1,4 @@
1
- const { Platform } = require("react-native");
1
+ import { Platform } from "react-native";
2
2
 
3
3
  Platform.OS = "web";
4
4
 
@@ -13,7 +13,7 @@ const globalTizen = {
13
13
  describe("keyCodes", () => {
14
14
  describe("keyCode", () => {
15
15
  const { keyCode } = require("..");
16
- const { KEYS } = require("../keys.web");
16
+ const { KEYS } = require("../keys/keys.web");
17
17
 
18
18
  it("returns an object for a given key event", () => {
19
19
  expect(keyCode(KEYS.Enter)).toMatchSnapshot();
@@ -63,7 +63,7 @@ describe("keyCodes", () => {
63
63
  it("uses the proper keyCode for the environment", () => {
64
64
  Platform.OS = "samsung_tv";
65
65
  const { keyCode } = require("../");
66
- const { KEYS } = require("../keys.web");
66
+ const { KEYS } = require("../keys/keys.web");
67
67
 
68
68
  expect(globalTizen.tvinputdevice.registerKeyBatch).toHaveBeenCalledWith([
69
69
  "MediaPlay",
@@ -97,7 +97,7 @@ describe("keyCodes", () => {
97
97
  it("uses the proper keyCode for the environment", () => {
98
98
  Platform.OS = "lg_tv";
99
99
  const { keyCode } = require("..");
100
- const { KEYS } = require("../keys.web");
100
+ const { KEYS } = require("../keys/keys.web");
101
101
  // Back is reserved on LG
102
102
  expect(keyCode({ keyCode: 417 }).matches(KEYS.Forward)).toBeTruthy();
103
103
  });
@@ -6,6 +6,8 @@ import * as R from "ramda";
6
6
  import { directionHelper } from "../directionHelper";
7
7
  import { KEYS, ARROW_KEYS } from "./keys";
8
8
 
9
+ export { KEYS, ARROW_KEYS, keyEventMapper } from "./keys";
10
+
9
11
  /**
10
12
  * @typedef KeyCode
11
13
  * @property {Object} value of the Key
@@ -0,0 +1,3 @@
1
+ export * from "./keys";
2
+
3
+ export { keyEventMapper } from "./keyEventMapper";
@@ -1,22 +1,3 @@
1
- export const KEYS = {
2
- Enter: { code: "Enter", keyCode: 13 },
3
- EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
4
- Back: { code: "Back", keyCode: 8 },
5
- Space: { code: "Space", keyCode: 32 },
6
- m: { code: "m", keyCode: 77 },
7
- ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
8
- ArrowUp: { code: "ArrowUp", keyCode: 38 },
9
- ArrowRight: { code: "ArrowRight", keyCode: 39 },
10
- ArrowDown: { code: "ArrowDown", keyCode: 40 },
11
- };
12
-
13
- export const ARROW_KEYS = [
14
- KEYS.ArrowUp,
15
- KEYS.ArrowLeft,
16
- KEYS.ArrowDown,
17
- KEYS.ArrowRight,
18
- ];
19
-
20
1
  export function keyEventMapper(keyCode) {
21
2
  switch (keyCode) {
22
3
  case 19: // ArrowUp
@@ -0,0 +1,18 @@
1
+ export const KEYS = {
2
+ Enter: { code: "Enter", keyCode: 13 },
3
+ EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
4
+ Back: { code: "Back", keyCode: 8 },
5
+ Space: { code: "Space", keyCode: 32 },
6
+ m: { code: "m", keyCode: 77 },
7
+ ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
8
+ ArrowUp: { code: "ArrowUp", keyCode: 38 },
9
+ ArrowRight: { code: "ArrowRight", keyCode: 39 },
10
+ ArrowDown: { code: "ArrowDown", keyCode: 40 },
11
+ };
12
+
13
+ export const ARROW_KEYS = [
14
+ KEYS.ArrowUp,
15
+ KEYS.ArrowLeft,
16
+ KEYS.ArrowDown,
17
+ KEYS.ArrowRight,
18
+ ];
@@ -0,0 +1,25 @@
1
+ export const KEYS = {
2
+ Enter: { code: "Enter", keyCode: 13 },
3
+ Space: { code: "Space", keyCode: 32 },
4
+ m: { code: "m", keyCode: 77 },
5
+ ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
6
+ ArrowUp: { code: "ArrowUp", keyCode: 38 },
7
+ ArrowRight: { code: "ArrowRight", keyCode: 39 },
8
+ ArrowDown: { code: "ArrowDown", keyCode: 40 },
9
+ Back: { code: "Backspace", keyCode: 8 },
10
+ Play: { code: "PlayPause", keyCode: 179 },
11
+ Pause: { code: "Pause", keyCode: 179 },
12
+ Forward: { code: "Forward", keyCode: 176 },
13
+ Rewind: { code: "Rewind", keyCode: 177 },
14
+ VolumeUp: { code: "VolumeUp", keyCode: 175 },
15
+ VolumeDown: { code: "VolumeDown", keyCode: 174 },
16
+ ToggleMute: { code: "VolumeMute", keyCode: 173 },
17
+ Stop: { code: "Q", keyCode: 81 },
18
+ };
19
+
20
+ export const ARROW_KEYS = [
21
+ KEYS.ArrowUp,
22
+ KEYS.ArrowLeft,
23
+ KEYS.ArrowDown,
24
+ KEYS.ArrowRight,
25
+ ];
@@ -0,0 +1,15 @@
1
+ // dummy file to make sure the folder structure is created
2
+ export const KEYS: Record<string, { code: string; keyCode: number }> = {
3
+ ArrowLeft: { code: "ArrowLeft", keyCode: -1 },
4
+ ArrowUp: { code: "ArrowUp", keyCode: -1 },
5
+ ArrowRight: { code: "ArrowRight", keyCode: -1 },
6
+ ArrowDown: { code: "ArrowDown", keyCode: -1 },
7
+ Back: { code: "Back", keyCode: -1 },
8
+ };
9
+
10
+ export const ARROW_KEYS = [
11
+ KEYS.ArrowUp,
12
+ KEYS.ArrowLeft,
13
+ KEYS.ArrowDown,
14
+ KEYS.ArrowRight,
15
+ ];
@@ -78,9 +78,9 @@ const web = {
78
78
  Escape: { code: "Escape", keyCode: 27 },
79
79
  EscapeDevice: { code: "Escape", keyCode: 27 },
80
80
  // For Debugging
81
- Z: { code: "KeyZ", keyCode: 90 },
82
- X: { code: "KeyX", keyCode: 88 },
83
- C: { code: "KeyC", keyCode: 67 },
81
+ Z: { code: "KeyZ", keyCode: 90 }, // Hardware Backward Button
82
+ X: { code: "KeyX", keyCode: 88 }, // Hardware Enter Button
83
+ C: { code: "KeyC", keyCode: 67 }, // Hardware Forward Button
84
84
  };
85
85
 
86
86
  const android_tv = {
@@ -0,0 +1,8 @@
1
+ export {
2
+ lg_tv,
3
+ samsung_tv,
4
+ web,
5
+ tvos,
6
+ android_tv,
7
+ vizio,
8
+ } from "./keys/keysByPlatform";
@@ -2,7 +2,7 @@
2
2
  import * as ReactNative from "react-native";
3
3
  import { isTV, platformSelect } from "../reactUtils";
4
4
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
6
6
 
7
7
  import {
8
8
  QUICK_BRICK_EVENTS,
@@ -23,3 +23,17 @@ export const PLATFORMS = {
23
23
  export const PLATFORM_KEYS = {
24
24
  deviceClosedCaptioningEnabled: "device_closed_captioning_enabled",
25
25
  };
26
+
27
+ export enum ZappPlatform {
28
+ Android = "android",
29
+ AndroidTV = "android_tv",
30
+ AmazonFireTV = "amazon",
31
+ iOS = "ios",
32
+ tvOS = "tvos",
33
+ Roku = "roku",
34
+ Tizen = "tizen",
35
+ Web = "web",
36
+ WebOS = "webos",
37
+ Vizio = "vizio",
38
+ Unknown = "unknown",
39
+ }
@@ -6,22 +6,10 @@ import {
6
6
  isSamsungPlatform,
7
7
  } from "@applicaster/zapp-react-dom-app/App/Loader/utils/platform";
8
8
 
9
- import { PLATFORM_KEYS, PLATFORMS } from "./const";
9
+ import { PLATFORM_KEYS, PLATFORMS, ZappPlatform } from "./const";
10
10
  import { createLogger, utilsLogger } from "../../logger";
11
-
12
- declare global {
13
- interface Window {
14
- VIZIO?: {
15
- exitApplication: () => void;
16
- Chromevox: {
17
- play: (text: string) => void;
18
- };
19
- setClosedCaptionHandler: (
20
- callback: (isCCEnabled: boolean) => void
21
- ) => void;
22
- };
23
- }
24
- }
11
+ import { getPlatform } from "../../reactUtils";
12
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
25
13
 
26
14
  const { log_debug } = createLogger({
27
15
  category: "General",
@@ -29,6 +17,20 @@ const { log_debug } = createLogger({
29
17
  parent: utilsLogger,
30
18
  });
31
19
 
20
+ export const getZappPlatform = (): ZappPlatform => {
21
+ const platform = appStore.get("appData")?.platform;
22
+
23
+ switch (platform) {
24
+ case "amazon_fire_tv":
25
+ return ZappPlatform.AmazonFireTV;
26
+ case ZappPlatform.Vizio:
27
+ return ZappPlatform.Vizio;
28
+ default:
29
+ // TODO: Use only ZappPlatform enum
30
+ return getPlatform() as ZappPlatform;
31
+ }
32
+ };
33
+
32
34
  export const getUserAgent = () => window?.navigator?.userAgent;
33
35
 
34
36
  /** VIZIO UTILS */
@@ -75,13 +77,22 @@ export class ClosedCaptioningManager {
75
77
 
76
78
  private constructor() {
77
79
  this.initialize();
80
+
81
+ window["vizioDebug"] = {
82
+ setCCEnabled: (isCCEnabled: boolean) => {
83
+ this.ccState$.next(isCCEnabled);
84
+ },
85
+ };
78
86
  }
79
87
 
80
88
  static getInstance(): ClosedCaptioningManager {
81
89
  if (!ClosedCaptioningManager.ccManagerInstance) {
90
+ log_debug("ClosedCaptioningManager: Creating new instance");
82
91
  ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
83
92
  }
84
93
 
94
+ log_debug("ClosedCaptioningManager: Returning existing instance");
95
+
85
96
  return ClosedCaptioningManager.ccManagerInstance;
86
97
  }
87
98
 
@@ -90,23 +101,41 @@ export class ClosedCaptioningManager {
90
101
  PLATFORM_KEYS.deviceClosedCaptioningEnabled
91
102
  );
92
103
 
93
- log_debug("Initializing closed captioning manager", { existingState });
94
-
95
104
  if (existingState !== null) {
105
+ log_debug(
106
+ `ClosedCaptioningManager: Setting initial state to ${existingState}`
107
+ );
108
+
96
109
  this.ccState$.next(existingState === "true" || existingState === true);
110
+ } else {
111
+ log_debug("ClosedCaptioningManager: No existing state found");
97
112
  }
98
113
 
99
114
  if (hasVizioAPIs()) {
115
+ log_debug("ClosedCaptioningManager: Setting closed captioning handler");
116
+
100
117
  window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
101
- log_debug("CC state changed", { isCCEnabled });
118
+ log_debug(
119
+ "ClosedCaptioningManager: There was a change in the CC state",
120
+ { isCCEnabled }
121
+ );
102
122
 
103
123
  sessionStorage.setItem(
104
124
  PLATFORM_KEYS.deviceClosedCaptioningEnabled,
105
125
  isCCEnabled
106
126
  );
107
127
 
128
+ log_debug(
129
+ "ClosedCaptioningManager: Saved CC state to session storage",
130
+ { isCCEnabled }
131
+ );
132
+
108
133
  this.ccState$.next(isCCEnabled);
109
134
  });
135
+ } else {
136
+ log_debug(
137
+ "ClosedCaptioningManager: Vizio APIs are not available, skipping setup"
138
+ );
110
139
  }
111
140
  }
112
141
 
@@ -98,6 +98,7 @@ export class Player {
98
98
  this.isFullScreenSupported = this.isFullScreenSupported.bind(this);
99
99
  this.onPlayerSeekComplete = this.onPlayerSeekComplete.bind(this);
100
100
 
101
+ this.isPaused = this.isPaused.bind(this);
101
102
  this.entryObservable = null;
102
103
  }
103
104
 
@@ -154,8 +155,8 @@ export class Player {
154
155
  this.isSeeking()
155
156
  ? this.playerState.seekPosition
156
157
  : this.playerState.adState
157
- ? this.playerState.adState.adPosition
158
- : this.playerState.contentPosition;
158
+ ? this.playerState.adState.adPosition
159
+ : this.playerState.contentPosition;
159
160
 
160
161
  getEntry = (): ZappEntry | null => this.entry;
161
162
 
@@ -253,9 +254,9 @@ export class Player {
253
254
  return this.playerState.seekPosition !== null;
254
255
  };
255
256
 
256
- isPaused = () => {
257
+ isPaused() {
257
258
  return !!this.playerState.isPaused;
258
- };
259
+ }
259
260
 
260
261
  isPlaying = () => {
261
262
  return !!this.playerState.isPaused === false;
@@ -58,7 +58,7 @@ export class PlayerNative extends Player {
58
58
  return this.playerState.contentPosition;
59
59
  };
60
60
 
61
- currentPlayerComponent = (): ReactComponent<PlayerProps> =>
61
+ currentPlayerComponent = (): ReactComponent<PlayerRefProps> =>
62
62
  this.playerComponent?.current;
63
63
 
64
64
  getState = () => this.playerState;
@@ -1,7 +1,7 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`shiftArray shifts the n first items from the head to the tail of the array with a positive offset 1`] = `
4
- Array [
4
+ [
5
5
  "bar",
6
6
  "baz",
7
7
  42,
@@ -10,7 +10,7 @@ Array [
10
10
  `;
11
11
 
12
12
  exports[`shiftArray shifts the n first items from the head to the tail of the array with a positive offset 2`] = `
13
- Array [
13
+ [
14
14
  "baz",
15
15
  42,
16
16
  "foo",
@@ -19,7 +19,7 @@ Array [
19
19
  `;
20
20
 
21
21
  exports[`shiftArray shifts the n last items from the tail to the head of the array with a negative offset 1`] = `
22
- Array [
22
+ [
23
23
  42,
24
24
  "foo",
25
25
  "bar",
@@ -28,7 +28,7 @@ Array [
28
28
  `;
29
29
 
30
30
  exports[`shiftArray shifts the n last items from the tail to the head of the array with a negative offset 2`] = `
31
- Array [
31
+ [
32
32
  "baz",
33
33
  42,
34
34
  "foo",
@@ -2,7 +2,6 @@ import { domUtilsLogger } from "./logger";
2
2
 
3
3
  /**
4
4
  * Gets an object of cookies and sets them on the DOM.
5
- * @param {Object} cookies selected data key for label.
6
5
  */
7
6
  export function setCookies(cookies): void {
8
7
  const cookieKeys = Object.keys(cookies);
@@ -25,7 +24,7 @@ export function setCookies(cookies): void {
25
24
  /**
26
25
  * Gets cookies set on DOM
27
26
  */
28
- export function getCookies(): Object {
27
+ export function getCookies(): typeof document.cookie {
29
28
  try {
30
29
  if (document) {
31
30
  return document.cookie;
@@ -49,9 +49,16 @@ export const isEqual =
49
49
  }
50
50
 
51
51
  if (compareRemainingKeysBySameValue) {
52
- const undeclaredKeys = R.difference(
53
- [...byValue, ...byReference, byComparator.keys],
54
- Object.keys(prev)
52
+ const allKeys = new Set([...Object.keys(prev), ...Object.keys(next)]);
53
+
54
+ const declaredKeys = new Set([
55
+ ...byValue,
56
+ ...byReference,
57
+ ...byComparator.keys,
58
+ ]);
59
+
60
+ const undeclaredKeys = Array.from(allKeys).filter(
61
+ (key) => !declaredKeys.has(key)
55
62
  );
56
63
 
57
64
  const isRestKeysEqualAllBySameValue = undeclaredKeys.every((key) =>
@@ -250,7 +250,17 @@ class FocusManager {
250
250
  }
251
251
 
252
252
  onDisableFocusChange = (id) => {
253
- if (FocusManager.instance.isFocused(id)) {
253
+ const isFocused = FocusManager.instance.isFocused(id);
254
+
255
+ const isDescendantFocused = (() => {
256
+ try {
257
+ return FocusManager.instance.isAnyDescendantFocused(id);
258
+ } catch (_e) {
259
+ return false;
260
+ }
261
+ })();
262
+
263
+ if (isFocused || isDescendantFocused) {
254
264
  // Move focus to next one
255
265
  const nextFocus = FocusManager.instance.focused?.props
256
266
  ?.nextFocusDown as string;
@@ -1,8 +1,8 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`functionUtils subscriber can be invoked without args 1`] = `
4
- Object {
5
- "handlers": Object {},
4
+ {
5
+ "handlers": {},
6
6
  "invokeHandler": [Function],
7
7
  "on": [Function],
8
8
  "removeHandler": [Function],
@@ -10,9 +10,9 @@ Object {
10
10
  `;
11
11
 
12
12
  exports[`functionUtils subscriber returns the original object with additional methods 1`] = `
13
- Object {
13
+ {
14
14
  "foo": "bar",
15
- "handlers": Object {},
15
+ "handlers": {},
16
16
  "invokeHandler": [Function],
17
17
  "method": [Function],
18
18
  "on": [Function],
@@ -111,12 +111,12 @@ type SubscriberFn<T> = (
111
111
 
112
112
  export type EventHandlerFn<T> = (event: string, ...args: unknown[]) => T;
113
113
 
114
- type SubscriberObj = Partial<{
115
- on?: SubscriberFn<SubscriberObj>;
116
- invokeHandler: EventHandlerFn<SubscriberObj>;
117
- removeHandler: EventHandlerFn<SubscriberObj>;
118
- handlers: Record<string, SubscriberFn<SubscriberObj>[] | []>;
119
- }>;
114
+ export type SubscriberObj<T extends {} = {}> = {
115
+ on: SubscriberFn<SubscriberObj<T>>;
116
+ invokeHandler: EventHandlerFn<SubscriberObj<T>>;
117
+ removeHandler: EventHandlerFn<SubscriberObj<T>>;
118
+ handlers: Record<string, SubscriberFn<SubscriberObj<T>>[] | []>;
119
+ } & T;
120
120
 
121
121
  export const clearObject = (object: { [key: string]: unknown }) =>
122
122
  Object.keys(object).forEach((key) => delete object[key]);
@@ -126,7 +126,11 @@ export const clearObject = (object: { [key: string]: unknown }) =>
126
126
  * @param {Object} obj to add the subscription feature on
127
127
  * @returns {Object} subscriber object
128
128
  */
129
- export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
129
+ export function subscriber<T extends Partial<SubscriberObj> = {}>(
130
+ _obj: T = {} as T
131
+ ): SubscriberObj {
132
+ const obj: T = _obj;
133
+
130
134
  if (!obj.handlers) {
131
135
  obj.handlers = {};
132
136
  }
@@ -172,7 +176,7 @@ export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
172
176
  | SubscriberFn<SubscriberObj>[]
173
177
  | [];
174
178
 
175
- return obj;
179
+ return obj as SubscriberObj;
176
180
  };
177
181
 
178
182
  /**
@@ -188,16 +192,16 @@ export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
188
192
 
189
193
  R.compose(R.forEach(callHandlerWithDispose), R.propOr([], event))(handlers);
190
194
 
191
- return obj;
195
+ return obj as SubscriberObj;
192
196
  };
193
197
 
194
198
  obj.removeHandler = function (event, handler) {
195
199
  handlers[event] = R.reject(R.equals(handler), handlers[event]);
196
200
 
197
- return obj;
201
+ return obj as SubscriberObj;
198
202
  };
199
203
 
200
- return obj;
204
+ return obj as SubscriberObj;
201
205
  }
202
206
 
203
207
  /**
@@ -0,0 +1,37 @@
1
+ import { TestScheduler } from "rxjs/testing";
2
+
3
+ import { withTimeout$ } from "..";
4
+
5
+ describe("withTimeout$", () => {
6
+ let testScheduler: TestScheduler;
7
+
8
+ beforeEach(() => {
9
+ testScheduler = new TestScheduler((actual, expected) => {
10
+ expect(actual).toEqual(expected);
11
+ });
12
+ });
13
+
14
+ it("should emit undefined after the specified timeout", () => {
15
+ testScheduler.run(({ expectObservable }) => {
16
+ const timeout = 1000;
17
+ const expectedMarble = "1s (a|)";
18
+ const expectedValues = { a: undefined };
19
+
20
+ const result$ = withTimeout$(timeout);
21
+
22
+ expectObservable(result$).toBe(expectedMarble, expectedValues);
23
+ });
24
+ });
25
+
26
+ it("should complete after emitting undefined", () => {
27
+ testScheduler.run(({ expectObservable }) => {
28
+ const timeout = 500;
29
+ const expectedMarble = "500ms (a|)";
30
+ const expectedValues = { a: undefined };
31
+
32
+ const result$ = withTimeout$(timeout);
33
+
34
+ expectObservable(result$).toBe(expectedMarble, expectedValues);
35
+ });
36
+ });
37
+ });
@@ -1,4 +1,4 @@
1
- export { withTimeout } from "./withTimeout";
1
+ export { withTimeout, withTimeout$ } from "./withTimeout";
2
2
 
3
3
  export { onIdle } from "./onIdle";
4
4
 
@@ -1,7 +1,20 @@
1
- export const withTimeout = (timeout: number) => {
2
- return new Promise((resolve) => {
1
+ import { of, Observable } from "rxjs";
2
+ import { delay } from "rxjs/operators";
3
+
4
+ export const withTimeout = (timeout: number): Promise<void> => {
5
+ return new Promise<void>((resolve) => {
3
6
  setTimeout(() => {
4
7
  resolve(undefined);
5
8
  }, timeout);
6
9
  });
7
10
  };
11
+
12
+ /**
13
+ * Creates an observable that emits a single value after a specified timeout.
14
+ *
15
+ * @param timeout - The delay duration in milliseconds before emitting the value.
16
+ * @returns An observable that emits `undefined` after the specified timeout.
17
+ */
18
+ export const withTimeout$ = (timeout: number): Observable<void> => {
19
+ return of(undefined).pipe(delay(timeout));
20
+ };