@granite-js/react-native 0.1.0 → 0.1.2

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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # @granite-js/react-native
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - e1384cf: re-add previously excluded native module packages
8
+ - Updated dependencies [e1384cf]
9
+ - @granite-js/lottie@0.1.2
10
+ - @granite-js/native@0.1.2
11
+ - @granite-js/image@0.1.2
12
+ - @granite-js/jest@0.1.2
13
+ - @granite-js/style-utils@0.1.2
14
+ - @granite-js/cli@0.1.2
15
+ - @granite-js/mpack@0.1.2
16
+
17
+ ## 0.1.1
18
+
19
+ ### Patch Changes
20
+
21
+ - d675415: Improve scaffolding to provide a better showcase UI
22
+ - 10a5f3f: empty
23
+ - Updated dependencies [d675415]
24
+ - Updated dependencies [10a5f3f]
25
+ - @granite-js/style-utils@0.1.1
26
+ - @granite-js/native@0.1.1
27
+ - @granite-js/image@0.1.1
28
+ - @granite-js/mpack@0.1.1
29
+ - @granite-js/jest@0.1.1
30
+ - @granite-js/cli@0.1.1
31
+
3
32
  ## 0.1.0
4
33
 
5
34
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import './types/global';
2
2
  export { Granite } from './app';
3
3
  export * from '@granite-js/style-utils';
4
4
  export * from '@granite-js/image';
5
+ export * from '@granite-js/lottie';
5
6
  export * from './dev-entrypoint';
6
7
  export * from './native-modules/natives';
7
8
  export * from './visibility';
@@ -13,5 +14,6 @@ export * from './scroll-view-inertial-background';
13
14
  export * from './react';
14
15
  export * from './router/createRoute';
15
16
  export * from './event';
17
+ export * from './video';
16
18
  export type { InitialProps, ColorPreference } from './initial-props';
17
19
  export type { GraniteProps } from './app';
@@ -8,14 +8,6 @@
8
8
  * @typedef {'light' | 'dark'} ColorPreference
9
9
  */
10
10
  export type ColorPreference = 'light' | 'dark';
11
- /**
12
- * @name NetworkStatus
13
- * @description
14
- * Type representing the network status.
15
- *
16
- * @typedef {'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE'} NetworkStatus
17
- */
18
- type NetworkStatus = 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE';
19
11
  /**
20
12
  * @category Types
21
13
  * @name BaseInitialProps
@@ -24,18 +16,12 @@ type NetworkStatus = 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE';
24
16
  *
25
17
  * @interface
26
18
  * @property {'ios' | 'android'} platform - Platform type
27
- * @property {string} appVersion - App version
28
19
  * @property {ColorPreference} initialColorPreference - Initial color
29
- * @property {NetworkStatus} networkStatus - Network status
30
- * @property {number} loadingStartTs - Timestamp when ReactNativeView started rendering in native
31
20
  * @property {string} [scheme] - Executed scheme
32
21
  */
33
22
  type BaseInitialProps = {
34
23
  platform: 'ios' | 'android';
35
- appVersion: string;
36
24
  initialColorPreference: ColorPreference;
37
- networkStatus: NetworkStatus;
38
- loadingStartTs: number;
39
25
  scheme?: string;
40
26
  };
41
27
  /**
@@ -47,13 +33,9 @@ type BaseInitialProps = {
47
33
  * @interface
48
34
  * @augments BaseInitialProps
49
35
  * @property {'android'} platform - Platform name (Android)
50
- * @property {string} initialFontScale - Font scale set on the device
51
- * @property {string} distributionGroup - Distribution group
52
36
  */
53
37
  export type AndroidInitialProps = BaseInitialProps & {
54
38
  platform: 'android';
55
- initialFontScale: string;
56
- distributionGroup: string;
57
39
  };
