@applicaster/zapp-react-native-ui-components 15.0.0-alpha.1627563808 → 15.0.0-alpha.1966607451

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 (43) hide show
  1. package/Components/BaseFocusable/index.ios.ts +12 -2
  2. package/Components/Cell/FocusableWrapper.tsx +3 -0
  3. package/Components/Cell/TvOSCellComponent.tsx +17 -5
  4. package/Components/Focusable/FocusableTvOS.tsx +12 -2
  5. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  6. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -0
  7. package/Components/HandlePlayable/HandlePlayable.tsx +10 -7
  8. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  9. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  10. package/Components/Layout/TV/index.tsx +3 -4
  11. package/Components/Layout/TV/index.web.tsx +3 -4
  12. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  13. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -10
  14. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
  15. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  16. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  17. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  18. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
  19. package/Components/MasterCell/utils/index.ts +61 -31
  20. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
  21. package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
  22. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  23. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  24. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  25. package/Components/PlayerContainer/PlayerContainer.tsx +4 -3
  26. package/Components/Screen/TV/index.web.tsx +4 -2
  27. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  28. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  29. package/Components/Screen/hooks.ts +2 -3
  30. package/Components/Screen/index.tsx +2 -3
  31. package/Components/Screen/navigationHandler.ts +49 -24
  32. package/Components/Screen/orientationHandler.ts +3 -3
  33. package/Components/ScreenResolver/index.tsx +13 -7
  34. package/Components/Transitioner/index.js +3 -3
  35. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -9
  36. package/Components/VideoModal/utils.ts +12 -9
  37. package/Decorators/Analytics/index.tsx +6 -5
  38. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  39. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  40. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  41. package/Helpers/DataSourceHelper/index.ts +19 -0
  42. package/package.json +6 -5
  43. package/Helpers/DataSourceHelper/index.js +0 -19
@@ -1,7 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
3
3
  import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
4
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
+ import { useAppData } from "@applicaster/zapp-react-native-redux";
5
+
5
6
  import { TransitionerComponent } from "./Transitioner";
6
7
 
7
8
  export const Transitioner = (props) => {
@@ -16,8 +17,7 @@ export const Transitioner = (props) => {
16
17
  deviceInfo: true,
17
18
  });
18
19
 
19
- const { appData } = usePickFromState(["appData"]);
20
- const isTabletPortrait = appData?.isTabletPortrait;
20
+ const { isTabletPortrait } = useAppData();
21
21
 
