@applicaster/zapp-react-native-ui-components 16.0.0-rc.12 → 16.0.0-rc.120
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.
- package/Components/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
- package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
- package/Components/AudioPlayer/tv/index.tsx +5 -1
- package/Components/Cell/Cell.tsx +3 -6
- package/Components/Cell/TvOSCellComponent.tsx +0 -1
- package/Components/CellRendererResolver/index.ts +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
- package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
- package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
- package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
- package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
- package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
- package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
- package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
- package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
- package/Components/GeneralContentScreen/index.ts +2 -0
- package/Components/Layout/FullWidthRow.tsx +38 -0
- package/Components/LinkHandler/LinkHandler.tsx +2 -7
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -6
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
- package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
- package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +34 -21
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
- package/Components/MasterCell/__tests__/masterCell.test.js +60 -0
- package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
- package/Components/MasterCell/dataAdapter.ts +15 -5
- package/Components/MasterCell/hooks/index.ts +2 -0
- package/Components/MasterCell/hooks/usePressedState.ts +4 -0
- package/Components/MasterCell/index.tsx +57 -8
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
- package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
- package/Components/MasterCell/utils/__tests__/withoutFocusedState.test.js +20 -0
- package/Components/MasterCell/utils/index.ts +103 -46
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
- package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1028 -0
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +164 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +433 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +563 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +440 -50
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +156 -0
- package/Components/ModalComponent/SortableList.web.tsx +34 -0
- package/Components/ModalComponent/TextInputContent.tsx +135 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
- package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +120 -0
- package/Components/ModalComponent/index.tsx +18 -9
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +54 -0
- package/Components/ModalComponent/utils.ts +82 -21
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
- package/Components/OfflineHandler/__tests__/index.test.tsx +186 -17
- package/Components/OfflineHandler/hooks.ts +111 -0
- package/Components/OfflineHandler/index.tsx +91 -75
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +28 -11
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +91 -62
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +142 -89
- package/Components/River/__tests__/componentsMap.test.js +8 -3
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/Components/Screen/__tests__/Screen.test.tsx +24 -0
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +13 -4
- package/Components/Screen/navigationHandler.ts +8 -8
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
- package/Components/TopCutoffOverlay/index.tsx +2 -2
- package/Components/Transitioner/AnimationManager.js +1 -1
- package/Components/Transitioner/Scene.tsx +4 -3
- package/Components/Transitioner/Transitioner.tsx +98 -49
- package/Components/Transitioner/__tests__/transitioner.test.js +372 -3
- package/Components/VideoLive/LiveImageManager.ts +9 -3
- package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
- package/Components/VideoModal/PlayerWrapper.tsx +4 -1
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/__tests__/playerWrapperStyle.test.ts +58 -0
- package/Components/VideoModal/__tests__/playerWrapperUtils.test.ts +16 -0
- package/Components/VideoModal/playerWrapperStyle.ts +21 -3
- package/Components/VideoModal/playerWrapperUtils.ts +7 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
- package/Contexts/CachedDimensionsContext/index.ts +17 -2
- package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
- package/Contexts/ModalNavigationContext/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/__tests__/screenToolbox.test.ts +347 -0
- package/Decorators/ZappPipesDataConnector/__tests__/screenToolboxUnavailable.test.ts +53 -0
- package/Decorators/ZappPipesDataConnector/index.tsx +19 -4
- package/Decorators/ZappPipesDataConnector/screenToolbox.ts +384 -0
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/index.js +0 -39
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/assets/empty-Info.png +0 -0
- package/package.json +6 -5
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
- package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
- package/Components/Screen/utils.ts +0 -16
- package/Helpers/Analytics/index.js +0 -95
- /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
- /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
- /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
// Fails the screen toolbox as a build without the X-Ray bridge does. Others (player, loaded with
|
|
4
|
+
// the toolbox's imports) register, or the helper would never let the screen toolbox try.
|
|
5
|
+
const mockRegister = jest.fn((toolbox) =>
|
|
6
|
+
toolbox.name === "screen"
|
|
7
|
+
? Promise.reject(new Error("no bridge"))
|
|
8
|
+
: Promise.resolve()
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
// The X-Ray mock (__mocks__/@applicaster/quick-brick-xray) has no toolbox API: give it one.
|
|
12
|
+
require("@applicaster/quick-brick-xray").registerReactToolbox = mockRegister;
|
|
13
|
+
|
|
14
|
+
jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
|
|
15
|
+
appStore: { get: () => undefined },
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
const { useScreenToolboxRecord } = require("../screenToolbox");
|
|
19
|
+
|
|
20
|
+
const mount = (id: string) =>
|
|
21
|
+
renderHook(() =>
|
|
22
|
+
useScreenToolboxRecord({ id }, "home", 0, undefined, "/river/home")
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const mounted = () => {
|
|
26
|
+
// Other toolboxes (player) may register first.
|
|
27
|
+
const { tools } = mockRegister.mock.calls.find(
|
|
28
|
+
([toolbox]) => toolbox.name === "screen"
|
|
29
|
+
)[0];
|
|
30
|
+
|
|
31
|
+
return tools
|
|
32
|
+
.find((tool) => tool.name === "current")
|
|
33
|
+
.handler({ pathname: "/river/home" }).mounted;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe("screenToolbox without the X-Ray bridge", () => {
|
|
37
|
+
it("drops its records and stops recording", async () => {
|
|
38
|
+
mount("c1");
|
|
39
|
+
|
|
40
|
+
// Let the failed registration settle.
|
|
41
|
+
await act(async () => {});
|
|
42
|
+
|
|
43
|
+
expect(mounted()).toEqual([]);
|
|
44
|
+
|
|
45
|
+
mount("c2");
|
|
46
|
+
|
|
47
|
+
expect(mounted()).toEqual([]);
|
|
48
|
+
|
|
49
|
+
expect(
|
|
50
|
+
mockRegister.mock.calls.filter(([toolbox]) => toolbox.name === "screen")
|
|
51
|
+
).toHaveLength(1);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -5,7 +5,9 @@ import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/naviga
|
|
|
5
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
|
+
import { useUIComponentContext } from "@applicaster/zapp-react-native-ui-components/Contexts/UIComponentContext";
|
|
8
9
|
import { ResolverSelector } from "./ResolverSelector";
|
|
10
|
+
import { useScreenToolboxRecord } from "./screenToolbox";
|
|
9
11
|
import { ComponentDataSourceContext } from "./types";
|
|
10
12
|
|
|
11
13
|
type Props = {
|
|
@@ -22,7 +24,7 @@ export function zappPipesDataConnector(
|
|
|
22
24
|
Component: React.FC<any> | React.ComponentClass<any>
|
|
23
25
|
) {
|
|
24
26
|
return function WrappedWithZappPipesData(props: Props) {
|
|
25
|
-
const { screenData } = useRoute();
|
|
27
|
+
const { screenData, pathname } = useRoute();
|
|
26
28
|
const plugins = usePlugins();
|
|
27
29
|
const screenContextData = useScreenContext();
|
|
28
30
|
|
|
@@ -53,6 +55,16 @@ export function zappPipesDataConnector(
|
|
|
53
55
|
|
|
54
56
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
55
57
|
|
|
58
|
+
const parent = useUIComponentContext() as { id?: string } | null;
|
|
59
|
+
|
|
60
|
+
const toolboxRecord = useScreenToolboxRecord(
|
|
61
|
+
component,
|
|
62
|
+
riverId,
|
|
63
|
+
componentIndex,
|
|
64
|
+
parent?.id,
|
|
65
|
+
pathname
|
|
66
|
+
);
|
|
67
|
+
|
|
56
68
|
// Prepare context for resolvers
|
|
57
69
|
const resolverProps: ComponentDataSourceContext = {
|
|
58
70
|
component,
|
|
@@ -71,9 +83,12 @@ export function zappPipesDataConnector(
|
|
|
71
83
|
|
|
72
84
|
return (
|
|
73
85
|
<ResolverSelector {...resolverProps}>
|
|
74
|
-
{(zappPipesDataProps) =>
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
{(zappPipesDataProps) => {
|
|
87
|
+
// A plain field on the toolbox record, read only when the agent asks: no render.
|
|
88
|
+
toolboxRecord.feed = zappPipesDataProps.zappPipesData;
|
|
89
|
+
|
|
90
|
+
return <Component {...props} {...zappPipesDataProps} />;
|
|
91
|
+
}}
|
|
77
92
|
</ResolverSelector>
|
|
78
93
|
);
|
|
79
94
|
};
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
|
+
import { Platform } from "react-native";
|
|
3
|
+
import * as R from "ramda";
|
|
4
|
+
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
5
|
+
import {
|
|
6
|
+
registerXrayToolbox,
|
|
7
|
+
XrayToolSpec,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/logger/xrayToolbox";
|
|
9
|
+
import { modalStore } from "@applicaster/zapp-react-native-utils/modalState";
|
|
10
|
+
import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
|
|
11
|
+
import { getXrayNavigator } from "@applicaster/zapp-react-native-utils/navigationUtils/xrayNavigator";
|
|
12
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
13
|
+
import { zappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
|
|
14
|
+
|
|
15
|
+
import { ZappPipesData } from "./types";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* X-Ray `screen.*` toolbox: what the current screen shows — its river components in order, the
|
|
19
|
+
* feed each one loaded and the entries it displays. Every river component, on every platform,
|
|
20
|
+
* goes through the zappPipes decorator, which writes a record here on mount and drops it on
|
|
21
|
+
* unmount: a plain Set, nothing subscribes to it, so it never renders anything. Records are
|
|
22
|
+
* dropped for good once X-Ray turns out to have no toolbox bridge (release builds).
|
|
23
|
+
*
|
|
24
|
+
* Screens that are not rivers (screen plugins, hooks, the player) report what renders them,
|
|
25
|
+
* read from navigation and the modal stores; a plugin with state of its own registers its own
|
|
26
|
+
* toolbox, as the player does.
|
|
27
|
+
*
|
|
28
|
+
* Mounted is not visible (lists are virtualised): which rows and cells are on screen comes from
|
|
29
|
+
* the native `ui.inspect`. River rows carry testID `component-<componentId>` (mobile, tvOS,
|
|
30
|
+
* Android TV) and cells carry their entry id in their testID.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
type ComponentRecord = {
|
|
34
|
+
component: ZappUIComponent;
|
|
35
|
+
riverId: string;
|
|
36
|
+
index?: number;
|
|
37
|
+
parentId?: string;
|
|
38
|
+
pathname: string;
|
|
39
|
+
/** Written on each render: the data the component was given, after item filter and limit. */
|
|
40
|
+
feed?: ZappPipesData;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** What a route shows; `screenType` is how ScreenResolver renders it. */
|
|
44
|
+
type RouteState = {
|
|
45
|
+
screenType?: string;
|
|
46
|
+
screen?: any;
|
|
47
|
+
entry?: Partial<ZappEntry>;
|
|
48
|
+
nested?: { screen?: ZappRiver };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** A screen presented over the navigation stack. `covers` is false when it is out of the way. */
|
|
52
|
+
type Layer = RouteState & { pathname: string; covers: boolean };
|
|
53
|
+
|
|
54
|
+
const records = new Set<ComponentRecord>();
|
|
55
|
+
|
|
56
|
+
/** Set once registration failed: X-Ray has no toolbox bridge, so nothing will ever read records. */
|
|
57
|
+
let unavailable = false;
|
|
58
|
+
|
|
59
|
+
const DEFAULT_ENTRIES_LIMIT = 10;
|
|
60
|
+
|
|
61
|
+
const toLimit = (value: unknown) =>
|
|
62
|
+
typeof value === "number" && value >= 0 ? value : DEFAULT_ENTRIES_LIMIT;
|
|
63
|
+
|
|
64
|
+
/** The hooks modal, with the pathname ZappHooksModal gives it; hidden while it runs in the background. */
|
|
65
|
+
const hooksModalLayer = (): Layer | undefined => {
|
|
66
|
+
const { state, isHooksExecutionInProgress, isRunningInBackground } =
|
|
67
|
+
zappHookModalStore.getState();
|
|
68
|
+
|
|
69
|
+
if (!isHooksExecutionInProgress || !state.path) return undefined;
|
|
70
|
+
|
|
71
|
+
const hookPlugin = state.screenData?.hookPlugin;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
pathname: `${ROUTE_TYPES.HOOKS_MODAL}/${hookPlugin ? hookPlugin.name : ""}`,
|
|
75
|
+
covers:
|
|
76
|
+
!isRunningInBackground && hookPlugin?.module?.presentFullScreen !== false,
|
|
77
|
+
screenType: "hooks",
|
|
78
|
+
screen: hookPlugin,
|
|
79
|
+
entry: state.screenData?.payload as ZappEntry,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** The modal screen or bottom sheet, with the pathname and props ModalProvider gives it. */
|
|
84
|
+
const modalLayer = (): Layer | undefined => {
|
|
85
|
+
const { visible, screen, props } = modalStore.getState().modalState;
|
|
86
|
+
|
|
87
|
+
if (!visible || !screen) return undefined;
|
|
88
|
+
|
|
89
|
+
const { screenId, screenType, entry, screenData } = {
|
|
90
|
+
screenId: screen.id,
|
|
91
|
+
screenType: "river",
|
|
92
|
+
...props,
|
|
93
|
+
} as Record<string, any>;
|
|
94
|
+
|
|
95
|
+
// A modal hook (and the ad interstitial) presents a { hookPlugin, payload } wrapper.
|
|
96
|
+
const isHook = screenType === "hooks";
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
pathname: `${ROUTE_TYPES.MODAL}/${screenId}`,
|
|
100
|
+
covers: true,
|
|
101
|
+
screenType,
|
|
102
|
+
screen: isHook ? (screen.hookPlugin ?? screenData?.hookPlugin) : screen,
|
|
103
|
+
entry: isHook ? screen.payload : entry,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const videoModalLayer = (): Layer | undefined => {
|
|
108
|
+
const videoModal = getXrayNavigator()?.videoModalState;
|
|
109
|
+
|
|
110
|
+
if (!videoModal?.visible) return undefined;
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
pathname: `${ROUTE_TYPES.VIDEO_MODAL}/${videoModal.item?.id}`,
|
|
114
|
+
covers: videoModal.mode !== "MINIMIZED",
|
|
115
|
+
screenType: "playable",
|
|
116
|
+
entry: videoModal.item,
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Topmost first: the hooks modal and modals are native RN Modals, drawn over the video modal.
|
|
122
|
+
* Only layers this platform renders: the mobile layout renders the hooks and video modals, and
|
|
123
|
+
* ModalProvider renders nothing on web.
|
|
124
|
+
*/
|
|
125
|
+
const presentedLayers = () => {
|
|
126
|
+
const web = Platform.OS === "web";
|
|
127
|
+
const mobile = !web && !isTV();
|
|
128
|
+
|
|
129
|
+
return [
|
|
130
|
+
mobile && hooksModalLayer(),
|
|
131
|
+
!web && modalLayer(),
|
|
132
|
+
mobile && videoModalLayer(),
|
|
133
|
+
].filter((layer): layer is Layer => Boolean(layer));
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/** The pathname of what is on top: a covering presented layer, else the stack top. */
|
|
137
|
+
export const getTopPathname = (): string | undefined =>
|
|
138
|
+
presentedLayers().find((layer) => layer.covers)?.pathname ??
|
|
139
|
+
getXrayNavigator()?.getPathname();
|
|
140
|
+
|
|
141
|
+
/** What the route at `pathname` shows. Presented layers are not on the stack: their stores hold them. */
|
|
142
|
+
const routeState = (pathname: string): RouteState => {
|
|
143
|
+
const layer = presentedLayers().find((item) => item.pathname === pathname);
|
|
144
|
+
|
|
145
|
+
if (layer) return layer;
|
|
146
|
+
|
|
147
|
+
// Not presented any more (a stale modal pathname): nothing to describe.
|
|
148
|
+
if (!pathname.startsWith("/")) return {};
|
|
149
|
+
|
|
150
|
+
const state = getXrayNavigator()?.getStackForPathname(pathname)?.state;
|
|
151
|
+
|
|
152
|
+
// A stack route ends in <screenType>/<screenId>.
|
|
153
|
+
const screenType = pathname.split("/").slice(-2)[0];
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
screenType,
|
|
157
|
+
...state,
|
|
158
|
+
// A hook screen's entry is the { payload } wrapper it was pushed with.
|
|
159
|
+
entry:
|
|
160
|
+
screenType === "hooks"
|
|
161
|
+
? ((state?.entry as any)?.payload ?? state?.entry)
|
|
162
|
+
: state?.entry,
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/** Screen types ScreenResolver renders itself rather than through a screen plugin. */
|
|
167
|
+
const BUILT_IN_KINDS = {
|
|
168
|
+
playable: "player",
|
|
169
|
+
link: "link",
|
|
170
|
+
favorites: "favorites",
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* What renders the screen, as ScreenResolver picks it: a river of components, a built-in screen,
|
|
175
|
+
* a hook plugin, or a screen plugin (a river whose type is a plugin identifier, or a route whose
|
|
176
|
+
* screen type is one).
|
|
177
|
+
*/
|
|
178
|
+
const describeKind = ({
|
|
179
|
+
screenType,
|
|
180
|
+
screen,
|
|
181
|
+
}: RouteState): { kind: string; identifier?: string } => {
|
|
182
|
+
if (!screenType) return { kind: "none" };
|
|
183
|
+
|
|
184
|
+
if (screen?.modalBottomSheetContentProps) return { kind: "bottomSheet" };
|
|
185
|
+
|
|
186
|
+
if (screenType === "hooks") {
|
|
187
|
+
return { kind: "hook", identifier: screen?.identifier };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (BUILT_IN_KINDS[screenType]) return { kind: BUILT_IN_KINDS[screenType] };
|
|
191
|
+
|
|
192
|
+
if (screenType !== "river") return { kind: "plugin", identifier: screenType };
|
|
193
|
+
|
|
194
|
+
return screen?.type === "general_content"
|
|
195
|
+
? { kind: "river" }
|
|
196
|
+
: { kind: "plugin", identifier: screen?.type };
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const describePlugin = (identifier?: string) => {
|
|
200
|
+
if (!identifier) return null;
|
|
201
|
+
|
|
202
|
+
const plugins = (appStore.get("plugins") ?? []) as QuickBrickPlugin[];
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
identifier,
|
|
206
|
+
name: plugins.find((plugin) => plugin.identifier === identifier)?.name,
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const describeFeed = (feed?: ZappPipesData) => {
|
|
211
|
+
if (!feed?.url) return null;
|
|
212
|
+
|
|
213
|
+
const error = feed.error as { message?: string } | undefined;
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
url: feed.url,
|
|
217
|
+
state: error ? "error" : feed.loading ? "loading" : "loaded",
|
|
218
|
+
...(error && { error: error.message ?? String(error) }),
|
|
219
|
+
count: feed.data?.entry?.length ?? 0,
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const byIndex = (a: ComponentRecord, b: ComponentRecord) =>
|
|
224
|
+
(a.index ?? 0) - (b.index ?? 0);
|
|
225
|
+
|
|
226
|
+
/** Components in order, a group's children nested under it (they share the river and its indexes). */
|
|
227
|
+
const describeComponents = (
|
|
228
|
+
mounted: ComponentRecord[],
|
|
229
|
+
belongs: (record: ComponentRecord) => boolean,
|
|
230
|
+
limit: number
|
|
231
|
+
) =>
|
|
232
|
+
mounted
|
|
233
|
+
.filter(belongs)
|
|
234
|
+
.sort(byIndex)
|
|
235
|
+
.map((record) => {
|
|
236
|
+
const children = describeComponents(
|
|
237
|
+
mounted,
|
|
238
|
+
(child) => child.parentId === record.component.id,
|
|
239
|
+
limit
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
index: record.index,
|
|
244
|
+
id: record.component.id,
|
|
245
|
+
type: record.component.component_type,
|
|
246
|
+
name: record.component.name,
|
|
247
|
+
feed: describeFeed(record.feed),
|
|
248
|
+
entries: (record.feed?.data?.entry ?? [])
|
|
249
|
+
.slice(0, limit)
|
|
250
|
+
.map((entry, index) => ({ index, id: entry.id, title: entry.title })),
|
|
251
|
+
...(children.length > 0 && { children }),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const describeRiverComponents = (mounted: ComponentRecord[], limit: number) => {
|
|
256
|
+
const ids = new Set(mounted.map((record) => record.component.id));
|
|
257
|
+
|
|
258
|
+
return describeComponents(
|
|
259
|
+
mounted,
|
|
260
|
+
(record) => !record.parentId || !ids.has(record.parentId),
|
|
261
|
+
limit
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const describeScreen = (pathname: string, limit: number) => {
|
|
266
|
+
const state = routeState(pathname);
|
|
267
|
+
const { screen, entry, nested } = state;
|
|
268
|
+
const { kind, identifier } = describeKind(state);
|
|
269
|
+
const plugin = describePlugin(identifier);
|
|
270
|
+
|
|
271
|
+
const mounted = Array.from(records).filter(
|
|
272
|
+
(record) => record.pathname === pathname
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const riverIds = R.uniq(mounted.map((record) => record.riverId));
|
|
276
|
+
const rivers = appStore.get("rivers") as Record<string, ZappRiver>;
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
pathname,
|
|
280
|
+
screen: {
|
|
281
|
+
kind,
|
|
282
|
+
...(screen && { id: screen.id, name: screen.name, type: screen.type }),
|
|
283
|
+
...(plugin && { plugin }),
|
|
284
|
+
},
|
|
285
|
+
...(nested?.screen && {
|
|
286
|
+
nested: {
|
|
287
|
+
id: nested.screen.id,
|
|
288
|
+
name: nested.screen.name,
|
|
289
|
+
type: nested.screen.type,
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
entry: entry ? { id: entry.id, title: entry.title } : null,
|
|
293
|
+
rivers: riverIds.map((riverId) => ({
|
|
294
|
+
id: riverId,
|
|
295
|
+
name: rivers?.[riverId]?.name,
|
|
296
|
+
type: rivers?.[riverId]?.type,
|
|
297
|
+
components: describeRiverComponents(
|
|
298
|
+
mounted.filter((record) => record.riverId === riverId),
|
|
299
|
+
limit
|
|
300
|
+
),
|
|
301
|
+
})),
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const tools: XrayToolSpec[] = [
|
|
306
|
+
{
|
|
307
|
+
name: "current",
|
|
308
|
+
description:
|
|
309
|
+
"The screen on top (hooks modal, modal or bottom sheet, video modal unless docked, else stack top) " +
|
|
310
|
+
"or the one at `pathname`: what renders it (kind river, plugin, hook, player, link, favorites, " +
|
|
311
|
+
"bottomSheet, and the plugin), its river components in order (a group's children nested) with " +
|
|
312
|
+
"their feed (url, state, count) and first entries. " +
|
|
313
|
+
"Lists mount ahead of the viewport, so a component here may be off screen: use the native " +
|
|
314
|
+
"ui.inspect for what is visible (row testID component-<id>; cell testIDs contain the entry id).",
|
|
315
|
+
parameters: [
|
|
316
|
+
{
|
|
317
|
+
name: "pathname",
|
|
318
|
+
type: "string",
|
|
319
|
+
description:
|
|
320
|
+
"A mounted screen's route (see mounted); defaults to the top one.",
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "limit",
|
|
324
|
+
type: "number",
|
|
325
|
+
description: `Entries per component, default ${DEFAULT_ENTRIES_LIMIT}.`,
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
handler: ({ pathname, limit }) => {
|
|
329
|
+
const target =
|
|
330
|
+
typeof pathname === "string" && pathname ? pathname : getTopPathname();
|
|
331
|
+
|
|
332
|
+
if (!target) throw new Error("Navigation is not available yet");
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
...describeScreen(target, toLimit(limit)),
|
|
336
|
+
mounted: R.uniq(Array.from(records, (record) => record.pathname)),
|
|
337
|
+
};
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
];
|
|
341
|
+
|
|
342
|
+
const registerScreenToolbox = () =>
|
|
343
|
+
registerXrayToolbox({
|
|
344
|
+
name: "screen",
|
|
345
|
+
description:
|
|
346
|
+
"What the current screen shows: what renders it, river components, their feeds and entries.",
|
|
347
|
+
tools,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Keeps a record of a mounted river component for the toolbox. Returns the record so the caller
|
|
352
|
+
* can attach the feed data it renders with.
|
|
353
|
+
*/
|
|
354
|
+
export const useScreenToolboxRecord = (
|
|
355
|
+
component: ZappUIComponent,
|
|
356
|
+
riverId: string,
|
|
357
|
+
index: number | undefined,
|
|
358
|
+
parentId: string | undefined,
|
|
359
|
+
pathname: string
|
|
360
|
+
): ComponentRecord => {
|
|
361
|
+
const record = useMemo(
|
|
362
|
+
() => ({ component, riverId, index, parentId, pathname }),
|
|
363
|
+
[component, riverId, index, parentId, pathname]
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
if (unavailable) return;
|
|
368
|
+
|
|
369
|
+
registerScreenToolbox().then((registered) => {
|
|
370
|
+
if (!registered) {
|
|
371
|
+
unavailable = true;
|
|
372
|
+
records.clear();
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
records.add(record);
|
|
377
|
+
|
|
378
|
+
return () => {
|
|
379
|
+
records.delete(record);
|
|
380
|
+
};
|
|
381
|
+
}, [record]);
|
|
382
|
+
|
|
383
|
+
return record;
|
|
384
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { sendTapCellEvent, sendTapMenuItem } from "../Analytics";
|
|
2
1
|
import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
3
2
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
4
3
|
|
|
@@ -12,7 +11,6 @@ export function onCellPress(
|
|
|
12
11
|
itemIndex,
|
|
13
12
|
layoutVersion = "v1"
|
|
14
13
|
) {
|
|
15
|
-
sendTapCellEvent(entry, component, headerTitle, itemIndex);
|
|
16
14
|
const componentScreenType = screenTypeFromComponent(component);
|
|
17
15
|
const entryScreenType = screenTypeFromEntry(entry);
|
|
18
16
|
const itemType = getItemType(entry, layoutVersion);
|
|
@@ -37,7 +35,3 @@ function screenTypeFromComponent(component) {
|
|
|
37
35
|
function screenTypeFromEntry(entry) {
|
|
38
36
|
return entry && entry.screen_type;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
export function onMenuItemFocus({ item, index, isHome }) {
|
|
42
|
-
sendTapMenuItem({ item, index, isHome });
|
|
43
|
-
}
|
package/Helpers/index.js
CHANGED
|
@@ -7,42 +7,3 @@ export const ASSETS = {
|
|
|
7
7
|
amazon: "tv_app_background",
|
|
8
8
|
}),
|
|
9
9
|
};
|
|
10
|
-
|
|
11
|
-
export const ANALYTICS_CORE_EVENTS = {
|
|
12
|
-
TAP_CELL: "Tap Cell",
|
|
13
|
-
PLAY_VOD_ITEM: "Play VOD Item",
|
|
14
|
-
VOD_ITEM_PLAY_WAS_TRIGGERED: "VOD Item: Play Was Triggered",
|
|
15
|
-
CHANNEL_ITEM_PLAY_WAS_TRIGGERED: "Channel Item: Play Was Triggered",
|
|
16
|
-
PROGRAM_ITEM_PLAY_WAS_TRIGGERED: "Program Item: Play Was Triggered",
|
|
17
|
-
TAP_MENU_ICON: "Tap Menu Item",
|
|
18
|
-
HOME_SCREEN_VIEWED: "Home Screen: Viewed",
|
|
19
|
-
ITEM_NOT_AVAILABLE: "N/A",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const ANALYTICS_ENTRY_EVENTS = {
|
|
23
|
-
ITEM_TYPE: "Item Type",
|
|
24
|
-
ITEM_TITLE: "Item Name",
|
|
25
|
-
ITEM_ID: "Item ID",
|
|
26
|
-
ITEM_LINK: "Item Link",
|
|
27
|
-
ITEM_INDEX: "Item Number",
|
|
28
|
-
ITEM_TIME_PLAYED: "Item Total Time Played",
|
|
29
|
-
ITEM_TOTAL_TIME_PLAYED: "Item Total Time Played",
|
|
30
|
-
ITEM_PLAY_COMPLETED: "Completed",
|
|
31
|
-
ITEM_CUSTOM_PROPERTY: "Custom Property",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const ANALYTICS_COMPONENT_EVENTS = {
|
|
35
|
-
COMPONENT_ID: "Component ID",
|
|
36
|
-
COMPONENT_TYPE: "Component Type",
|
|
37
|
-
CELL_STYLE: "Cell Style",
|
|
38
|
-
HEADER_TITLE: "Header Name",
|
|
39
|
-
COMPONENT_SOURCE: "Component Source",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const ANALYTICS_MENU_ITEM_EVENTS = {
|
|
43
|
-
ITEM_TYPE: "Item Type",
|
|
44
|
-
ITEM_TITLE: "Item Name",
|
|
45
|
-
ITEM_ID: "Item ID",
|
|
46
|
-
ITEM_HOME_SCREEN: "Home Screen",
|
|
47
|
-
ITEM_INDEX: "Item Number",
|
|
48
|
-
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
|
|
4
|
+
import {
|
|
5
|
+
buildEntryActions,
|
|
6
|
+
EntryActionDeps,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/entryActions";
|
|
8
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
9
|
+
import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
|
|
10
|
+
import {
|
|
11
|
+
useCurrentScreenData,
|
|
12
|
+
useScreenContext,
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
14
|
+
import { RegisteredAction } from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Expands `entry.extensions.entry_action` into invokable actions, against the
|
|
18
|
+
* screen this hook is called from.
|
|
19
|
+
*
|
|
20
|
+
* Entry actions are data on the entry, not an installed capability, so there is
|
|
21
|
+
* nothing to look up by identifier: the surface showing the entry expands them.
|
|
22
|
+
* That also decides which screen they execute against — the one whose tree this
|
|
23
|
+
* hook runs in, rather than whichever screen happened to be current when a
|
|
24
|
+
* global provider was registered.
|
|
25
|
+
*
|
|
26
|
+
* Pass the result to `resolveActionIdentifiers` / `resolvePlayerActions` as
|
|
27
|
+
* `expandEntryActions`.
|
|
28
|
+
*/
|
|
29
|
+
export function useEntryActionsExpander(): (
|
|
30
|
+
entry: ZappEntry | ZappFeed
|
|
31
|
+
) => RegisteredAction[] {
|
|
32
|
+
const { pathname } = useRoute();
|
|
33
|
+
|
|
34
|
+
const screenContext = useScreenContext();
|
|
35
|
+
const screenData = useCurrentScreenData();
|
|
36
|
+
const screenState = screenContext?.options;
|
|
37
|
+
const screenStateStore = useScreenStateStore();
|
|
38
|
+
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
39
|
+
|
|
40
|
+
// Read through a ref so the returned expander keeps a stable identity: it
|
|
41
|
+
// feeds `useMemo` dependency lists on surfaces that re-resolve their actions
|
|
42
|
+
// on every registry change.
|
|
43
|
+
const depsRef = React.useRef<EntryActionDeps>();
|
|
44
|
+
|
|
45
|
+
depsRef.current = {
|
|
46
|
+
actionExecutor,
|
|
47
|
+
actionContext: {
|
|
48
|
+
screenData,
|
|
49
|
+
screenState,
|
|
50
|
+
screenRoute: pathname,
|
|
51
|
+
screenStateStore,
|
|
52
|
+
// From the screen context, the way `useCellClick` builds the same bag.
|
|
53
|
+
// The ZappPipes entry context is a route-keyed map, so reading `.data`
|
|
54
|
+
// off it was always undefined.
|
|
55
|
+
screenEntry: screenContext?.entry,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return React.useCallback(
|
|
60
|
+
(entry: ZappEntry | ZappFeed) => buildEntryActions(entry, depsRef.current),
|
|
61
|
+
[]
|
|
62
|
+
);
|
|
63
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "16.0.0-rc.
|
|
3
|
+
"version": "16.0.0-rc.120",
|
|
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,12 +28,13 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "16.0.0-rc.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "16.0.0-rc.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "16.0.0-rc.
|
|
31
|
+
"@applicaster/applicaster-types": "16.0.0-rc.120",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.120",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "16.0.0-rc.120",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "16.0.0-rc.120",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
|
+
"react-native-sortables": "1.7.1",
|
|
37
38
|
"url": "^0.11.0",
|
|
38
39
|
"uuid": "^3.3.2"
|
|
39
40
|
},
|