Fix tsc (#49)
* Test: Rename a used prop * Use `github-check` reporter * Also output to CI * Update validate-js.yml * Update validate-js.yml * Update validate-js.yml * Revert "Test: Rename a used prop" This reverts commit 266b2716ea591a1e826279c1f573870bee3b13e5. * Run tsc and lint in parallel * Flatten `CameraProps` into single `interface` * Type NativeCameraViewProps * Fix native method typings * Force `as any` for now
This commit is contained in:
parent
d85126d883
commit
33483cba94
35
.github/workflows/validate-js.yml
vendored
35
.github/workflows/validate-js.yml
vendored
@ -19,15 +19,12 @@ on:
|
|||||||
- '*.lock'
|
- '*.lock'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
vibe_check:
|
compile:
|
||||||
name: Validate JS (tsc, eslint, prettier)
|
name: Compile JS (tsc)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install reviewdog
|
|
||||||
uses: reviewdog/action-setup@v1
|
|
||||||
|
|
||||||
- name: Get yarn cache directory path
|
- name: Get yarn cache directory path
|
||||||
id: yarn-cache-dir-path
|
id: yarn-cache-dir-path
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
@ -46,9 +43,30 @@ jobs:
|
|||||||
run: yarn install --frozen-lockfile --cwd example
|
run: yarn install --frozen-lockfile --cwd example
|
||||||
|
|
||||||
- name: Run TypeScript
|
- name: Run TypeScript
|
||||||
run: yarn typescript | reviewdog -f=tsc -reporter=github-pr-review -fail-on-error
|
uses: ypresto/typescript-error-reporter-action@6cb6a970f0783c19f55fb83079f7846a583c7543
|
||||||
env:
|
|
||||||
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
lint:
|
||||||
|
name: Lint JS (eslint, prettier)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get yarn cache directory path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Restore node_modules from cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
id: yarn-cache
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
|
- name: Install node_modules
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
- name: Install node_modules (example/)
|
||||||
|
run: yarn install --frozen-lockfile --cwd example
|
||||||
|
|
||||||
- name: Run ESLint
|
- name: Run ESLint
|
||||||
uses: reviewdog/action-eslint@v1
|
uses: reviewdog/action-eslint@v1
|
||||||
@ -56,3 +74,4 @@ jobs:
|
|||||||
reporter: github-pr-review
|
reporter: github-pr-review
|
||||||
eslint_flags: '--ext .js,.ts,.jsx,.tsx src'
|
eslint_flags: '--ext .js,.ts,.jsx,.tsx src'
|
||||||
fail_on_error: true
|
fail_on_error: true
|
||||||
|
filter_mode: nofilter
|
||||||
|
@ -42,6 +42,10 @@ function App() {
|
|||||||
See the [CameraPreset.ts](https://github.com/cuvent/react-native-vision-camera/blob/main/src/CameraPreset.ts) type for more information about presets
|
See the [CameraPreset.ts](https://github.com/cuvent/react-native-vision-camera/blob/main/src/CameraPreset.ts) type for more information about presets
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
You cannot set `preset` and `format` at the same time; if `format` is set, `preset` must be `undefined` and vice versa!
|
||||||
|
:::
|
||||||
|
|
||||||
### What you need to know about cameras
|
### What you need to know about cameras
|
||||||
|
|
||||||
To understand a bit more about camera formats, you first need to understand a few "general camera basics":
|
To understand a bit more about camera formats, you first need to understand a few "general camera basics":
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
TapGestureHandlerStateChangeEvent,
|
TapGestureHandlerStateChangeEvent,
|
||||||
} from 'react-native-gesture-handler';
|
} from 'react-native-gesture-handler';
|
||||||
import { Navigation, NavigationFunctionComponent } from 'react-native-navigation';
|
import { Navigation, NavigationFunctionComponent } from 'react-native-navigation';
|
||||||
import type { CameraDevice, CameraDeviceFormat, CameraProps, CameraRuntimeError, PhotoFile, VideoFile } from 'react-native-vision-camera';
|
import type { CameraDevice, CameraDeviceFormat, CameraRuntimeError, PhotoFile, VideoFile } from 'react-native-vision-camera';
|
||||||
import { Camera, frameRateIncluded, sortDevices, sortFormatsByResolution, filterFormatsByAspectRatio } from 'react-native-vision-camera';
|
import { Camera, frameRateIncluded, sortDevices, sortFormatsByResolution, filterFormatsByAspectRatio } from 'react-native-vision-camera';
|
||||||
import { useIsScreenFocused } from './hooks/useIsScreenFocused';
|
import { useIsScreenFocused } from './hooks/useIsScreenFocused';
|
||||||
import { CONTENT_SPACING, MAX_ZOOM_FACTOR, SAFE_AREA_PADDING } from './Constants';
|
import { CONTENT_SPACING, MAX_ZOOM_FACTOR, SAFE_AREA_PADDING } from './Constants';
|
||||||
@ -24,7 +24,9 @@ import IonIcon from 'react-native-vector-icons/Ionicons';
|
|||||||
import { useSelector } from 'pipestate';
|
import { useSelector } from 'pipestate';
|
||||||
import { FpsSelector } from './state/selectors';
|
import { FpsSelector } from './state/selectors';
|
||||||
|
|
||||||
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera);
|
// TODO: Remove once https://github.com/software-mansion/react-native-reanimated/pull/1697 gets merged
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
|
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera) as any;
|
||||||
Reanimated.addWhitelistedNativeProps({
|
Reanimated.addWhitelistedNativeProps({
|
||||||
zoom: true,
|
zoom: true,
|
||||||
});
|
});
|
||||||
@ -108,7 +110,7 @@ export const App: NavigationFunctionComponent = ({ componentId }) => {
|
|||||||
const neutralZoomScaled = (neutralZoom / maxZoomFactor) * formatMaxZoom;
|
const neutralZoomScaled = (neutralZoom / maxZoomFactor) * formatMaxZoom;
|
||||||
const maxZoomScaled = (1 / formatMaxZoom) * maxZoomFactor;
|
const maxZoomScaled = (1 / formatMaxZoom) * maxZoomFactor;
|
||||||
|
|
||||||
const cameraAnimatedProps = useAnimatedProps<Partial<CameraProps>>(
|
const cameraAnimatedProps = useAnimatedProps(
|
||||||
() => ({
|
() => ({
|
||||||
zoom: interpolate(zoom.value, [0, neutralZoomScaled, 1], [0, neutralZoom, maxZoomScaled], Extrapolate.CLAMP),
|
zoom: interpolate(zoom.value, [0, neutralZoomScaled, 1], [0, neutralZoom, maxZoomScaled], Extrapolate.CLAMP),
|
||||||
}),
|
}),
|
||||||
@ -249,8 +251,6 @@ export const App: NavigationFunctionComponent = ({ componentId }) => {
|
|||||||
onInitialized={onInitialized}
|
onInitialized={onInitialized}
|
||||||
onError={onError}
|
onError={onError}
|
||||||
enableZoomGesture={false}
|
enableZoomGesture={false}
|
||||||
// TODO: Remove once https://github.com/software-mansion/react-native-reanimated/pull/1697 gets merged
|
|
||||||
// @ts-expect-error animatedProps should be Partial<P>
|
|
||||||
animatedProps={cameraAnimatedProps}
|
animatedProps={cameraAnimatedProps}
|
||||||
/>
|
/>
|
||||||
</TapGestureHandler>
|
</TapGestureHandler>
|
||||||
|
186
src/Camera.tsx
186
src/Camera.tsx
@ -12,66 +12,7 @@ import type { TakeSnapshotOptions } from './Snapshot';
|
|||||||
import type { RecordVideoOptions, VideoFile } from './VideoFile';
|
import type { RecordVideoOptions, VideoFile } from './VideoFile';
|
||||||
|
|
||||||
//#region Types
|
//#region Types
|
||||||
type Modify<T, R> = Omit<T, keyof R> & R;
|
export interface CameraProps extends ViewProps {
|
||||||
|
|
||||||
interface CameraFormatProps {
|
|
||||||
/**
|
|
||||||
* Automatically selects a camera format which best matches the given preset
|
|
||||||
*/
|
|
||||||
preset?: CameraPreset;
|
|
||||||
/**
|
|
||||||
* Specify the frames per second this camera should use. Make sure the given `format` includes a frame rate range with the given `fps`.
|
|
||||||
*/
|
|
||||||
fps?: never;
|
|
||||||
/**
|
|
||||||
* Enables or disables HDR on this camera device. Make sure the given `format` supports HDR mode.
|
|
||||||
*/
|
|
||||||
hdr?: never;
|
|
||||||
/**
|
|
||||||
* Enables or disables low-light boost on this camera device. Make sure the given `format` supports low-light boost.
|
|
||||||
*/
|
|
||||||
lowLightBoost?: never;
|
|
||||||
/**
|
|
||||||
* Specifies the color space to use for this camera device. Make sure the given `format` contains the given `colorSpace`.
|
|
||||||
*/
|
|
||||||
colorSpace?: never;
|
|
||||||
/**
|
|
||||||
* Selects a given format.
|
|
||||||
*/
|
|
||||||
format?: never;
|
|
||||||
}
|
|
||||||
type CameraPresetProps = Modify<
|
|
||||||
CameraFormatProps,
|
|
||||||
{
|
|
||||||
preset?: never;
|
|
||||||
fps?: number;
|
|
||||||
hdr?: boolean;
|
|
||||||
lowLightBoost?: boolean;
|
|
||||||
colorSpace?: ColorSpace;
|
|
||||||
format?: CameraDeviceFormat;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
interface CameraScannerPropsNever {
|
|
||||||
/**
|
|
||||||
* Specify the code types this camera can scan.
|
|
||||||
*/
|
|
||||||
scannableCodes?: never;
|
|
||||||
/**
|
|
||||||
* Called when one or multiple codes have been scanned.
|
|
||||||
*/
|
|
||||||
onCodeScanned?: never;
|
|
||||||
}
|
|
||||||
export type CameraScannerProps = Modify<
|
|
||||||
CameraScannerPropsNever,
|
|
||||||
{
|
|
||||||
scannableCodes: CodeType[];
|
|
||||||
onCodeScanned: (codes: Code[]) => void;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export interface CameraDeviceProps {
|
|
||||||
// Properties
|
|
||||||
/**
|
/**
|
||||||
* The Camera Device to use.
|
* The Camera Device to use.
|
||||||
*
|
*
|
||||||
@ -92,30 +33,6 @@ export interface CameraDeviceProps {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
device: CameraDevice;
|
device: CameraDevice;
|
||||||
/**
|
|
||||||
* Also captures data from depth-perception sensors. (e.g. disparity maps)
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
enableDepthData?: boolean;
|
|
||||||
/**
|
|
||||||
* A boolean specifying whether the photo render pipeline is prepared for portrait effects matte delivery.
|
|
||||||
*
|
|
||||||
* When enabling this, you must also set `enableDepthData` to `true`.
|
|
||||||
*
|
|
||||||
* @platform iOS 12.0+
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
enablePortraitEffectsMatteDelivery?: boolean;
|
|
||||||
/**
|
|
||||||
* Indicates whether the photo render pipeline should be configured to deliver high resolution still images
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
enableHighResolutionCapture?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CameraDynamicProps {
|
|
||||||
/**
|
/**
|
||||||
* Whether the Camera should actively stream video frames, or not. See the [documentation about the `isActive` prop](https://cuvent.github.io/react-native-vision-camera/docs/devices#the-isactive-prop) for more information.
|
* Whether the Camera should actively stream video frames, or not. See the [documentation about the `isActive` prop](https://cuvent.github.io/react-native-vision-camera/docs/devices#the-isactive-prop) for more information.
|
||||||
*
|
*
|
||||||
@ -124,6 +41,8 @@ export interface CameraDynamicProps {
|
|||||||
* > Note: If you fully unmount the `<Camera>` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. In return, it will use less resources since the Camera will be completely destroyed when unmounted.
|
* > Note: If you fully unmount the `<Camera>` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. In return, it will use less resources since the Camera will be completely destroyed when unmounted.
|
||||||
*/
|
*/
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
||||||
|
//#region Common Props (torch, zoom)
|
||||||
/**
|
/**
|
||||||
* Set the current torch mode.
|
* Set the current torch mode.
|
||||||
*
|
*
|
||||||
@ -148,9 +67,66 @@ export interface CameraDynamicProps {
|
|||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
enableZoomGesture?: boolean;
|
enableZoomGesture?: boolean;
|
||||||
}
|
//#endregion
|
||||||
|
|
||||||
export interface CameraEventProps {
|
//#region Format/Preset selection
|
||||||
|
/**
|
||||||
|
* Automatically selects a camera format which best matches the given preset. Must be `undefined` when `format` is set!
|
||||||
|
*/
|
||||||
|
preset?: CameraPreset;
|
||||||
|
/**
|
||||||
|
* Selects a given format. Must be `undefined` when `preset` is set!
|
||||||
|
*/
|
||||||
|
format?: CameraDeviceFormat;
|
||||||
|
/**
|
||||||
|
* Specify the frames per second this camera should use. Make sure the given `format` includes a frame rate range with the given `fps`.
|
||||||
|
*
|
||||||
|
* Requires `format` to be set.
|
||||||
|
*/
|
||||||
|
fps?: number;
|
||||||
|
/**
|
||||||
|
* Enables or disables HDR on this camera device. Make sure the given `format` supports HDR mode.
|
||||||
|
*
|
||||||
|
* Requires `format` to be set.
|
||||||
|
*/
|
||||||
|
hdr?: boolean;
|
||||||
|
/**
|
||||||
|
* Enables or disables low-light boost on this camera device. Make sure the given `format` supports low-light boost.
|
||||||
|
*
|
||||||
|
* Requires `format` to be set.
|
||||||
|
*/
|
||||||
|
lowLightBoost?: boolean;
|
||||||
|
/**
|
||||||
|
* Specifies the color space to use for this camera device. Make sure the given `format` contains the given `colorSpace`.
|
||||||
|
*
|
||||||
|
* Requires `format` to be set.
|
||||||
|
*/
|
||||||
|
colorSpace?: ColorSpace;
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Also captures data from depth-perception sensors. (e.g. disparity maps)
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
enableDepthData?: boolean;
|
||||||
|
/**
|
||||||
|
* A boolean specifying whether the photo render pipeline is prepared for portrait effects matte delivery.
|
||||||
|
*
|
||||||
|
* When enabling this, you must also set `enableDepthData` to `true`.
|
||||||
|
*
|
||||||
|
* @platform iOS 12.0+
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
enablePortraitEffectsMatteDelivery?: boolean;
|
||||||
|
/**
|
||||||
|
* Indicates whether the photo render pipeline should be configured to deliver high resolution still images
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
enableHighResolutionCapture?: boolean;
|
||||||
|
|
||||||
|
//#region Events
|
||||||
/**
|
/**
|
||||||
* Called when any kind of runtime error occured.
|
* Called when any kind of runtime error occured.
|
||||||
*/
|
*/
|
||||||
@ -159,14 +135,19 @@ export interface CameraEventProps {
|
|||||||
* Called when the camera was successfully initialized.
|
* Called when the camera was successfully initialized.
|
||||||
*/
|
*/
|
||||||
onInitialized?: () => void;
|
onInitialized?: () => void;
|
||||||
}
|
|
||||||
|
|
||||||
export type CameraProps = (CameraPresetProps | CameraFormatProps) &
|
// TODO: Remove once frameProcessors land
|
||||||
(CameraScannerPropsNever | CameraScannerProps) &
|
/**
|
||||||
CameraDeviceProps &
|
* Specify the code types this camera can scan.
|
||||||
CameraDynamicProps &
|
*/
|
||||||
CameraEventProps &
|
scannableCodes?: CodeType[];
|
||||||
ViewProps;
|
// TODO: Remove once frameProcessors land
|
||||||
|
/**
|
||||||
|
* Called when one or multiple codes have been scanned.
|
||||||
|
*/
|
||||||
|
onCodeScanned?: (codes: Code[]) => void;
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
|
|
||||||
export type CameraPermissionStatus = 'authorized' | 'not-determined' | 'denied' | 'restricted';
|
export type CameraPermissionStatus = 'authorized' | 'not-determined' | 'denied' | 'restricted';
|
||||||
export type CameraPermissionRequestResult = 'authorized' | 'denied';
|
export type CameraPermissionRequestResult = 'authorized' | 'denied';
|
||||||
@ -179,6 +160,13 @@ interface OnErrorEvent {
|
|||||||
interface OnCodeScannedEvent {
|
interface OnCodeScannedEvent {
|
||||||
codes: Code[];
|
codes: Code[];
|
||||||
}
|
}
|
||||||
|
type NativeCameraViewProps = Omit<CameraProps, 'device' | 'onInitialized' | 'onError' | 'onCodeScanned'> & {
|
||||||
|
cameraId: string;
|
||||||
|
onInitialized?: (event: NativeSyntheticEvent<void>) => void;
|
||||||
|
onError?: (event: NativeSyntheticEvent<OnErrorEvent>) => void;
|
||||||
|
onCodeScanned?: (event: NativeSyntheticEvent<OnCodeScannedEvent>) => void;
|
||||||
|
};
|
||||||
|
type RefType = React.Component<NativeCameraViewProps> & Readonly<NativeMethods>;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@ -194,8 +182,6 @@ interface CameraState {
|
|||||||
cameraId?: string;
|
cameraId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefType = React.Component<CameraProps> & Readonly<NativeMethods>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### A powerful `<Camera>` component.
|
* ### A powerful `<Camera>` component.
|
||||||
*
|
*
|
||||||
@ -510,7 +496,7 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Events (Wrapped to maintain reference equality)
|
//#region Events (Wrapped to maintain reference equality)
|
||||||
private onError(event?: NativeSyntheticEvent<OnErrorEvent>): void {
|
private onError(event: NativeSyntheticEvent<OnErrorEvent>): void {
|
||||||
if (event == null) throw new Error('onError() was invoked but event was null!');
|
if (event == null) throw new Error('onError() was invoked but event was null!');
|
||||||
|
|
||||||
if (this.props.onError != null) {
|
if (this.props.onError != null) {
|
||||||
@ -527,7 +513,7 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
this.props.onInitialized?.();
|
this.props.onInitialized?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCodeScanned(event?: NativeSyntheticEvent<OnCodeScannedEvent>): void {
|
private onCodeScanned(event: NativeSyntheticEvent<OnCodeScannedEvent>): void {
|
||||||
if (event == null) throw new Error('onCodeScanned() was invoked but event was null!');
|
if (event == null) throw new Error('onCodeScanned() was invoked but event was null!');
|
||||||
|
|
||||||
if (this.props.onCodeScanned == null)
|
if (this.props.onCodeScanned == null)
|
||||||
@ -550,6 +536,8 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
|
if (this.state.cameraId == null) throw new Error('CameraId was null! Did you pass a valid `device`?');
|
||||||
|
|
||||||
// We remove the big `device` object from the props because we only need to pass `cameraId` to native.
|
// We remove the big `device` object from the props because we only need to pass `cameraId` to native.
|
||||||
const { device: _, ...props } = this.props;
|
const { device: _, ...props } = this.props;
|
||||||
return (
|
return (
|
||||||
@ -558,9 +546,7 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
cameraId={this.state.cameraId}
|
cameraId={this.state.cameraId}
|
||||||
ref={this.ref}
|
ref={this.ref}
|
||||||
onInitialized={this.onInitialized}
|
onInitialized={this.onInitialized}
|
||||||
// @ts-expect-error with our callback wrapping we have to extract NativeSyntheticEvent params
|
|
||||||
onError={this.onError}
|
onError={this.onError}
|
||||||
// @ts-expect-error with our callback wrapping we have to extract NativeSyntheticEvent params
|
|
||||||
onCodeScanned={this.onCodeScanned}
|
onCodeScanned={this.onCodeScanned}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -568,7 +554,7 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// requireNativeComponent automatically resolves 'CameraView' to 'CameraViewManager'
|
// requireNativeComponent automatically resolves 'CameraView' to 'CameraViewManager'
|
||||||
const NativeCameraView = requireNativeComponent<CameraProps>(
|
const NativeCameraView = requireNativeComponent<NativeCameraViewProps>(
|
||||||
'CameraView',
|
'CameraView',
|
||||||
// @ts-expect-error because the type declarations are kinda wrong, no?
|
// @ts-expect-error because the type declarations are kinda wrong, no?
|
||||||
Camera,
|
Camera,
|
||||||
|
Loading…
Reference in New Issue
Block a user