@applicaster/zapp-react-native-utils 13.0.0-alpha.7210171818 → 13.0.0-alpha.7330390362

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 (115) hide show
  1. package/actionsExecutor/ActionExecutor.ts +16 -9
  2. package/actionsExecutor/ActionExecutorContext.tsx +74 -9
  3. package/alertUtils/alert.ts +148 -0
  4. package/alertUtils/index.ts +1 -148
  5. package/analyticsUtils/AnalyticPlayerListener.ts +18 -1
  6. package/analyticsUtils/__tests__/__snapshots__/analyticsManagerNoModule.test.js.snap +9 -9
  7. package/analyticsUtils/helpers/hooks.ts +1 -1
  8. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +10 -8
  10. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  11. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  12. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  13. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  14. package/appUtils/HooksManager/{index.js → index.ts} +121 -112
  15. package/appUtils/HooksManager/types.ts +119 -0
  16. package/appUtils/RiverFocusManager/index.js +17 -12
  17. package/appUtils/accessibilityManager/index.ts +42 -1
  18. package/appUtils/contextKeysManager/contextResolver.ts +77 -0
  19. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +7 -6
  20. package/appUtils/focusManager/index.ts +100 -65
  21. package/appUtils/focusManager/treeDataStructure/Tree/index.js +25 -3
  22. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  23. package/appUtils/focusManager/utils/enums.ts +4 -0
  24. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  25. package/appUtils/{index.js → index.ts} +1 -1
  26. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
  27. package/appUtils/keyCodes/__tests__/keyCodes.test.js +4 -4
  28. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  29. package/appUtils/keyCodes/keys/index.ts +3 -0
  30. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  31. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  32. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  33. package/appUtils/keyCodes/keys/keys.ts +15 -0
  34. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +4 -3
  35. package/appUtils/keyCodes/keysByPlatform.ts +8 -0
  36. package/appUtils/keyInputHandler/KeyInputHandler.ts +10 -32
  37. package/appUtils/orientationHelper.ts +1 -1
  38. package/appUtils/platform/const.ts +14 -0
  39. package/appUtils/platform/platformUtils.ts +47 -18
  40. package/appUtils/playerManager/index.ts +6 -2
  41. package/appUtils/playerManager/player.ts +9 -10
  42. package/appUtils/playerManager/playerNative.ts +1 -1
  43. package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -15
  44. package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
  45. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  46. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +4 -4
  47. package/functionUtils/index.ts +15 -11
  48. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  49. package/idleUtils/index.ts +1 -1
  50. package/idleUtils/withTimeout.ts +15 -2
  51. package/logger/const.ts +9 -67
  52. package/manifestUtils/__tests__/createConfig.test.js +16 -16
  53. package/modalState/index.ts +1 -5
  54. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +6 -6
  55. package/navigationUtils/__tests__/itemTypes.test.js +2 -2
  56. package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
  57. package/navigationUtils/index.ts +17 -8
  58. package/numberUtils/index.ts +7 -5
  59. package/package.json +3 -2
  60. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  61. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +6 -8
  62. package/reactHooks/autoscrolling/useTrackedView.ts +12 -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 +29 -218
  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/useRoute.ts +100 -0
  84. package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
  85. package/reactHooks/player/TVSeekControlller/ISeekController.ts +27 -2
  86. package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +39 -74
  87. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +155 -96
  88. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +31 -53
  89. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +115 -0
  90. package/reactHooks/player/__tests__/useTapSeek._test.ts +94 -0
  91. package/reactHooks/player/const.ts +1 -5
  92. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  93. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  94. package/reactHooks/usePluginConfiguration.ts +1 -1
  95. package/reactHooks/useSubscriberFor.ts +4 -3
  96. package/reactUtils/__tests__/reactUtils.test.js +10 -28
  97. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +19 -19
  98. package/reactUtils/createContext/__tests__/__snapshots__/index.test.js.snap +2 -2
  99. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -3
  100. package/reactUtils/createContext/__tests__/helpers.test.js +8 -8
  101. package/reactUtils/index.ts +0 -14
  102. package/screenState/index.ts +24 -10
  103. package/theme/__mocks__/index.ts +4 -0
  104. package/theme/index.ts +1 -1
  105. package/time/Timer.ts +5 -2
  106. package/types.ts +1 -0
  107. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  108. package/appUtils/keyCodes/keys.ios.js +0 -46
  109. package/appUtils/playerManager/DelayedSeekPlayerWrapper.tsx +0 -180
  110. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  111. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  112. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  113. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  114. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  115. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -0,0 +1,14 @@