58
40
  /**
59
41
  * @category Types
@@ -64,23 +46,10 @@ export type AndroidInitialProps = BaseInitialProps & {
64
46
  * @interface
65
47
  * @augments BaseInitialProps
66
48
  * @property {'ios'} platform - Platform (iOS)
67
- * @property {IOSFontSizeType} initialFontSize - Initial font size
68
- * @property {boolean} isVisible - Visibility status
69
49
  */
70
50
  export type IOSInitialProps = BaseInitialProps & {
71
51
  platform: 'ios';
72
- initialFontSize: IOSFontSizeType;
73
- isVisible: boolean;
74
52
  };
75
- /**
76
- * @category Types
77
- * @name IOSFontSizeType
78
- * @description
79
- * Type representing iOS font size type.
80
- *
81
- * @typedef {'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxLarge' | 'xxxLarge' | 'A11y_Medium' | 'A11y_Large' | 'A11y_xLarge' | 'A11y_xxLarge' | 'A11y_xxxLarge'} IOSFontSizeType
82
- */
83
- type IOSFontSizeType = 'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxLarge' | 'xxxLarge' | 'A11y_Medium' | 'A11y_Large' | 'A11y_xLarge' | 'A11y_xxLarge' | 'A11y_xxxLarge';
84
53
  /**
85
54
  * @public
86
55
  * @category Core
@@ -93,11 +62,7 @@ type IOSFontSizeType = 'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxL
93
62
  *
94
63
  * @property {'ios' | 'android'} platform - The platform on which the app is currently running. Has a value of either `ios` or `android`.
95
64
  * @property {ColorPreference} initialColorPreference - The initial color theme. Represents the color theme set by the user.
96
- * @property {NetworkStatus} networkStatus - The current device's network connection status and connected network.
97
65
  * @property {string} [scheme] - The URL scheme used to enter the current screen.
98
- * @property {`xSmall` | `Small` | `Medium` | `Large` | `xLarge` | `xxLarge` | `xxxLarge` | `A11y_Medium` | `A11y_Large` | `A11y_xLarge` | `A11y_xxLarge` | `A11y_xxxLarge`} initialFontSize (iOS only) iOS system font size. Each value represents a specific font size. Default value is `Large`.
99
- * @property {boolean} isVisible (iOS only) Whether the screen is currently visible in iOS. Initial value is passed as `true`.
100
- * @property {string} initialFontScale (Android only) Android system font scale. The font size scale adjusted by the user in Android device's accessibility settings. This value is multiplied by the base font size to determine the final font size.
101
66
  *
102
67
  * @example
103
68
  *
@@ -120,8 +85,8 @@ type IOSFontSizeType = 'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxL
120
85
  * appName: APP_NAME,
121
86
  * context,
122
87
  * });
123
- * :::
124
88
  * ```
89
+ * :::
125
90
  */
126
91
  export type InitialProps = AndroidInitialProps | IOSInitialProps;
127
92
  export {};
