@applicaster/quick-brick-core 16.0.0-rc.11 → 16.0.0-rc.111
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/App/ActionsProvider/ActionsProvider.tsx +31 -9
- package/App/ActionsProvider/LegacyActionsRegistryAdapter.tsx +123 -0
- package/App/ActionsProvider/__tests__/LegacyActionsRegistryAdapter.test.tsx +64 -0
- package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/__tests__/useOpenSchemeHandler.test.tsx +25 -15
- package/App/ModalProvider/ModalBottomSheet/DraggableBottomSheet/__tests__/index.test.tsx +88 -0
- package/App/ModalProvider/ModalBottomSheet/DraggableBottomSheet/index.tsx +30 -56
- package/App/ModalProvider/ModalBottomSheet/ModalBottomSheetFrame.tsx +9 -2
- package/App/ModalProvider/ModalBottomSheet/hooks/__tests__/useKeyboardHeight.android.test.ts +105 -0
- package/App/ModalProvider/ModalBottomSheet/hooks/__tests__/useKeyboardHeight.test.ts +102 -0
- package/App/ModalProvider/ModalBottomSheet/hooks/index.ts +1 -0
- package/App/ModalProvider/ModalBottomSheet/hooks/useKeyboardHeight.ts +30 -0
- package/App/ModalProvider/ModalBottomSheet/index.tsx +5 -2
- package/App/ModalProvider/ModalContent.tsx +3 -0
- package/App/ModalProvider/__tests__/ModalContent.test.tsx +39 -0
- package/App/ModalProvider/__tests__/index.test.tsx +99 -0
- package/App/ModalProvider/index.tsx +39 -14
- package/App/NavigationProvider/NavigationProvider.tsx +57 -5
- package/App/NavigationProvider/__tests__/navigationProvider.test.tsx +56 -0
- package/App/NavigationProvider/__tests__/utils.test.ts +31 -1
- package/App/NavigationProvider/utils.ts +14 -0
- package/App/NetworkStatusProvider/NetworkStatusProvider.tsx +32 -4
- package/App/NetworkStatusProvider/ResumeVerificationController.ts +282 -0
- package/App/NetworkStatusProvider/__tests__/NetworkStatusProvider.test.tsx +152 -1
- package/App/NetworkStatusProvider/__tests__/ResumeVerificationController.test.ts +471 -0
- package/App/NetworkStatusProvider/__tests__/resumeVerification.test.ts +126 -0
- package/App/NetworkStatusProvider/__tests__/useResumeVerifiedNetInfo.test.ts +189 -0
- package/App/NetworkStatusProvider/resumeVerification.ts +54 -0
- package/App/NetworkStatusProvider/useResumeVerifiedNetInfo.ts +33 -0
- package/App/NotificationToastRenderer/NotificationToastManager.ts +214 -0
- package/App/NotificationToastRenderer/NotificationToastRenderer.tsx +134 -0
- package/App/NotificationToastRenderer/NotificationToastRenderer.tv.tsx +10 -0
- package/App/NotificationToastRenderer/NotificationToastRenderer.web.tsx +61 -0
- package/App/NotificationToastRenderer/__tests__/NotificationToastManager.test.ts +237 -0
- package/App/NotificationToastRenderer/__tests__/NotificationToastRenderer.test.tsx +233 -0
- package/App/NotificationToastRenderer/__tests__/NotificationToastRenderer.web.test.tsx +90 -0
- package/App/NotificationToastRenderer/__tests__/resolveConfirmationToastStyle.test.ts +118 -0
- package/App/NotificationToastRenderer/__tests__/useNotificationHeight.test.tsx +58 -0
- package/App/NotificationToastRenderer/__tests__/useNotificationToastState.test.ts +112 -0
- package/App/NotificationToastRenderer/index.tsx +9 -0
- package/App/NotificationToastRenderer/resolveConfirmationToastStyle.ts +33 -0
- package/App/NotificationToastRenderer/useNotificationHeight.tsx +14 -0
- package/App/NotificationToastRenderer/useNotificationToastState.tsx +12 -0
- package/App/index.tsx +8 -5
- package/package.json +8 -8
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
let mockInsets = { top: 0 };
|
|
4
|
+
const mockGetNavbarHeight = jest.fn();
|
|
5
|
+
|
|
6
|
+
jest.mock("react-native-safe-area-context", () => ({
|
|
7
|
+
useSafeAreaInsets: () => mockInsets,
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
|
|
11
|
+
getNavbarHeight: () => mockGetNavbarHeight(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
import { useNotificationHeight } from "../useNotificationHeight";
|
|
15
|
+
|
|
16
|
+
describe("useNotificationHeight", () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
mockGetNavbarHeight.mockClear();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("adds the safe area top inset to the nav bar height", () => {
|
|
22
|
+
mockInsets = { top: 44 };
|
|
23
|
+
mockGetNavbarHeight.mockReturnValueOnce(56);
|
|
24
|
+
|
|
25
|
+
const { result } = renderHook(() => useNotificationHeight());
|
|
26
|
+
|
|
27
|
+
expect(result.current).toEqual({
|
|
28
|
+
statusHeight: 44,
|
|
29
|
+
notificationHeight: 100,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("falls back to a 0 status height when there is no top inset", () => {
|
|
34
|
+
mockInsets = { top: 0 };
|
|
35
|
+
mockGetNavbarHeight.mockReturnValueOnce(44);
|
|
36
|
+
|
|
37
|
+
const { result } = renderHook(() => useNotificationHeight());
|
|
38
|
+
|
|
39
|
+
expect(result.current).toEqual({
|
|
40
|
+
statusHeight: 0,
|
|
41
|
+
notificationHeight: 44,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("uses getNavbarHeight for the nav bar height", () => {
|
|
46
|
+
mockInsets = { top: 20 };
|
|
47
|
+
mockGetNavbarHeight.mockReturnValueOnce(56);
|
|
48
|
+
|
|
49
|
+
const { result } = renderHook(() => useNotificationHeight());
|
|
50
|
+
|
|
51
|
+
expect(mockGetNavbarHeight).toHaveBeenCalled();
|
|
52
|
+
|
|
53
|
+
expect(result.current).toEqual({
|
|
54
|
+
statusHeight: 20,
|
|
55
|
+
notificationHeight: 76,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
import { notificationToastManager } from "../NotificationToastManager";
|
|
4
|
+
import { useNotificationToastState } from "../useNotificationToastState";
|
|
5
|
+
|
|
6
|
+
jest.useFakeTimers();
|
|
7
|
+
|
|
8
|
+
describe("useNotificationToastState", () => {
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterAll(() => {
|
|
14
|
+
(console.log as jest.Mock).mockRestore();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
// drain whatever is left showing/queued so the next test starts clean;
|
|
19
|
+
// the hook's own effect cleanup (on unmount) removes its SHOW/HIDE
|
|
20
|
+
// handlers automatically via RNTL's auto-cleanup.
|
|
21
|
+
for (let i = 0; i < 10; i++) {
|
|
22
|
+
notificationToastManager.dismiss();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
jest.restoreAllMocks();
|
|
26
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("starts with no toast", () => {
|
|
30
|
+
const { result } = renderHook(() => useNotificationToastState());
|
|
31
|
+
|
|
32
|
+
expect(result.current).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("reflects the toast emitted by the manager's SHOW event", () => {
|
|
36
|
+
const { result } = renderHook(() => useNotificationToastState());
|
|
37
|
+
|
|
38
|
+
act(() => {
|
|
39
|
+
notificationToastManager.showToast({ message: "hello" });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(result.current).toEqual(
|
|
43
|
+
expect.objectContaining({ message: "hello" })
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("clears the toast when the manager emits HIDE", () => {
|
|
48
|
+
const { result } = renderHook(() => useNotificationToastState());
|
|
49
|
+
|
|
50
|
+
act(() => {
|
|
51
|
+
notificationToastManager.showToast({ message: "hello" });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(result.current).not.toBeNull();
|
|
55
|
+
|
|
56
|
+
act(() => {
|
|
57
|
+
notificationToastManager.dismiss();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(result.current).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("stops updating after unmount", () => {
|
|
64
|
+
const { result, unmount } = renderHook(() => useNotificationToastState());
|
|
65
|
+
|
|
66
|
+
unmount();
|
|
67
|
+
|
|
68
|
+
act(() => {
|
|
69
|
+
notificationToastManager.showToast({ message: "after unmount" });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(result.current).toBeNull();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("subscribes on mount and disposes the subscription on unmount", () => {
|
|
76
|
+
const dispose = jest.fn();
|
|
77
|
+
|
|
78
|
+
const subscribeSpy = jest
|
|
79
|
+
.spyOn(notificationToastManager, "subscribe")
|
|
80
|
+
.mockReturnValue(dispose);
|
|
81
|
+
|
|
82
|
+
const { unmount } = renderHook(() => useNotificationToastState());
|
|
83
|
+
|
|
84
|
+
expect(subscribeSpy).toHaveBeenCalledWith(expect.any(Function));
|
|
85
|
+
expect(dispose).not.toHaveBeenCalled();
|
|
86
|
+
|
|
87
|
+
unmount();
|
|
88
|
+
|
|
89
|
+
expect(dispose).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("subscribe registers SHOW/HIDE handlers and its disposer removes them", () => {
|
|
93
|
+
const callback = jest.fn();
|
|
94
|
+
|
|
95
|
+
const dispose = notificationToastManager.subscribe(callback);
|
|
96
|
+
|
|
97
|
+
act(() => {
|
|
98
|
+
notificationToastManager.showToast({ message: "hello" }); // emits SHOW
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(callback).toHaveBeenCalled();
|
|
102
|
+
|
|
103
|
+
callback.mockClear();
|
|
104
|
+
dispose();
|
|
105
|
+
|
|
106
|
+
act(() => {
|
|
107
|
+
notificationToastManager.showToast({ message: "again" }); // emits SHOW
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(callback).not.toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { notificationToastManager } from "./NotificationToastManager";
|
|
2
|
+
|
|
3
|
+
export type { ToastPayload, ToastStyle } from "./NotificationToastManager";
|
|
4
|
+
|
|
5
|
+
export { CONFIRMATION_TOAST_SOURCE } from "./NotificationToastManager";
|
|
6
|
+
|
|
7
|
+
export { NotificationToastRenderer } from "./NotificationToastRenderer";
|
|
8
|
+
|
|
9
|
+
export { resolveConfirmationToastStyle } from "./resolveConfirmationToastStyle";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getAllSpecificStyles } from "@applicaster/zapp-react-native-utils/configurationUtils/manifestKeyParser";
|
|
2
|
+
|
|
3
|
+
import { ToastStyle } from "./NotificationToastManager";
|
|
4
|
+
|
|
5
|
+
const CONFIRMATION_TOAST_STYLE_COMPONENT = "confirmation_toast";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builds confirmation-toast style from Theme defaults via getAllSpecificStyles,
|
|
9
|
+
* then shallow-merges any caller override on top.
|
|
10
|
+
*
|
|
11
|
+
* Expected Theme keys follow:
|
|
12
|
+
* `confirmation_toast_style_[platform_]<style_name>`
|
|
13
|
+
* e.g. confirmation_toast_style_background_color,
|
|
14
|
+
* confirmation_toast_style_ios_font_family
|
|
15
|
+
*/
|
|
16
|
+
export function resolveConfirmationToastStyle(
|
|
17
|
+
theme: Partial<BaseThemePropertiesMobile> | null | undefined,
|
|
18
|
+
overrideStyle?: ToastStyle | null
|
|
19
|
+
): ToastStyle {
|
|
20
|
+
const outStyles: Record<string, ToastStyle> = {};
|
|
21
|
+
|
|
22
|
+
getAllSpecificStyles({
|
|
23
|
+
configuration: { ...(theme ?? {}) },
|
|
24
|
+
componentName: CONFIRMATION_TOAST_STYLE_COMPONENT,
|
|
25
|
+
subComponentName: "",
|
|
26
|
+
outStyles,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
...outStyles.default,
|
|
31
|
+
...overrideStyle,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
2
|
+
import { getNavbarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
3
|
+
|
|
4
|
+
/** Hook calculates the height of the notification area including the status bar and navigation bar, used only for mobile */
|
|
5
|
+
export const useNotificationHeight = () => {
|
|
6
|
+
const insets = useSafeAreaInsets();
|
|
7
|
+
|
|
8
|
+
const navBarHeight = getNavbarHeight();
|
|
9
|
+
|
|
10
|
+
const statusHeight = insets.top;
|
|
11
|
+
const notificationHeight = statusHeight + navBarHeight;
|
|
12
|
+
|
|
13
|
+
return { statusHeight, notificationHeight };
|
|
14
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { notificationToastManager } from "./NotificationToastManager";
|
|
4
|
+
|
|
5
|
+
export const useNotificationToastState = () => {
|
|
6
|
+
const state = React.useSyncExternalStore(
|
|
7
|
+
notificationToastManager.subscribe,
|
|
8
|
+
notificationToastManager.getCurrentState
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
return state;
|
|
12
|
+
};
|
package/App/index.tsx
CHANGED
|
@@ -31,6 +31,7 @@ import { withActionExecutor } from "@applicaster/zapp-react-native-utils/actions
|
|
|
31
31
|
import { withScreenDataContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
32
32
|
import { LogicAggregatorContainer } from "./LogicAggregatorContainer";
|
|
33
33
|
import { LoadingOverlay } from "./LoadingOverlay";
|
|
34
|
+
import { NotificationToastRenderer } from "./NotificationToastRenderer";
|
|
34
35
|
import { ZappAppWrapper } from "./components/ZappAppWrapper";
|
|
35
36
|
|
|
36
37
|
interface AppOptions {
|
|
@@ -67,11 +68,13 @@ const App = ({
|
|
|
67
68
|
<ErrorBoundary>
|
|
68
69
|
<URLSchemeListener>
|
|
69
70
|
<SplashLoader>
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
<NotificationToastRenderer>
|
|
72
|
+
<OfflineHandler>
|
|
73
|
+
<Layout>
|
|
74
|
+
<RouteManager />
|
|
75
|
+
</Layout>
|
|
76
|
+
</OfflineHandler>
|
|
77
|
+
</NotificationToastRenderer>
|
|
75
78
|
</SplashLoader>
|
|
76
79
|
<ModalProvider />
|
|
77
80
|
</URLSchemeListener>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-core",
|
|
3
|
-
"version": "16.0.0-rc.
|
|
3
|
+
"version": "16.0.0-rc.111",
|
|
4
4
|
"description": "Core package for Applicaster's Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,13 +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/quick-brick-core-plugins": "16.0.0-rc.
|
|
33
|
-
"@applicaster/zapp-pipes-v2-client": "16.0.0-rc.
|
|
34
|
-
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.
|
|
35
|
-
"@applicaster/zapp-react-native-redux": "16.0.0-rc.
|
|
36
|
-
"@applicaster/zapp-react-native-ui-components": "16.0.0-rc.
|
|
37
|
-
"@applicaster/zapp-react-native-utils": "16.0.0-rc.
|
|
31
|
+
"@applicaster/applicaster-types": "16.0.0-rc.111",
|
|
32
|
+
"@applicaster/quick-brick-core-plugins": "16.0.0-rc.111",
|
|
33
|
+
"@applicaster/zapp-pipes-v2-client": "16.0.0-rc.111",
|
|
34
|
+
"@applicaster/zapp-react-native-bridge": "16.0.0-rc.111",
|
|
35
|
+
"@applicaster/zapp-react-native-redux": "16.0.0-rc.111",
|
|
36
|
+
"@applicaster/zapp-react-native-ui-components": "16.0.0-rc.111",
|
|
37
|
+
"@applicaster/zapp-react-native-utils": "16.0.0-rc.111",
|
|
38
38
|
"atob": "^2.1.2",
|
|
39
39
|
"axios": "^0.28.0",
|
|
40
40
|
"btoa": "^1.2.1",
|