1
+ import { getNavigationProps } from "../../navigationUtils";
2
+ import { useNavigation } from "./useNavigation";
3
+
4
+ export const useGetNavBarTopBorderWidth = (): number => {
5
+ const navigator = useNavigation();
6
+
7
+ const navProps = getNavigationProps({
8
+ navigator,
9
+ title: "",
10
+ category: "menu",
11
+ });
12
+
13
+ return Number(((navProps?.styles as any)?.top_border_width as number) ?? 0);
14
+ };
@@ -0,0 +1,10 @@
1
+ import { platformSelect } from "../../reactUtils";
2
+
3
+ const TAB_BAR_HEIGHT_IOS = 49;
4
+ const TAB_BAR_HEIGHT_ANDROID = 56;
5
+
6
+ export const useGetTabBarHeight = () =>
7
+ platformSelect({
8
+ ios: TAB_BAR_HEIGHT_IOS,
9
+ android: TAB_BAR_HEIGHT_ANDROID,
10
+ }) as number;
@@ -0,0 +1,17 @@
1
+ import { useNavigation } from "./useNavigation";
2
+ import { usePathname } from "./usePathname";
3
+
4
+ // If current screen is active/focused (visible to the user)
5
+ export const useIsScreenActive = () => {
6
+ const pathname = usePathname();
7
+ const { currentRoute, videoModalState } = useNavigation();
8
+
9
+ if (
10
+ videoModalState.visible &&
11
+ ["FULLSCREEN", "MAXIMIZED", "PIP"].includes(videoModalState.mode)
12
+ ) {
13
+ return false;
14
+ }
15
+
16
+ return pathname === currentRoute;
17
+ };
@@ -0,0 +1,15 @@
1
+ import { useRoute } from "./useRoute";
2
+
3
+ export const useNavigationPluginData = (): ZappNavigation | undefined => {
4
+ const {
5
+ screenData: useRouteScreenData,
6
+ }: { screenData: QuickBrickNavigationData | null } = useRoute();
7
+
8
+ const navigations = useRouteScreenData?.targetScreen
9
+ ? (useRouteScreenData.targetScreen as ZappRiver).navigations
10
+ : (useRouteScreenData as ZappRiver).navigations;
11
+
12
+ const navigationMenu = navigations?.find((nav) => nav.category === "menu");
13
+
14
+ return navigationMenu;
15
+ };
@@ -0,0 +1,15 @@
1
+ import { useNavigationPluginData } from "./useNavigationPluginData";
2
+
3
+ export enum MenuTypes {
4
+ drawer = "DRAWER",
5
+ bottomTabBar = "BOTTOM_TAB_BAR",
6
+ }
7
+
8
+ export const useNavigationType = (): MenuTypes => {
9
+ const navigationMenu = useNavigationPluginData();
10
+
11
+ return !navigationMenu ||
12
+ navigationMenu.navigation_type === "quick_brick_side_menu"
13
+ ? MenuTypes.drawer
14
+ : MenuTypes.bottomTabBar;
15
+ };
@@ -0,0 +1,4 @@
1
+ import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
2
+ import React from "react";
3
+
4
+ export const usePathname = () => React.useContext(PathnameContext);
@@ -0,0 +1,100 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ /* eslint max-len: off */
3
+
4
+ import { useContext } from "react";
5
+
6
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
7
+
8
+ import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
9
+
10
+ import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
11
+
12
+ import { getTargetScreenData } from "../screen/useTargetScreenData";
13
+
14
+ import { useNavigation } from "./useNavigation";
15
+ import { useModalStore } from "../../modalState";
16
+ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
17
+ import { usePathname } from "./usePathname";
18
+
19
+ // starts with modal/
20
+ const isModalPathname = (pathname: string) => /^modal\//.test(pathname);
21
+
22
+ const isVideoModalPathname = (pathname: string) =>
23
+ /^video-modal\//.test(pathname);
24
+
25
+ const isHookModalPathname = (pathname: string) =>
26
+ /^hooks-modal\//.test(pathname);
27
+
28
+ const isHookPathname = (pathname: string) => /^\/hooks\//.test(pathname);
29
+
30
+ type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
31
+
32
+ export const useRoute = (): {
33
+ screenData: VariousScreenData;
34
+ pathname: string;
35
+ } => {
36
+ const pathname = usePathname() || "";
37
+ const navigator = useNavigation();
38
+
39
+ const screenDataContext = legacyScreenData(useContext(ScreenDataContext));
40
+
41
+ const { plugins, contentTypes, rivers } = usePickFromState([
42
+ "plugins",
43
+ "rivers",
44
+ "contentTypes",
45
+ ]);
46
+
47
+ const { modalState } = useModalStore();
48
+ const hookModalState = useZappHooksModalState();
49
+
50
+ const modalScreenData = modalState.screen;
51
+
52
+ const hookModalScreenData = hookModalState.state.screenData?.payload;
53
+
54
+ const videoModalScreenData =
55
+ navigator?.videoModalState?.item &&
56
+ legacyScreenData(
57
+ {
58
+ entry: navigator.videoModalState?.item as ZappEntry,
59
+ screen: getTargetScreenData(
60
+ navigator.videoModalState?.item as ZappEntry,
61
+ rivers,
62
+ contentTypes
63
+ ),
64
+ },
65
+ plugins
66
+ );
67
+
68
+ // There are 4 route scenarios
69
+ // For regular screens take date from navigator stack.
70
+ // is path is model grab screenData from modal state
71
+ // if path is video modal grab screenData from video state
72
+ // if path is hook modal grab screenData from hook state
73
+ // if path is hook grab screenData from screenData
74
+
75
+ if (isModalPathname(pathname)) {
76
+ const screenData = modalScreenData ?? ({} as ZappEntry);
77
+
78
+ return { screenData, pathname };
79
+ }
80
+
81
+ if (isVideoModalPathname(pathname)) {
82
+ const screenData = videoModalScreenData as LegacyNavigationScreenData;
83
+
84
+ return { screenData, pathname };
85
+ }
86
+
87
+ if (isHookModalPathname(pathname)) {
88
+ const screenData = hookModalScreenData;
89
+
90
+ return { screenData, pathname };
91
+ }
92
+
93
+ if (isHookPathname(pathname)) {
94
+ return { screenData: screenDataContext, pathname };
95
+ }
96
+
97
+ const screenData = screenDataContext;
98
+
99
+ return { screenData, pathname };
100
+ };
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ import { isWeb } from "../../reactUtils";
3
+ import { useNavigation } from "./useNavigation";
4
+ import { usePathname } from "./usePathname";
5
+ import {
6
+ QUICK_BRICK_CONTENT,
7
+ QUICK_BRICK_NAVBAR,
8
+ } from "@applicaster/quick-brick-core/const";
9
+
10
+ type Return = (prefix: string) => string;
11
+
12
+ export const useUniqueRouteSuffix = (): Return => {
13
+ const pathname = usePathname();
14
+ const { currentRoute } = useNavigation();
15
+
16
+ const suffix = `currentRoute:${currentRoute}_pathname:${pathname}`;
17
+
18
+ const withUniqueRouteSuffix = React.useCallback((prefix: string) => {
19
+ if (isWeb()) {
20
+ // we should use extended route prefix only on Web, where we have stack-navigator
21
+ return `${prefix}___${suffix}`;
22
+ }
23
+
24
+ // for other platforms use previous version
25
+ return prefix;
26
+ }, []);
27
+
28
+ return withUniqueRouteSuffix;
29
+ };
30
+
31
+ export const useNavbarId = () => {
32
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
33
+
34
+ return withUniqueRouteSuffix(QUICK_BRICK_NAVBAR);
35
+ };
36
+
37
+ export const useContentId = () => {
38
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
39
+
40
+ return withUniqueRouteSuffix(QUICK_BRICK_CONTENT);
41
+ };
@@ -1,7 +1,32 @@
1
- import { SEEK_TYPE } from "../const";
1
+ import { MAX_SEEK_TIME, SEEK_TYPE, SKIP_TIME_BASE } from "../const";
2
+
3
+ export interface ISeekControllerDelegate {
4
+ handleDelayedSeek(offset: number): void;
5
+ handleSeek(offset: number): void;
6
+ handleSeekComplete(): void;
7
+ handlePlayerPause(): void;
8
+ }
2
9
 