@@ -0,0 +1,67 @@
1
+ import type { default as VideoRef } from '@granite-js/native/react-native-video';
2
+ import { ComponentProps } from 'react';
3
+ import { Animated } from 'react-native';
4
+ import * as instance from './instance';
5
+ declare const AnimatedRNVideo: Animated.AnimatedComponent<import("react").ComponentType<instance.VideoNativeProps>>;
6
+ type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
7
+ /**
8
+ * @public
9
+ * @name Video
10
+ * @category UI
11
+ * @description
12
+ * 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.
13
+ *
14
+ * ::: warning
15
+ * 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.
16
+ * :::
17
+ *
18
+ * @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.
19
+ *
20
+ * @param {VideoProperties} [props] Properties provided by [`react-native-video`](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6).
21
+ * @param {string} [props.source.uri] Source of the video to play. Can be set to a file path or URL.
22
+ * @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`.
23
+ * @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.
24
+ * @param {OnAudioFocusChanged} [props.onAudioFocusChanged] Callback function called when audio focus changes. Must be implemented when `muted` is `false`. For more details, see [OnAudioFocusChanged](/reference/react-native/Types/OnAudioFocusChanged.html).
25
+ * @param {Ref<VideoRef>} ref Reference object to access the video instance. Through this ref, you can access various methods of the video instance.
26
+ *
27
+ * @returns {JSX.Element} Returns a JSX element that renders the video. Uses `Animated` to provide smooth animation effects during video playback.
28
+ *
29
+ * @see [react-native-video] https://github.com/react-native-video/react-native-video
30
+ * For detailed properties of the video component, please refer to the official documentation.
31
+ * @see [react-native-video-6.0.0] https://github.com/TheWidlarzGroup/react-native-video/releases/tag/v6.0.0
32
+ * This is the source code of the version currently installed in the sandbox app.
33
+ *
34
+ * @example
35
+ *
36
+ * ### Video Autoplay Example
37
+ *
38
+ * ```tsx
39
+ * import { useRef } from 'react';
40
+ * import { View } from 'react-native';
41
+ * import { Video } from '@granite-js/react-native';
42
+ *
43
+ * export function VideoExample() {
44
+ * const videoRef = useRef(null);
45
+ *
46
+ * return (
47
+ * <View>
48
+ * <Video
49
+ * ref={videoRef}
50
+ * source={{ uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' }}
51
+ * muted={true}
52
+ * paused={false}
53
+ * resizeMode="cover"
54
+ * style={{ width: 300, height: 200, borderWidth: 1 }}
55
+ * />
56
+ * </View>
57
+ * );
58
+ * }
59
+ * ```
60
+ */
61
+ declare const Video: import("react").ForwardRefExoticComponent<Omit<import("react-native-video").VideoProperties, "onAudioFocusChanged"> & {
62
+ onAudioFocusChanged?: (event: {
63
+ hasAudioFocus: boolean;
64
+ }) => void;
65
+ } & import("react").RefAttributes<VideoRef>>;
66
+ export { Video };
67
+ export type { VideoRef, VideoProps };
@@ -0,0 +1 @@
1
+ export * from './Video';
@@ -0,0 +1,9 @@
1
+ import type { VideoProperties } from '@granite-js/native/react-native-video';
2
+ import { type ComponentType } from 'react';
3
+ export type VideoNativeProps = Omit<VideoProperties, 'onAudioFocusChanged'> & {
4
+ onAudioFocusChanged?: (event: {
5
+ hasAudioFocus: boolean;
6
+ }) => void;
7
+ };
8
+ export declare const Component: ComponentType<VideoNativeProps>;
9
+ export declare const isAvailable: boolean;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@granite-js/react-native",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The Granite Framework",
5
5
  "bin": {
6
6
  "granite": "./bin/cli.js"
7
7
  },
8
8
  "scripts": {
9
9
  "typecheck": "tsc --noEmit",
10
- "test": "vitest --no-watch",
10
+ "test": "vitest --no-watch --coverage",
11
11
  "lint": "eslint .",
12
12
  "build": "tsup && tsc -p tsconfig.build.json",
13
13
  "prepack": "yarn build"
@@ -56,7 +56,7 @@
56
56
  "@babel/core": "^7.24.9",
57
57
  "@babel/preset-env": "^7.24.8",
58
58
  "@babel/preset-typescript": "^7.24.7",
59
- "@granite-js/native": "0.1.0",
59
+ "@granite-js/native": "0.1.2",
60
60
  "@testing-library/dom": "^10.4.0",
61
61
  "@testing-library/react": "^16.1.0",
62
62
  "@types/babel__core": "^7",
@@ -64,6 +64,7 @@
64
64
  "@types/node": "^22.10.2",
65
65
  "@types/react": "18.3.3",
66
66
  "@types/react-dom": "^18",
67
+ "@vitest/coverage-v8": "^2.1.8",
67
68
  "esbuild": "^0.25.4",
68
69
  "eslint": "^9.7.0",
69
70
  "jsdom": "^25.0.1",
@@ -81,11 +82,12 @@
81
82
  "react-native": "*"
82
83
  },
