@granite-js/react-native 0.1.34 → 1.0.0
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/CHANGELOG.md +12 -573
- package/dist/app/Granite.d.ts +2 -2
- package/dist/async-bridges.js +6 -6
- package/dist/async-bridges.mjs +2 -2
- package/dist/chunk-7GFSQK76.mjs +7 -0
- package/dist/constant-bridges.js +4 -4
- package/dist/constant-bridges.mjs +2 -2
- package/dist/image/Image.d.ts +77 -0
- package/dist/image/SvgImage.d.ts +47 -0
- package/dist/image/index.d.ts +1 -0
- package/dist/image/types.d.ts +3 -0
- package/dist/index.d.ts +4 -3
- package/dist/intersection-observer/IOFlatList.d.ts +2 -2
- package/dist/lottie/Lottie.d.ts +22 -0
- package/dist/lottie/ensureSafeLottie.d.ts +3 -0
- package/dist/lottie/index.d.ts +1 -0
- package/dist/lottie/useFetchResource.d.ts +2 -0
- package/dist/native-modules/index.d.ts +0 -1
- package/dist/native-modules/natives/GraniteBrownfieldModule.brick.d.ts +14 -0
- package/dist/router/Router.d.ts +11 -3
- package/dist/router/components/CanGoBackGuard.d.ts +2 -1
- package/dist/router/components/ErrorBoundary.d.ts +16 -0
- package/dist/router/components/StackNavigator.d.ts +40 -43
- package/dist/router/components/useRouterBackHandler.d.ts +3 -3
- package/dist/router/createRoute.d.ts +4 -1
- package/dist/router/hooks/useRouterControls.d.ts +3 -2
- package/dist/router/types/ErrorComponent.d.ts +6 -0
- package/dist/router/types/RouteScreen.d.ts +6 -0
- package/dist/router/types/index.d.ts +1 -0
- package/dist/status-bar/utils.d.ts +2 -2
- package/dist/video/Video.d.ts +5 -18
- package/package.json +22 -19
- package/src/app/Granite.tsx +2 -2
- package/src/image/Image.tsx +125 -0
- package/src/image/SvgImage.tsx +124 -0
- package/src/image/index.ts +1 -0
- package/src/image/types.ts +6 -0
- package/src/index.ts +14 -3
- package/src/intersection-observer/IOFlatList.ts +2 -2
- package/src/intersection-observer/withIO.tsx +71 -17
- package/src/lottie/Lottie.tsx +87 -0
- package/src/lottie/ensureSafeLottie.ts +15 -0
- package/src/lottie/index.ts +1 -0
- package/src/lottie/useFetchResource.ts +31 -0
- package/src/native-modules/index.ts +0 -1
- package/src/native-modules/natives/GraniteBrownfieldModule.brick.ts +15 -0
- package/src/native-modules/natives/closeView.ts +2 -2
- package/src/native-modules/natives/getSchemeUri.ts +2 -2
- package/src/router/Router.tsx +40 -12
- package/src/router/components/CanGoBackGuard.tsx +2 -3
- package/src/router/components/ErrorBoundary.tsx +38 -0
- package/src/router/components/useRouterBackHandler.tsx +3 -3
- package/src/router/createRoute.ts +6 -2
- package/src/router/hooks/useRouterControls.tsx +21 -7
- package/src/router/types/ErrorComponent.ts +8 -0
- package/src/router/types/RouteScreen.ts +6 -0
- package/src/router/types/index.ts +1 -0
- package/src/router/utils/screen.tsx +2 -0
- package/src/status-bar/utils.ts +2 -2
- package/src/types/global.ts +1 -1
- package/src/video/Video.tsx +6 -17
- package/src/visibility/VisibilityProvider.tsx +3 -3
- package/src/visibility/utils/usePrevious.tsx +1 -1
- package/dist/blur/BlurView.d.ts +0 -78
- package/dist/blur/ReactNativeBlurModule.d.ts +0 -6
- package/dist/blur/constants.d.ts +0 -1
- package/dist/blur/index.d.ts +0 -1
- package/dist/chunk-A3JGM5OI.mjs +0 -7
- package/dist/native-event-emitter/eventEmitters/index.d.ts +0 -2
- package/dist/native-event-emitter/eventEmitters/types.d.ts +0 -4
- package/dist/native-event-emitter/eventEmitters/visibilityChanged.d.ts +0 -10
- package/dist/native-event-emitter/index.d.ts +0 -1
- package/dist/native-event-emitter/nativeEventEmitter.d.ts +0 -15
- package/dist/native-modules/core/GraniteCoreModule.d.ts +0 -8
- package/dist/native-modules/natives/GraniteModule.d.ts +0 -7
- package/dist/video/instance.d.ts +0 -9
- package/src/blur/BlurView.tsx +0 -103
- package/src/blur/ReactNativeBlurModule.ts +0 -19
- package/src/blur/constants.ts +0 -3
- package/src/blur/index.ts +0 -1
- package/src/native-event-emitter/eventEmitters/index.ts +0 -3
- package/src/native-event-emitter/eventEmitters/types.ts +0 -4
- package/src/native-event-emitter/eventEmitters/visibilityChanged.ts +0 -11
- package/src/native-event-emitter/index.ts +0 -1
- package/src/native-event-emitter/nativeEventEmitter.ts +0 -18
- package/src/native-modules/core/GraniteCoreModule.ts +0 -9
- package/src/native-modules/natives/GraniteModule.ts +0 -8
- package/src/video/instance.tsx +0 -28
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraniteModule } from './
|
|
1
|
+
import { GraniteModule } from './GraniteBrownfieldModule.brick';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
@@ -21,5 +21,5 @@ import { GraniteModule } from './GraniteModule';
|
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
export async function closeView() {
|
|
24
|
-
return GraniteModule
|
|
24
|
+
return GraniteModule?.closeView();
|
|
25
25
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraniteModule } from './
|
|
1
|
+
import { GraniteModule } from './GraniteBrownfieldModule.brick';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
@@ -23,5 +23,5 @@ import { GraniteModule } from './GraniteModule';
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
export function getSchemeUri() {
|
|
26
|
-
return GraniteModule.schemeUri;
|
|
26
|
+
return GraniteModule.getConstants().schemeUri;
|
|
27
27
|
}
|
package/src/router/Router.tsx
CHANGED
|
@@ -7,16 +7,24 @@ import {
|
|
|
7
7
|
RouteProp,
|
|
8
8
|
} from '@granite-js/native/@react-navigation/native';
|
|
9
9
|
import { NativeStackNavigationOptions } from '@granite-js/native/@react-navigation/native-stack';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
ComponentProps,
|
|
12
|
+
ComponentType,
|
|
13
|
+
Fragment,
|
|
14
|
+
PropsWithChildren,
|
|
15
|
+
ReactElement,
|
|
16
|
+
useCallback,
|
|
17
|
+
useMemo,
|
|
18
|
+
useState,
|
|
19
|
+
} from 'react';
|
|
11
20
|
import { InitialProps } from '..';
|
|
12
21
|
import { closeView } from '../native-modules';
|
|
13
22
|
import { BackButton } from './components/BackButton';
|
|
14
23
|
import { CanGoBackGuard } from './components/CanGoBackGuard';
|
|
15
24
|
import { StackNavigator } from './components/StackNavigator';
|
|
16
25
|
import { useInternalRouterBackHandler } from './components/useRouterBackHandler';
|
|
17
|
-
import { useInitialRouteName } from './hooks/useInitialRouteName';
|
|
18
26
|
import { useRouterControls, type RouterControlsConfig } from './hooks/useRouterControls';
|
|
19
|
-
import { RequireContext } from './types';
|
|
27
|
+
import type { ErrorComponent, RequireContext } from './types';
|
|
20
28
|
import { BASE_STACK_NAVIGATOR_STYLE } from './types/screen-option';
|
|
21
29
|
|
|
22
30
|
/**
|
|
@@ -68,7 +76,7 @@ interface StackNavigatorProps {
|
|
|
68
76
|
* @description
|
|
69
77
|
* You can create and pass a NavigationContainerRef from @react-navigation/native externally. This allows external control of the router.
|
|
70
78
|
*/
|
|
71
|
-
navigationContainerRef?: NavigationContainerRefWithCurrent<
|
|
79
|
+
navigationContainerRef?: NavigationContainerRefWithCurrent<never>;
|
|
72
80
|
/**
|
|
73
81
|
* @name defaultScreenOption
|
|
74
82
|
* @description
|
|
@@ -83,6 +91,12 @@ interface StackNavigatorProps {
|
|
|
83
91
|
* Container component that wraps each Screen component.
|
|
84
92
|
*/
|
|
85
93
|
screenContainer?: ComponentType<PropsWithChildren<any>>;
|
|
94
|
+
/**
|
|
95
|
+
* @name defaultErrorComponent
|
|
96
|
+
* @description
|
|
97
|
+
* Error boundary component used when a route does not provide its own error component.
|
|
98
|
+
*/
|
|
99
|
+
defaultErrorComponent?: ErrorComponent;
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
type NavigationContainerProps = Pick<
|
|
@@ -101,11 +115,12 @@ type NavigationContainerProps = Pick<
|
|
|
101
115
|
*
|
|
102
116
|
* @param {string} prefix Prefix to use when the scheme is executed. For example, to enter 'scheme://my-service/intro', you need to set 'scheme://my-service' as the prefix.
|
|
103
117
|
* @param {RequireContext} context Object containing information about screens for file-based routing.
|
|
104
|
-
* @param {NavigationContainerRefWithCurrent<
|
|
118
|
+
* @param {NavigationContainerRefWithCurrent<never>} [navigationContainerRef] You can create and pass a NavigationContainerRef from @react-navigation/native externally. This allows external control of the router.
|
|
105
119
|
* @param {NativeStackNavigationOptions | ((props: { route: RouteProp<ParamListBase>; navigation: any }) => NativeStackNavigationOptions)} [defaultScreenOption] Default options for screens. You can set options to be applied commonly to screens, such as title or headerStyle.
|
|
106
120
|
* @param {boolean} [canGoBack=true] Whether navigation back is possible. Default is true, and when set to true, you can use the back gesture or back button from @react-navigation/native.
|
|
107
121
|
* @param {() => void} [onBack] Callback function called when the user presses the back button or uses the back gesture. For example, you can set it to log when the user presses the back button.
|
|
108
122
|
* @param {ComponentType<{ children: ReactNode }>} [container=Fragment] Container component that wraps the Navigator from @react-navigation/native.
|
|
123
|
+
* @param {ComponentType<{ error: unknown; reset: () => void }>} [defaultErrorComponent] Default error component for screens without a route-specific error component.
|
|
109
124
|
* @param {NavigationContainerProps} [navigationContainerProps] - You can set props to be passed to NavigationContainer from @react-navigation/native.
|
|
110
125
|
*
|
|
111
126
|
* @returns {ReactElement} - Returns the router component.
|
|
@@ -130,21 +145,22 @@ export function Router({
|
|
|
130
145
|
navigationContainerRef,
|
|
131
146
|
defaultScreenOption,
|
|
132
147
|
screenContainer,
|
|
148
|
+
defaultErrorComponent,
|
|
133
149
|
// Public props (StackNavigator)
|
|
134
150
|
setIosSwipeGestureEnabled,
|
|
135
151
|
getInitialUrl,
|
|
136
152
|
...navigationContainerProps
|
|
137
153
|
}: InternalRouterProps & RouterProps): ReactElement {
|
|
138
|
-
const initialRouteName = useInitialRouteName({ prefix, initialScheme });
|
|
139
154
|
const { Screens, linkingOptions } = useRouterControls({
|
|
140
155
|
prefix,
|
|
141
156
|
context,
|
|
142
157
|
screenContainer,
|
|
143
158
|
initialScheme,
|
|
144
159
|
getInitialUrl,
|
|
160
|
+
defaultErrorComponent,
|
|
145
161
|
});
|
|
146
162
|
|
|
147
|
-
const ref = useMemo(() => navigationContainerRef ?? createNavigationContainerRef<
|
|
163
|
+
const ref = useMemo(() => navigationContainerRef ?? createNavigationContainerRef<never>(), [navigationContainerRef]);
|
|
148
164
|
|
|
149
165
|
const { handler, canGoBack, onBack } = useInternalRouterBackHandler({
|
|
150
166
|
navigationContainerRef: ref,
|
|
@@ -166,13 +182,25 @@ export function Router({
|
|
|
166
182
|
[canGoBack, defaultScreenOption, headerLeft]
|
|
167
183
|
);
|
|
168
184
|
|
|
185
|
+
const [isInitialScreen, setIsInitialScreen] = useState(true);
|
|
186
|
+
|
|
169
187
|
return (
|
|
170
|
-
<NavigationContainer
|
|
171
|
-
|
|
188
|
+
<NavigationContainer
|
|
189
|
+
onStateChange={(state) => {
|
|
190
|
+
setIsInitialScreen(state ? state?.index === 0 : true);
|
|
191
|
+
}}
|
|
192
|
+
ref={ref}
|
|
193
|
+
{...navigationContainerProps}
|
|
194
|
+
linking={linkingOptions}
|
|
195
|
+
>
|
|
196
|
+
<CanGoBackGuard
|
|
197
|
+
canGoBack={canGoBack}
|
|
198
|
+
isInitialScreen={isInitialScreen}
|
|
199
|
+
onBack={onBack}
|
|
200
|
+
setIosSwipeGestureEnabled={setIosSwipeGestureEnabled}
|
|
201
|
+
>
|
|
172
202
|
<Container {...initialProps}>
|
|
173
|
-
<StackNavigator.Navigator
|
|
174
|
-
{Screens}
|
|
175
|
-
</StackNavigator.Navigator>
|
|
203
|
+
<StackNavigator.Navigator screenOptions={screenOptions}>{Screens}</StackNavigator.Navigator>
|
|
176
204
|
</Container>
|
|
177
205
|
</CanGoBackGuard>
|
|
178
206
|
</NavigationContainer>
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { ReactNode, useEffect } from 'react';
|
|
2
2
|
import { BackHandler } from 'react-native';
|
|
3
|
-
import { useIsInitialScreen } from '../hooks/useIsInitialScreen';
|
|
4
3
|
|
|
5
4
|
export function CanGoBackGuard({
|
|
6
5
|
children,
|
|
7
6
|
canGoBack,
|
|
8
7
|
onBack,
|
|
8
|
+
isInitialScreen,
|
|
9
9
|
setIosSwipeGestureEnabled,
|
|
10
10
|
}: {
|
|
11
11
|
canGoBack: boolean;
|
|
12
|
+
isInitialScreen: boolean;
|
|
12
13
|
children: ReactNode;
|
|
13
14
|
onBack?: () => void;
|
|
14
15
|
setIosSwipeGestureEnabled?: ({ isEnabled }: { isEnabled: boolean }) => void;
|
|
15
16
|
}) {
|
|
16
|
-
const isInitialScreen = useIsInitialScreen();
|
|
17
|
-
|
|
18
17
|
const shouldBlockGoingBack = !canGoBack;
|
|
19
18
|
|
|
20
19
|
useEffect(() => {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Component, type ReactNode } from 'react';
|
|
2
|
+
import type { ErrorComponent } from '../types';
|
|
3
|
+
|
|
4
|
+
interface ErrorBoundaryProps {
|
|
5
|
+
fallback: ErrorComponent;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ErrorBoundaryState {
|
|
10
|
+
error: unknown | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
14
|
+
state: ErrorBoundaryState = {
|
|
15
|
+
error: null,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
static getDerivedStateFromError(error: unknown): ErrorBoundaryState {
|
|
19
|
+
return { error };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
render() {
|
|
23
|
+
if (this.state.error != null) {
|
|
24
|
+
const Fallback = this.props.fallback;
|
|
25
|
+
return <Fallback error={this.state.error} reset={this.reset} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return this.props.children;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private reset = () => {
|
|
32
|
+
if (this.state.error == null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.setState({ error: null });
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -9,7 +9,7 @@ import { useBackEventContext } from '../../use-back-event';
|
|
|
9
9
|
* @description
|
|
10
10
|
* A hook that provides a handler for handling back navigation actions. This can be used when you need to close a view directly when the back button is pressed in modals or independent screens where there's no navigation stack. This hook uses `NavigationContainerRef` from `@react-navigation/native` to navigate to the previous screen if there's a remaining navigation stack, or executes the user-defined `onClose` function if the stack is empty.
|
|
11
11
|
*
|
|
12
|
-
* @param {NavigationContainerRefWithCurrent<
|
|
12
|
+
* @param {NavigationContainerRefWithCurrent<never>} navigationContainerRef - A `NavigationContainerRef` that can reference the current navigation state. Used when executing back navigation actions.
|
|
13
13
|
* @param {() => void} [onClose] - A function to execute when the navigation stack is empty. For example, you can pass a function that closes a React Native View.
|
|
14
14
|
*
|
|
15
15
|
* @returns {{ handler: () => void }} A handler function that can be used in back buttons or similar components.
|
|
@@ -48,7 +48,7 @@ export function useRouterBackHandler({
|
|
|
48
48
|
navigationContainerRef,
|
|
49
49
|
onClose,
|
|
50
50
|
}: {
|
|
51
|
-
navigationContainerRef: NavigationContainerRefWithCurrent<
|
|
51
|
+
navigationContainerRef: NavigationContainerRefWithCurrent<never>;
|
|
52
52
|
onClose?: () => void;
|
|
53
53
|
}) {
|
|
54
54
|
const { handler } = useInternalRouterBackHandler({ navigationContainerRef, onClose });
|
|
@@ -60,7 +60,7 @@ export function useInternalRouterBackHandler({
|
|
|
60
60
|
navigationContainerRef,
|
|
61
61
|
onClose,
|
|
62
62
|
}: {
|
|
63
|
-
navigationContainerRef: NavigationContainerRefWithCurrent<
|
|
63
|
+
navigationContainerRef: NavigationContainerRefWithCurrent<never>;
|
|
64
64
|
onClose?: () => void;
|
|
65
65
|
}) {
|
|
66
66
|
const { hasBackEvent, onBack } = useBackEventContext();
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
11
11
|
import { useMemo } from 'react';
|
|
12
12
|
import { RESERVED_PATHS } from './constants';
|
|
13
|
+
import type { ErrorComponent } from './types';
|
|
13
14
|
import { defaultParserParams } from './utils/defaultParserParams';
|
|
14
15
|
import { type InferOutput, type InferInput } from './utils/standardSchema';
|
|
15
16
|
import { validateRouteParams } from './utils/validateRouteParams';
|
|
@@ -18,6 +19,7 @@ export interface RouteOptions<T extends Readonly<object | undefined>> {
|
|
|
18
19
|
parserParams?: (params: Record<string, unknown>) => Record<string, unknown>;
|
|
19
20
|
validateParams?: ((params: Readonly<object | undefined>) => T) | StandardSchemaV1<any, T>;
|
|
20
21
|
component: React.FC<any>;
|
|
22
|
+
errorComponent?: ErrorComponent;
|
|
21
23
|
screenOptions?: NativeStackNavigationOptions | ((context: { params: T }) => NativeStackNavigationOptions);
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -49,8 +51,9 @@ export type RouteHooksOptions<TScreen extends keyof RegisterScreen> =
|
|
|
49
51
|
export const routeMap = new Map<
|
|
50
52
|
keyof RegisterScreenInput,
|
|
51
53
|
{
|
|
52
|
-
options: Omit<RouteOptions<any>, 'component' | 'screenOptions'>;
|
|
54
|
+
options: Omit<RouteOptions<any>, 'component' | 'screenOptions' | 'errorComponent'>;
|
|
53
55
|
component: React.FC<any>;
|
|
56
|
+
errorComponent?: ErrorComponent;
|
|
54
57
|
screenOptions?: NativeStackNavigationOptions | ((context: { params: any }) => NativeStackNavigationOptions);
|
|
55
58
|
}
|
|
56
59
|
>();
|
|
@@ -193,10 +196,11 @@ export function createRoute<T extends Readonly<object | undefined>>(
|
|
|
193
196
|
|
|
194
197
|
// Implementation
|
|
195
198
|
export function createRoute(path: keyof RegisterScreenInput, options: RouteOptions<any>) {
|
|
196
|
-
const { component, screenOptions, ...restOptions } = options;
|
|
199
|
+
const { component, screenOptions, errorComponent, ...restOptions } = options;
|
|
197
200
|
routeMap.set(path, {
|
|
198
201
|
options: restOptions,
|
|
199
202
|
component,
|
|
203
|
+
errorComponent,
|
|
200
204
|
screenOptions: screenOptions,
|
|
201
205
|
});
|
|
202
206
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { NavigationContainer } from '@granite-js/native/@react-navigation/native';
|
|
2
2
|
import { useMemo, type ComponentProps, type ComponentType, type PropsWithChildren } from 'react';
|
|
3
|
+
import { ErrorBoundary } from '../components/ErrorBoundary';
|
|
3
4
|
import { StackNavigator } from '../components/StackNavigator';
|
|
4
5
|
import { RESERVED_KEYWORDS } from '../constants';
|
|
5
|
-
import { RequireContext } from '../types
|
|
6
|
+
import type { ErrorComponent, RequireContext } from '../types';
|
|
6
7
|
import { getRouteScreens, getScreenPathMapConfig } from '../utils';
|
|
7
8
|
import { createParentRouteScreenMap } from '../utils/createParentRouteScreenMap';
|
|
8
9
|
import { mergeParentLayoutScreen } from '../utils/mergeParentLayoutScreen';
|
|
@@ -16,6 +17,7 @@ export interface RouterControlsConfig {
|
|
|
16
17
|
context: RequireContext;
|
|
17
18
|
getInitialUrl?: (initialScheme: string) => string | undefined | Promise<string | undefined>;
|
|
18
19
|
screenContainer?: ComponentType<PropsWithChildren<any>>;
|
|
20
|
+
defaultErrorComponent?: ErrorComponent;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export function useRouterControls({
|
|
@@ -24,6 +26,7 @@ export function useRouterControls({
|
|
|
24
26
|
screenContainer: ScreenContainer,
|
|
25
27
|
getInitialUrl = defaultGetInitialUrl,
|
|
26
28
|
initialScheme,
|
|
29
|
+
defaultErrorComponent,
|
|
27
30
|
}: RouterControlsConfig) {
|
|
28
31
|
const routeScreens = useMemo(() => getRouteScreens(context), [context]);
|
|
29
32
|
|
|
@@ -37,16 +40,27 @@ export function useRouterControls({
|
|
|
37
40
|
|
|
38
41
|
const Screens = useMemo(() => {
|
|
39
42
|
return registerScreens.map((routeScreen) => {
|
|
43
|
+
const RouteErrorComponent = routeScreen.errorComponent;
|
|
40
44
|
const Layout = mergeParentLayoutScreen(layoutScreenMap, routeScreen.path);
|
|
41
45
|
|
|
42
46
|
const Component = function Component() {
|
|
43
|
-
const
|
|
44
|
-
|
|
47
|
+
const routeElement =
|
|
48
|
+
RouteErrorComponent == null ? (
|
|
45
49
|
<routeScreen.component />
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
) : (
|
|
51
|
+
<ErrorBoundary fallback={RouteErrorComponent}>
|
|
52
|
+
<routeScreen.component />
|
|
53
|
+
</ErrorBoundary>
|
|
54
|
+
);
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
const element = <Layout>{routeElement}</Layout>;
|
|
57
|
+
const wrappedElement = ScreenContainer == null ? element : <ScreenContainer>{element}</ScreenContainer>;
|
|
58
|
+
|
|
59
|
+
if (defaultErrorComponent == null) {
|
|
60
|
+
return wrappedElement;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return <ErrorBoundary fallback={defaultErrorComponent}>{wrappedElement}</ErrorBoundary>;
|
|
50
64
|
};
|
|
51
65
|
|
|
52
66
|
const routePath = routeScreen.path;
|
|
@@ -54,7 +68,7 @@ export function useRouterControls({
|
|
|
54
68
|
|
|
55
69
|
return <StackNavigator.Screen key={routePath} name={routePath} component={Component} options={options} />;
|
|
56
70
|
});
|
|
57
|
-
}, [registerScreens, layoutScreenMap, ScreenContainer]);
|
|
71
|
+
}, [registerScreens, layoutScreenMap, ScreenContainer, defaultErrorComponent]);
|
|
58
72
|
|
|
59
73
|
const linkingOptions: NavigationContainerProps['linking'] = useMemo(() => {
|
|
60
74
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NativeStackNavigationOptions } from '@granite-js/native/@react-navigation/native-stack';
|
|
2
|
+
import type { ErrorComponent } from './ErrorComponent';
|
|
2
3
|
import { Screen } from './Screen';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -15,6 +16,11 @@ export interface RouteScreen {
|
|
|
15
16
|
* @description Screen component
|
|
16
17
|
*/
|
|
17
18
|
component: Screen;
|
|
19
|
+
/**
|
|
20
|
+
* @name errorComponent
|
|
21
|
+
* @description Error boundary component for this screen
|
|
22
|
+
*/
|
|
23
|
+
errorComponent?: ErrorComponent;
|
|
18
24
|
/**
|
|
19
25
|
* @name screenOptions
|
|
20
26
|
* @description Screen options for React Navigation (can be static or a function that receives route params)
|
|
@@ -36,6 +36,7 @@ export function getRouteScreens(context: RequireContext): RouteScreen[] {
|
|
|
36
36
|
|
|
37
37
|
// Retrieve route configuration from routeMap
|
|
38
38
|
const routeMapEntry = routeMap.get(context(key)?.Route?._path);
|
|
39
|
+
const errorComponent = routeMapEntry?.errorComponent;
|
|
39
40
|
|
|
40
41
|
// Get screenOptions from routeMap or component (routeMap takes priority)
|
|
41
42
|
const rawScreenOptions = routeMapEntry?.screenOptions ?? component.screenOptions;
|
|
@@ -64,6 +65,7 @@ export function getRouteScreens(context: RequireContext): RouteScreen[] {
|
|
|
64
65
|
return {
|
|
65
66
|
path,
|
|
66
67
|
component,
|
|
68
|
+
errorComponent,
|
|
67
69
|
screenOptions,
|
|
68
70
|
};
|
|
69
71
|
});
|
package/src/status-bar/utils.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { ColorSchemeName } from 'react-native';
|
|
1
2
|
import type { StatusBarStyle } from './types';
|
|
2
|
-
import type { ColorPreference } from '../initial-props';
|
|
3
3
|
|
|
4
4
|
export function toStatusBarContentStyle(
|
|
5
5
|
statusBarStyle: StatusBarStyle = 'auto',
|
|
6
|
-
colorPreference:
|
|
6
|
+
colorPreference: ColorSchemeName = 'light'
|
|
7
7
|
): 'light-content' | 'dark-content' {
|
|
8
8
|
const resolvedStyle = (() => {
|
|
9
9
|
switch (statusBarStyle) {
|
package/src/types/global.ts
CHANGED
package/src/video/Video.tsx
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import VideoBase, { type VideoRef } from '@granite-js/video';
|
|
2
2
|
import { ComponentProps, forwardRef, useMemo, useState } from 'react';
|
|
3
3
|
import { Animated, Platform } from 'react-native';
|
|
4
|
-
import * as instance from './instance';
|
|
5
4
|
import { useVisibility } from '../visibility';
|
|
6
5
|
|
|
7
|
-
const AnimatedRNVideo = Animated.createAnimatedComponent(
|
|
6
|
+
const AnimatedRNVideo = Animated.createAnimatedComponent(VideoBase);
|
|
8
7
|
|
|
9
8
|
type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
|
|
10
9
|
|
|
@@ -15,13 +14,8 @@ type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
|
|
|
15
14
|
* @description
|
|
16
15
|
* The Video component implements audio focus control logic to prevent the sandbox app from stopping music playing in other apps. It automatically plays or pauses based on the app's state. For example, when the app transitions to the background, the video automatically pauses.
|
|
17
16
|
*
|
|
18
|
-
* ::: warning
|
|
19
|
-
* The Video component uses [react-native-video version (6.0.0-alpha.6)](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6). Therefore, some types or features may not be compatible with the latest version.
|
|
20
|
-
* :::
|
|
21
|
-
*
|
|
22
17
|
* @property {boolean} [isAvailable] Value to check if the `Video` component can be used. You can check this value to determine if the user can render the video or if video functionality is unavailable due to environmental constraints (e.g., network connection issues, unsupported devices). If this value is `false`, you should handle it by not rendering the video or providing alternative content.
|
|
23
18
|
*
|
|
24
|
-
* @param {VideoProperties} [props] Properties provided by [`react-native-video`](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6).
|
|
25
19
|
* @param {string} [props.source.uri] Source of the video to play. Can be set to a file path or URL.
|
|
26
20
|
* @param {boolean} [props.muted=false] Controls the mute state of the video. If `true`, the video's audio is muted; if `false`, the audio plays. Default is `false`.
|
|
27
21
|
* @param {boolean} [props.paused=false] Property to control video playback. If `true`, the video is paused; if `false`, the video plays. Default is `false`, and it autoplays.
|
|
@@ -30,11 +24,6 @@ type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
|
|
|
30
24
|
*
|
|
31
25
|
* @returns {JSX.Element} Returns a JSX element that renders the video. Uses `Animated` to provide smooth animation effects during video playback.
|
|
32
26
|
*
|
|
33
|
-
* @see [react-native-video] https://github.com/react-native-video/react-native-video
|
|
34
|
-
* For detailed properties of the video component, please refer to the official documentation.
|
|
35
|
-
* @see [react-native-video-6.0.0] https://github.com/TheWidlarzGroup/react-native-video/releases/tag/v6.0.0
|
|
36
|
-
* This is the source code of the version currently installed in the sandbox app.
|
|
37
|
-
*
|
|
38
27
|
* @example
|
|
39
28
|
*
|
|
40
29
|
* ### Video Autoplay Example
|
|
@@ -62,7 +51,7 @@ type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
|
|
|
62
51
|
* }
|
|
63
52
|
* ```
|
|
64
53
|
*/
|
|
65
|
-
const VideoImpl = forwardRef<VideoRef,
|
|
54
|
+
const VideoImpl = forwardRef<VideoRef, VideoProps>((props, ref) => {
|
|
66
55
|
const [isFocused, setIsFocused] = useState(props.muted || props.paused);
|
|
67
56
|
const visible = useVisibility();
|
|
68
57
|
|
|
@@ -77,11 +66,11 @@ const VideoImpl = forwardRef<VideoRef, instance.VideoNativeProps>((props, ref) =
|
|
|
77
66
|
|
|
78
67
|
return (
|
|
79
68
|
<AnimatedRNVideo
|
|
80
|
-
ref={ref
|
|
69
|
+
ref={ref}
|
|
81
70
|
progressUpdateInterval={16}
|
|
82
71
|
disableFocus={Platform.OS === 'ios' ? false : disableFocus}
|
|
83
72
|
playWhenInactive
|
|
84
|
-
onAudioFocusChanged={(event
|
|
73
|
+
onAudioFocusChanged={(event) => {
|
|
85
74
|
setIsFocused(event.hasAudioFocus);
|
|
86
75
|
props.onAudioFocusChanged?.(event);
|
|
87
76
|
}}
|
|
@@ -94,7 +83,7 @@ const VideoImpl = forwardRef<VideoRef, instance.VideoNativeProps>((props, ref) =
|
|
|
94
83
|
});
|
|
95
84
|
|
|
96
85
|
export const Video = Object.defineProperty(VideoImpl, 'isAvailable', {
|
|
97
|
-
get: () =>
|
|
86
|
+
get: () => VideoBase.isAvailable,
|
|
98
87
|
configurable: false,
|
|
99
88
|
}) as typeof VideoImpl & { isAvailable: boolean };
|
|
100
89
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactElement, ReactNode, useEffect, useState } from 'react';
|
|
2
2
|
import { AppStateProvider } from './useIsAppForeground';
|
|
3
3
|
import { VisibilityChangedProvider } from './useVisibilityChanged';
|
|
4
|
-
import {
|
|
4
|
+
import { GraniteModule } from '../native-modules/natives/GraniteBrownfieldModule.brick';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
isVisible: boolean;
|
|
@@ -33,8 +33,8 @@ export function VisibilityProvider({ isVisible, children }: Props): ReactElement
|
|
|
33
33
|
const [visible, setVisible] = useState(isVisible);
|
|
34
34
|
|
|
35
35
|
useEffect(() => {
|
|
36
|
-
const subscription =
|
|
37
|
-
setVisible(
|
|
36
|
+
const subscription = GraniteModule.onVisibilityChanged(({ visible }) => {
|
|
37
|
+
setVisible(visible);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
return () => {
|
package/dist/blur/BlurView.d.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import type { BlurViewProps as InternalBlurViewProps } from '@granite-js/native/@react-native-community/blur';
|
|
2
|
-
import { ViewProps } from 'react-native';
|
|
3
|
-
export type BlurType = InternalBlurViewProps['blurType'];
|
|
4
|
-
export interface BlurViewProps extends ViewProps {
|
|
5
|
-
blurType?: BlurType;
|
|
6
|
-
blurAmount?: number;
|
|
7
|
-
vibrancyEffect?: boolean;
|
|
8
|
-
reducedTransparencyFallbackColor?: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* @public
|
|
12
|
-
* @category UI
|
|
13
|
-
* @name BlurView
|
|
14
|
-
* @description
|
|
15
|
-
* `BlurView` adds a blurred background effect, primarily on iOS. It creates a visual blur on the background view.
|
|
16
|
-
*
|
|
17
|
-
* This component is supported only on iOS. On Android, it simply renders a regular [`View`](https://reactnative.dev/docs/0.72/view) without any blur effect.
|
|
18
|
-
*
|
|
19
|
-
* You can control the blur intensity and optionally enable the [vibrancy effect](https://developer.apple.com/documentation/uikit/uivibrancyeffect?language=objc), which enhances the visual impact of content displayed over a blurred background.
|
|
20
|
-
*
|
|
21
|
-
* If blur is not supported or doesn't render properly, you can use the `reducedTransparencyFallbackColor` prop to set a fallback background color.
|
|
22
|
-
*
|
|
23
|
-
* Use the `isSupported` property to check whether the current device supports blur. Blur is available on iOS from version 5.126.0 and not supported on Android.
|
|
24
|
-
*
|
|
25
|
-
* @param {BlurViewProps} [props] The props you can pass to `BlurView`. It extends `react-native`'s `ViewProps`, so you can use layout and style properties. The props align with those of [`@react-native-community/blur`](https://github.com/Kureev/react-native-blur/tree/v4.3.2?tab=readme-ov-file#blurview).
|
|
26
|
-
* @param {BlurType} [props.blurType] Type of blur to apply, such as `light`, `dark`, or `extraDark`.
|
|
27
|
-
* @param {number} [props.blurAmount=10] Intensity of the blur effect. Higher values make the blur stronger. Accepts values from `0` to `100`. Default is `10`.
|
|
28
|
-
* @param {boolean} [props.vibrancyEffect=false] Enables the vibrancy effect. This effect enhances content displayed on top of the blur. Only supported on iOS. Default is `false`.
|
|
29
|
-
* @param {string} [props.reducedTransparencyFallbackColor] Fallback background color used when blur cannot be applied due to system settings or device limitations.
|
|
30
|
-
*
|
|
31
|
-
* @returns {JSX.Element} On iOS, returns a blurred `BlurView` or `VibrancyView` component. On Android, returns a regular `View` without blur.
|
|
32
|
-
*
|
|
33
|
-
* ::: warning Note
|
|
34
|
-
* `BlurView` is only supported on iOS. On Android, it renders a regular `View` without any blur effect.
|
|
35
|
-
* :::
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
*
|
|
39
|
-
* ### Blurring background behind a text
|
|
40
|
-
*
|
|
41
|
-
* ```tsx
|
|
42
|
-
* import { BlurView } from '@granite-js/react-native';
|
|
43
|
-
* import { View, Text, StyleSheet } from 'react-native';
|
|
44
|
-
*
|
|
45
|
-
* export function BlurViewExample() {
|
|
46
|
-
* return (
|
|
47
|
-
* <View style={styles.container}>
|
|
48
|
-
* <Text style={styles.absolute}>Blurred Text</Text>
|
|
49
|
-
* <BlurView style={styles.absolute} blurType="light" blurAmount={1} />
|
|
50
|
-
* <Text>Non Blurred Text</Text>
|
|
51
|
-
* </View>
|
|
52
|
-
* );
|
|
53
|
-
* }
|
|
54
|
-
*
|
|
55
|
-
* const styles = StyleSheet.create({
|
|
56
|
-
* container: {
|
|
57
|
-
* justifyContent: 'center',
|
|
58
|
-
* alignItems: 'center',
|
|
59
|
-
* width: '100%',
|
|
60
|
-
* height: 300,
|
|
61
|
-
* },
|
|
62
|
-
* absolute: {
|
|
63
|
-
* position: 'absolute',
|
|
64
|
-
* top: 0,
|
|
65
|
-
* left: 0,
|
|
66
|
-
* bottom: 0,
|
|
67
|
-
* right: 0,
|
|
68
|
-
* },
|
|
69
|
-
* });
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* @see [iOS Vibrancy Effect Documentation](https://developer.apple.com/documentation/uikit/uivibrancyeffect)
|
|
73
|
-
* @see [Zeddios Blog Explanation](https://zeddios.tistory.com/1140)
|
|
74
|
-
*/
|
|
75
|
-
export declare function BlurView({ blurType, blurAmount, reducedTransparencyFallbackColor, vibrancyEffect, ...viewProps }: BlurViewProps): import("react/jsx-runtime").JSX.Element;
|
|
76
|
-
export declare namespace BlurView {
|
|
77
|
-
var isSupported: boolean;
|
|
78
|
-
}
|
package/dist/blur/constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const isBlurNativeModuleSupported: boolean;
|
package/dist/blur/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './BlurView';
|
package/dist/chunk-A3JGM5OI.mjs
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { EventEmitterSchema } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* @name VisibilityChangedEventEmitter
|
|
4
|
-
* @kind typedef
|
|
5
|
-
* @platform iOS
|
|
6
|
-
* @description
|
|
7
|
-
* Emits an event when the visibility state of the app changes.
|
|
8
|
-
* Only available on iOS.
|
|
9
|
-
*/
|
|
10
|
-
export type VisibilityChangedEventEmitter = EventEmitterSchema<'visibilityChanged', [boolean]>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './nativeEventEmitter';
|