3
10
  export interface ISeekController {
11
+ title: string;
4
12
  onStartSeek(seekType: SEEK_TYPE): void;
5
- onSeekEnd?(): void;
13
+ onSeekEnd(): void;
6
14
  reset(): void;
7
15
  }
16
+
17
+ export class SeekIncrementalBaseStrategy {
18
+ private skipMultiplier = 1;
19
+
20
+ getSkipTime = () =>
21
+ Math.min(MAX_SEEK_TIME, SKIP_TIME_BASE * this.skipMultiplier);
22
+
23
+ increment = () => {
24
+ this.skipMultiplier++;
25
+ };
26
+
27
+ getSkipMultiplier = () => this.skipMultiplier;
28
+
29
+ reset = () => {
30
+ this.skipMultiplier = 1;
31
+ };
32
+ }
@@ -1,99 +1,64 @@
1
- import { ISeekController } from "./ISeekController";
2
- import { SEEK_TYPE } from "../const";
3
1
  import {
4
- log_debug,
5
- log_error,
6
- log_verbose,
7
- TVSeekController,
8
- } from "./TVSeekController";
2
+ ISeekController,
3
+ ISeekControllerDelegate,
4
+ SeekIncrementalBaseStrategy,
5
+ } from "./ISeekController";
6
+ import { SEEK_TYPE } from "../const";
7
+ import { log_debug, log_error, log_verbose } from "./TVSeekController";
9
8
  import { interval, Subscription } from "rxjs";