22
22
  return (
23
23
  <TransitionerComponent
@@ -4,8 +4,11 @@ import { Animated, Dimensions } from "react-native";
4
4
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
5
5
 
6
6
  import { useConfiguration } from "../utils";
7
- import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
8
- import { isMenuVisible } from "../../Screen/navigationHandler";
7
+ import {
8
+ useAppData,
9
+ usePlugins,
10
+ } from "@applicaster/zapp-react-native-redux/hooks";
11
+ import { isBottomTabVisible } from "../../Screen/navigationHandler";
9
12
 
10
13
  import {
11
14
  useSafeAreaFrame,
@@ -18,7 +21,6 @@ import {
18
21
  import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
19
22
  import { PROGRESS_BAR_HEIGHT } from "./utils";
20
23
  import { useIsTablet as getIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
21
- import { useAppSelector } from "@applicaster/zapp-react-native-redux";
22
24
 
23
25
  export type ModalAnimationContextT = {
24
26
  yTranslate: React.MutableRefObject<Animated.AnimatedInterpolation<number>>;
@@ -64,13 +66,15 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
64
66
  screenData,
65
67
  } = useNavigation();
66
68
 
67
- const isTabletPortrait = useAppSelector(
68
- (state) => state.appData.isTabletPortrait
69
- );
69
+ const { isTabletPortrait } = useAppData();
70
70
 
71
71
  const plugins = usePlugins();
72
72
 
73
- const menuVisible = isMenuVisible(currentRoute, screenData, plugins);
73
+ const bottomTabsVisible = isBottomTabVisible(
74
+ currentRoute,
75
+ screenData,
76
+ plugins
77
+ );
74
78
 
75
79
  const frame = useSafeAreaFrame();
76
80
  const insets = useSafeAreaInsets();
@@ -115,7 +119,7 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
115
119
  React.useEffect(() => {
116
120
  const collapsedHeight =
117
121
  minimisedHeight +
118
- (menuVisible ? bottomTabBarHeight : 0) +
122
+ (bottomTabsVisible ? bottomTabBarHeight : 0) +
119
123
  (isOldAndroidDevice ? 0 : insets.bottom) + // insets.bottom is added to properly display docked modal
120
124
  PROGRESS_BAR_HEIGHT;
121
125
 
@@ -136,7 +140,7 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
136
140
  setHeightAboveMinimised(heightAboveMinimised);
137
141
  offset.current = heightAboveMinimised;
138
142
  }
139
- }, [frame.height, insets.bottom, menuVisible, minimisedHeight]);
143
+ }, [frame.height, insets.bottom, bottomTabsVisible, minimisedHeight]);
140
144
 
141
145
  return (
142
146
  <ReactContext.Provider
@@ -1,32 +1,35 @@
1
1
  import { mergeRight } from "ramda";
2
2
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
3
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
+ import {
4
+ useAppSelector,
5
+ useContentTypes,
6
+ } from "@applicaster/zapp-react-native-redux/hooks";
4
7
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
5
8
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
6
9
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
7
10
  import { create } from "zustand";
11
+ import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
12
+ import { selectPluginConfigurationsByPluginId } from "@applicaster/zapp-react-native-redux";
8
13
 
9
14
  export const useConfiguration = () => {
10
15
  const {
11
16
  videoModalState: { item },
12
17
  } = useNavigation();
13
18
 
14
- const { rivers, contentTypes, pluginConfigurations } = usePickFromState([
15
- "rivers",
16
- "contentTypes",
17
- "pluginConfigurations",
18
- ]);
19
+ const rivers = useRivers();
20
+ const contentTypes = useContentTypes();
19
21
 
20
22
  const targetScreenId = contentTypes?.[item?.type?.value]?.screen_id;
21
23
  const targetScreenConfiguration = rivers?.[targetScreenId];
22
24
 
23
- const pluginConfiguration =
24
- pluginConfigurations[targetScreenConfiguration?.type]?.configuration_json;
25
+ const { configuration_json } = useAppSelector((state) =>
26
+ selectPluginConfigurationsByPluginId(state, targetScreenConfiguration?.type)
27
+ );
25
28
 
26
29
  const playerPluginConfig = playerManager.getPluginConfiguration();
27
30
 
28
31
  const config = mergeRight(playerPluginConfig, {
29
- ...pluginConfiguration,
32
+ ...configuration_json,
30
33
  ...targetScreenConfiguration?.general,
31
34
  ...targetScreenConfiguration?.styles,
32
35
  });
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
 
3
3
  import { getAnalyticsFunctions } from "@applicaster/zapp-react-native-utils/analyticsUtils";
4
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
4
 
6
5
  type ComponentProps = {
7
6
  component: {
@@ -21,11 +20,13 @@ type ComponentProps = {
21
20
 
22
21
  function withAnalytics(Component) {
23
22
  return function WithAnalytics(props: ComponentProps) {
24
- const { appData } = usePickFromState(["appData"]);
25
-
26
23
  const analyticsFunctions = React.useMemo(
27
- () => getAnalyticsFunctions({ props, appData }),
28
- [props, appData]
24
+ () =>
25
+ getAnalyticsFunctions({
26
+ component: props.component,
27
+ zappPipesData: props.zappPipesData,
28
+ } as any),
29
+ [props.component, props.zappPipesData]
29
30
  );
30
31
 
31
32
  return (
@@ -2,7 +2,7 @@
2
2
  /// <reference types="@applicaster/zapp-react-native-ui-components" />
3
3
  import React from "react";
4
4
  import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
6
6
  import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
7
7
  import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
8
8
  import { ResolverSelector } from "./ResolverSelector";
@@ -23,7 +23,7 @@ export function zappPipesDataConnector(
23
23
  ) {
24
24
  return function WrappedWithZappPipesData(props: Props) {
25
25
  const { screenData } = useRoute();
26
- const { plugins } = usePickFromState(["plugins"]);
26
+ const plugins = usePlugins();
27
27
  const screenContextData = useScreenContext();
28
28
 
29
29
  const {
@@ -76,7 +76,7 @@ export function StaticFeedResolver({
76
76
 
77
77
  const zappPipesDataProps = useMemo(
78
78
  () => ({
79
- zappPipesData: { url, loading, data, error },
79
+ zappPipesData: { url, loading, data, error }, // todo: add applyItemLimit
80
80
  reloadData,
81
81
  loadNextData: undefined, // Static resolver doesn't support pagination
82
82
  }),
@@ -0,0 +1,80 @@
1
+ import { itemLimitForData } from "..";
2
+
3
+ describe("itemLimitForData (no mocks)", () => {
4
+ test("returns full array when item_limit is undefined (default Infinity)", () => {
5
+ // @ts-ignore
6
+ const result = itemLimitForData([1, 2, 3], {
7
+ rules: { item_limit: undefined },
8
+ });
9
+
10
+ expect(result).toEqual([1, 2, 3]);
11
+ });
12
+
13
+ test("enforces positive numeric item_limit", () => {
14
+ // @ts-ignore
15
+ const result = itemLimitForData([1, 2, 3, 4], {
16
+ rules: { item_limit: 2 },
17
+ });
18
+
19
+ expect(result).toEqual([1, 2]);
20
+ });
21
+
22
+ test("returns empty array when entry is empty", () => {
23
+ const result = itemLimitForData([], {
24
+ rules: { item_limit: 3 },
25
+ });
26
+
27
+ expect(result).toEqual([]);
28
+ });
29
+
30
+ test("defaults entry to empty array when it is undefined", () => {
31
+ const result = itemLimitForData(undefined, {
32
+ rules: { item_limit: 5 },
33
+ });
34
+
35
+ expect(result).toEqual([]);
36
+ });
37
+
38
+ test("handles missing component", () => {
39
+ // @ts-ignore
40
+ const result = itemLimitForData([10, 20, 30], undefined);
41
+ // missing component → item_limit = undefined → fallback to Infinity
42
+ expect(result).toEqual([10, 20, 30]);
43
+ });
44
+
45
+ test("handles missing rules object", () => {
46
+ // @ts-ignore
47
+ const result = itemLimitForData([10, 20, 30], {});
48
+
49
+ expect(result).toEqual([10, 20, 30]);
50
+ });
51
+
52
+ test("non-positive item_limit should fall back to Infinity", () => {
53
+ // @ts-ignore
54
+ const result = itemLimitForData([1, 2, 3], {
55
+ rules: { item_limit: -10 },
56
+ });
57
+
58
+ // -10 → invalid → fallback to Infinity → no limit
59
+ expect(result).toEqual([1, 2, 3]);
60
+ });
61
+
62
+ test("zero item_limit should fall back to Infinity", () => {
63
+ // @ts-ignore
64
+ const result = itemLimitForData([1, 2, 3], {
65
+ rules: { item_limit: 0 },
66
+ });
67
+
68
+ // 0 → invalid → fallback to Infinity
69
+ expect(result).toEqual([1, 2, 3]);
70
+ });
71
+
72
+ test("NaN item_limit should fall back to Infinity", () => {
73
+ // @ts-ignore
74
+ const result = itemLimitForData([1, 2, 3], {
75
+ rules: { item_limit: NaN },
76
+ });
77
+
78
+ expect(result).toEqual([1, 2, 3]);
79
+ });
80
+ });
@@ -0,0 +1,19 @@
1
+ import { toPositiveNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
2
+
3
+ export function itemLimitForData(
4
+ entry: ZappEntry[],
5
+ component: {
6
+ rules?: { item_limit?: number | string };
7
+ }
8
+ ) {
9
+ if (!component?.rules?.item_limit) {
10
+ return entry;
11
+ }
12
+
13
+ const itemLimit = toPositiveNumberWithDefault(
14
+ Infinity,
15
+ component?.rules?.item_limit
16
+ );
17
+
18
+ return (entry || []).slice(0, itemLimit);
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "15.0.0-alpha.1627563808",
3
+ "version": "15.0.0-alpha.1966607451",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,10 +28,11 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "15.0.0-alpha.1627563808",
32
- "@applicaster/zapp-react-native-bridge": "15.0.0-alpha.1627563808",
33
- "@applicaster/zapp-react-native-redux": "15.0.0-alpha.1627563808",
34
- "@applicaster/zapp-react-native-utils": "15.0.0-alpha.1627563808",
31
+ "@applicaster/applicaster-types": "15.0.0-alpha.1966607451",
32
+ "@applicaster/zapp-react-native-bridge": "15.0.0-alpha.1966607451",
33
+ "@applicaster/zapp-react-native-redux": "15.0.0-alpha.1966607451",
34
+ "@applicaster/zapp-react-native-utils": "15.0.0-alpha.1966607451",
35
+ "fast-json-stable-stringify": "^2.1.0",
35
36
  "promise": "^8.3.0",
36
37
  "url": "^0.11.0",
37
38
  "uuid": "^3.3.2"
@@ -1,19 +0,0 @@
1
- import * as R from "ramda";
2
-
3
- export function itemLimitForData(entry = [], component) {
4
- const itemLimitValue = Number(R.path(["rules", "item_limit"], component));
5
-
6
- const itemLimit =
7
- itemLimitValue && itemLimitValue > 0
8
- ? itemLimitValue
9
- : Number.MAX_SAFE_INTEGER;
10
-
11
- const isInRange = (min, max) => R.both(R.gte(R.__, min), R.lt(R.__, max));
12
-
13
- const entryShouldBeSliced = (entry) =>
14
- isInRange(0, R.length(entry))(itemLimit);
15
-
16
- const sliceEntriesUpToItemLimit = R.slice(0, itemLimit);
17
-
18
- return R.when(entryShouldBeSliced, sliceEntriesUpToItemLimit)(entry);
19
- }