* 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:
Marc Rousavy 2021-03-12 13:21:46 +01:00 committed by GitHub
parent d85126d883
commit 33483cba94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 113 deletions

View File

@ -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

View File

@ -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":

View File

@ -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>

View File

@ -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,