10
9
  import { tap } from "rxjs/operators";
11
10
 
12
- /**
13
- * Example interface for the configuration needed for long-press seeking.
14
- */
15
11
  interface LongPressConfig {
16
- LONG_PRESS_THRESHOLD: number; // ms
17
- TIMER_INTERVAL_MS: number; // ms
18
- SKIP_INCREMENT_STEP: number; // seconds
19
- MAX_SKIP_PER_TICK: number; // seconds
20
- INITIAL_SKIP_AMOUNT: number; // e.g., 10s to start
12
+ TIMER_INTERVAL_MS: number;
21
13
  }
22
14
 
23
15
  export class LongPressSeekController implements ISeekController {
24
- private pressStartTime = 0;
25
- private isLongPressActive = false;
26
- private currentSkipAmount = 0;
27
16
  private subscription: Subscription | null = null;
28
-
17
+ readonly title = "LongPressSeek";
29
18
  constructor(
30
- private parent: TVSeekController,
19
+ private seekControllerDelegate: ISeekControllerDelegate,
20
+ private seekIncrementalStrategy: SeekIncrementalBaseStrategy,
31
21
  private config: LongPressConfig
32
22
  ) {}
33
23
 
34
24
  onStartSeek(seekType: SEEK_TYPE) {
35
25
  this.cleanUpSubscription();
36
26
 
37
- log_debug(
38
- `LongPressSeekController: start long press seek type:${seekType}.`
39
- );
40
-
41
- this.parent.currentSeekType = seekType;
42
- this.parent.pausePlayer();
43
-
44
- this.pressStartTime = Date.now();
45
- this.isLongPressActive = true;
46
- this.currentSkipAmount = this.config.INITIAL_SKIP_AMOUNT;
47
-
48
- // Start the interval immediately without waiting for a threshold.
49
- this.subscription = interval(this.config.TIMER_INTERVAL_MS).pipe(
50
- tap(() => {
51
- this.parent.handleDelayedSeek(
52
- this.parent.currentSeekType,
53
- this.currentSkipAmount
54
- );
55
-
56
- log_debug(
57
- `LongPressSeekController: handle delayed seek type: ${seekType} - currentSkipAmount: ${this.currentSkipAmount}.`
58
- );
59
-
60
- this.currentSkipAmount = Math.min(
61
- this.currentSkipAmount + this.config.SKIP_INCREMENT_STEP,
62
- this.config.MAX_SKIP_PER_TICK
63
- );
64
- })
65
- ).subscribe({
66
- complete: () =>
67
- log_verbose("LongPressSeekController: Long press subscription complete"),
68
- error: (err) =>
69
- log_error("LongPressSeekController: Long press subscription error", err),
70
- });
27
+ log_debug(`${this.title}: start long press seek type: ${seekType}.`);
28
+
29
+ this.seekControllerDelegate.handlePlayerPause();
30
+
31
+ this.subscription = interval(this.config.TIMER_INTERVAL_MS)
32
+ .pipe(
33
+ tap(() => {
34
+ this.seekControllerDelegate.handleDelayedSeek(
35
+ this.seekIncrementalStrategy.getSkipTime()
36
+ );
37
+
38
+ log_debug(
39
+ `${
40
+ this.title
41
+ }: handle delayed seek type: ${seekType} - multiplier: ${this.seekIncrementalStrategy.getSkipMultiplier()}, currentSkipAmount: ${this.seekIncrementalStrategy.getSkipTime()}.`
42
+ );
43
+
44
+ this.seekIncrementalStrategy.increment();
45
+ })
46
+ )
47
+ .subscribe({
48
+ complete: () =>
49
+ log_verbose(`${this.title}: Long press subscription complete`),
50
+ error: (err) =>
51
+ log_error(`${this.title}: Long press subscription error`, err),
52
+ });
71
53
  }
72
54
 
73
55
  onSeekEnd() {
74
- const pressDuration = Date.now() - this.pressStartTime;
75
-
76
- if (
77
- this.isLongPressActive &&
78
- pressDuration > this.config.LONG_PRESS_THRESHOLD
79
- ) {
80
- const offset = this.parent.delayedSeekOffset;
81
-
82
- if (offset) {
83
- log_debug(
84
- `LongPressSeekController: onPressEnd for LongPressSeekController, seek offset: ${offset}`
85
- );
86
-
87
- this.parent.seekPlayer(offset);
88
- }
89
- }
90
-
91
- this.parent.resetAll();
56
+ this.cleanUpSubscription();
57
+ this.seekControllerDelegate.handleSeekComplete();
92
58
  }
93
59
 
94
60
  reset() {
95
- this.isLongPressActive = false;
96
- this.currentSkipAmount = 0;
61
+ this.seekIncrementalStrategy.reset();
97
62
  this.cleanUpSubscription();
98
63
  }
99
64