83
84
  "dependencies": {
84
- "@granite-js/cli": "0.1.0",
85
- "@granite-js/image": "0.1.0",
86
- "@granite-js/jest": "0.1.0",
87
- "@granite-js/mpack": "0.1.0",
88
- "@granite-js/style-utils": "0.1.0",
85
+ "@granite-js/cli": "0.1.2",
86
+ "@granite-js/image": "0.1.2",
87
+ "@granite-js/jest": "0.1.2",
88
+ "@granite-js/lottie": "0.1.2",
89
+ "@granite-js/mpack": "0.1.2",
90
+ "@granite-js/style-utils": "0.1.2",
89
91
  "es-toolkit": "^1.34.1",
90
92
  "react-native-url-polyfill": "1.3.0"
91
93
  }
package/src/index.ts CHANGED
@@ -3,6 +3,8 @@ import './types/global';
3
3
  export { Granite } from './app';
4
4
  export * from '@granite-js/style-utils';
5
5
  export * from '@granite-js/image';
6
+ export * from '@granite-js/lottie';
7
+
6
8
  export * from './dev-entrypoint';
7
9
  export * from './native-modules/natives';
8
10
  export * from './visibility';
@@ -14,6 +16,7 @@ export * from './scroll-view-inertial-background';
14
16
  export * from './react';
15
17
  export * from './router/createRoute';
16
18
  export * from './event';
19
+ export * from './video';
17
20
 
18
21
  export type { InitialProps, ColorPreference } from './initial-props';
19
22
  export type { GraniteProps } from './app';
@@ -9,15 +9,6 @@
9
9
  */
10
10
  export type ColorPreference = 'light' | 'dark';
11
11
 
12
- /**
13
- * @name NetworkStatus
14
- * @description
15
- * Type representing the network status.
16
- *
17
- * @typedef {'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE'} NetworkStatus
18
- */
19
- type NetworkStatus = 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE';
20
-
21
12
  /**
22
13
  * @category Types
23
14
  * @name BaseInitialProps
@@ -26,18 +17,12 @@ type NetworkStatus = 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'UNKNOWN' | 'OFFLINE';
26
17
  *
27
18
  * @interface
28
19
  * @property {'ios' | 'android'} platform - Platform type
29
- * @property {string} appVersion - App version
30
20
  * @property {ColorPreference} initialColorPreference - Initial color
31
- * @property {NetworkStatus} networkStatus - Network status
32
- * @property {number} loadingStartTs - Timestamp when ReactNativeView started rendering in native
33
21
  * @property {string} [scheme] - Executed scheme
34
22
  */
35
23
  type BaseInitialProps = {
36
24
  platform: 'ios' | 'android';
37
- appVersion: string;
38
25
  initialColorPreference: ColorPreference;
39
- networkStatus: NetworkStatus;
40
- loadingStartTs: number;
41
26
  scheme?: string;
42
27
  };
43
28
 
@@ -50,13 +35,9 @@ type BaseInitialProps = {
50
35
  * @interface
51
36
  * @augments BaseInitialProps
52
37
  * @property {'android'} platform - Platform name (Android)
53
- * @property {string} initialFontScale - Font scale set on the device
54
- * @property {string} distributionGroup - Distribution group
55
38
  */
56
39
  export type AndroidInitialProps = BaseInitialProps & {
57
40
  platform: 'android';
58
- initialFontScale: string;
59
- distributionGroup: string;
60
41
  };
61
42
 
62
43
  /**
@@ -68,37 +49,11 @@ export type AndroidInitialProps = BaseInitialProps & {
68
49
  * @interface
69
50
  * @augments BaseInitialProps
70
51
  * @property {'ios'} platform - Platform (iOS)
71
- * @property {IOSFontSizeType} initialFontSize - Initial font size
72
- * @property {boolean} isVisible - Visibility status
73
52
  */
74
53
  export type IOSInitialProps = BaseInitialProps & {
75
54
  platform: 'ios';
76
- initialFontSize: IOSFontSizeType;
77
- isVisible: boolean;
78
55
  };
79
56
 
80
- /**
81
- * @category Types
82
- * @name IOSFontSizeType
83
- * @description
84
- * Type representing iOS font size type.
85
- *
86
- * @typedef {'xSmall' | 'Small' | 'Medium' | 'Large' | 'xLarge' | 'xxLarge' | 'xxxLarge' | 'A11y_Medium' | 'A11y_Large' | 'A11y_xLarge' | 'A11y_xxLarge' | 'A11y_xxxLarge'} IOSFontSizeType
87
- */
88
- type IOSFontSizeType =
89
- | 'xSmall'
90
- | 'Small'
91
- | 'Medium'
92
- | 'Large'
93
- | 'xLarge'
94
- | 'xxLarge'
95
- | 'xxxLarge'
96
- | 'A11y_Medium'
97
- | 'A11y_Large'
98
- | 'A11y_xLarge'
99
- | 'A11y_xxLarge'
100
- | 'A11y_xxxLarge';
101
-
102
57
  /**
103
58
  * @public
104
59
  * @category Core
@@ -111,11 +66,7 @@ type IOSFontSizeType =
111
66
  *
112
67
  * @property {'ios' | 'android'} platform - The platform on which the app is currently running. Has a value of either `ios` or `android`.
113
68
  * @property {ColorPreference} initialColorPreference - The initial color theme. Represents the color theme set by the user.
114
- * @property {NetworkStatus} networkStatus - The current device's network connection status and connected network.
115
69
  * @property {string} [scheme] - The URL scheme used to enter the current screen.
116
- * @property {`xSmall` | `Small` | `Medium` | `Large` | `xLarge` | `xxLarge` | `xxxLarge` | `A11y_Medium` | `A11y_Large` | `A11y_xLarge` | `A11y_xxLarge` | `A11y_xxxLarge`} initialFontSize (iOS only) iOS system font size. Each value represents a specific font size. Default value is `Large`.
117
- * @property {boolean} isVisible (iOS only) Whether the screen is currently visible in iOS. Initial value is passed as `true`.
118
- * @property {string} initialFontScale (Android only) Android system font scale. The font size scale adjusted by the user in Android device's accessibility settings. This value is multiplied by the base font size to determine the final font size.
119
70
  *
120
71
  * @example
121
72
  *
@@ -138,7 +89,7 @@ type IOSFontSizeType =
138
89
  * appName: APP_NAME,
139
90
  * context,
140
91
  * });
141
- * :::
142
92
  * ```
93
+ * :::
143
94
  */
144
95
  export type InitialProps = AndroidInitialProps | IOSInitialProps;
@@ -0,0 +1,104 @@
1
+ import type { default as VideoRef } from '@granite-js/native/react-native-video';
2
+ import { ComponentProps, forwardRef, useMemo, useState } from 'react';
3
+ import { Animated, Platform } from 'react-native';
4
+ import * as instance from './instance';
5
+ import { useVisibility } from '../visibility';
6
+
7
+ const AnimatedRNVideo = Animated.createAnimatedComponent(instance.Component);
8
+
9
+ type VideoProps = ComponentProps<typeof AnimatedRNVideo>;
10
+
11
+ /**
12
+ * @public
13
+ * @name Video
14
+ * @category UI
15
+ * @description
16
+ * 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
+ *
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
+ * @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
+ *
24
+ * @param {VideoProperties} [props] Properties provided by [`react-native-video`](https://github.com/TheWidlarzGroup/react-native-video/tree/v6.0.0-alpha.6).
25
+ * @param {string} [props.source.uri] Source of the video to play. Can be set to a file path or URL.
26
+ * @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
+ * @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.
28
+ * @param {OnAudioFocusChanged} [props.onAudioFocusChanged] Callback function called when audio focus changes. Must be implemented when `muted` is `false`. For more details, see [OnAudioFocusChanged](/reference/react-native/Types/OnAudioFocusChanged.html).
29
+ * @param {Ref<VideoRef>} ref Reference object to access the video instance. Through this ref, you can access various methods of the video instance.
30
+ *
31
+ * @returns {JSX.Element} Returns a JSX element that renders the video. Uses `Animated` to provide smooth animation effects during video playback.
32
+ *
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
+ * @example
39
+ *
40
+ * ### Video Autoplay Example
41
+ *
42
+ * ```tsx
43
+ * import { useRef } from 'react';
44
+ * import { View } from 'react-native';
45
+ * import { Video } from '@granite-js/react-native';
46
+ *
47
+ * export function VideoExample() {
48
+ * const videoRef = useRef(null);
49
+ *
50
+ * return (
51
+ * <View>
52
+ * <Video
53
+ * ref={videoRef}
54
+ * source={{ uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' }}
55
+ * muted={true}
56
+ * paused={false}
57
+ * resizeMode="cover"
58
+ * style={{ width: 300, height: 200, borderWidth: 1 }}
59
+ * />
60
+ * </View>
61
+ * );
62
+ * }
63
+ * ```
64
+ */
65
+ const Video = forwardRef<VideoRef, instance.VideoNativeProps>((props, ref) => {
66
+ const [isFocused, setIsFocused] = useState(props.muted || props.paused);
67
+ const visible = useVisibility();
68
+
69
+ // If focus state is not managed directly by the service through onAudioFocusChanged, control the paused value based on internal state.
70
+ const paused = useMemo(
71
+ () => !visible || props.paused || (!props.onAudioFocusChanged && !isFocused),
72
+ [props.onAudioFocusChanged, props.paused, visible, isFocused]
73
+ );
74
+
75
+ const disableFocus = props.muted || props.paused;
76
+ const mixWithOthers = props.muted ? 'mix' : undefined;
77
+
78
+ return (
79
+ <AnimatedRNVideo
80
+ ref={ref as any}
81
+ progressUpdateInterval={16}
82
+ disableFocus={Platform.OS === 'ios' ? false : disableFocus}
83
+ playWhenInactive
84
+ onAudioFocusChanged={(event: any) => {
85
+ setIsFocused(event.hasAudioFocus);
86
+ props.onAudioFocusChanged?.(event);
87
+ }}
88
+ {...props}
89
+ // Internal state is used to control the component's states.
90
+ paused={paused}
91
+ mixWithOthers={mixWithOthers}
92
+ />
93
+ );
94
+ });
95
+
96
+ Object.defineProperty(Video, 'isAvailable', {
97
+ value: instance.isAvailable,
98
+ enumerable: true,
99
+ writable: false,
100
+ configurable: false,
101
+ });
102
+
103
+ export { Video };
104
+ export type { VideoRef, VideoProps };
@@ -0,0 +1 @@
1
+ export * from './Video';
@@ -0,0 +1,28 @@
1
+ import type { VideoProperties } from '@granite-js/native/react-native-video';
2
+ import { Component as ReactComponent, forwardRef, type ComponentType, type ForwardedRef } from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ export type VideoNativeProps = Omit<VideoProperties, 'onAudioFocusChanged'> & {
6
+ onAudioFocusChanged?: (event: { hasAudioFocus: boolean }) => void;
7
+ };
8
+
9
+ class FallbackComponent extends ReactComponent<VideoNativeProps & { innerRef: ForwardedRef<View> }> {
10
+ render() {
11
+ return <View ref={this.props.innerRef} />;
12
+ }
13
+ }
14
+
15
+ const ForwardedComponent = forwardRef<View, VideoNativeProps>((props: VideoNativeProps, ref) => (
16
+ <FallbackComponent {...props} innerRef={ref} />
17
+ ));
18
+
19
+ function getVideoComponent(): ComponentType<VideoNativeProps> {
20
+ try {
21
+ return require('@granite-js/native/react-native-video')?.default;
22
+ } catch {
23
+ return ForwardedComponent;
24
+ }
25
+ }
26
+
27
+ export const Component = getVideoComponent();
28
+ export const isAvailable = Component !== ForwardedComponent;