Skip to content

Commit beae39b

Browse files
committed
feat: add basic implementation
1 parent 50c05ac commit beae39b

File tree

18 files changed

+18949
-39
lines changed

18 files changed

+18949
-39
lines changed

README.md

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,45 @@ Google reCAPTCHA provider for react native projects
55
## Installation
66

77
```sh
8-
npm install react-native-google-recaptcha-provider
8+
yarn add react-native-google-recaptcha-provider
99
```
1010

11-
## Usage
11+
## Overview
1212

13-
```js
14-
import { multiply } from 'react-native-google-recaptcha-provider';
13+
_react-native-google-recaptcha-provider_ is a library for integrating Google reCAPTCHA into React Native applications. It provides a convenient way to add and customize reCAPTCHA in your application to prevent spam and abuse.
1514

16-
// ...
15+
## Example
1716

18-
const result = await multiply(3, 7);
19-
```
17+
[You can find a usage example here](./example)
18+
19+
## Customization
20+
21+
The library provides various customization options such as specifying the size, theme, language, and action associated with the reCAPTCHA widget.
2022

21-
## Contributing
23+
## Method and Field Descriptions
2224

23-
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
25+
### __GoogleRecaptchaProps__
26+
| Prop Name | Type | Required | Description |
27+
|--------------------|--------------------------------------------------------|----------|--------------------------------------------------------------------------------------------------|
28+
| siteKey | string | Yes | The site key obtained from Google reCAPTCHA. |
29+
| baseUrl | string | Yes | The base URL of the website where reCAPTCHA is being used. |
30+
| onVerify | (token: string) => void | Yes | Callback function invoked when reCAPTCHA token is successfully verified. |
31+
| onExpire | () => void | No | Callback function invoked when the reCAPTCHA token expires. |
32+
| onError | (error: any) => void | No | Callback function invoked when an error occurs during reCAPTCHA verification. |
33+
| onClose | () => void | No | Callback function invoked when the reCAPTCHA widget is closed without completing. |
34+
| onLoad | () => void | No | Callback function invoked when the WebView finishes loading the HTML content. |
35+
| loadingComponent | ReactNode | No | A custom loading component to display while reCAPTCHA is loading. |
36+
| webViewProps | Omit<WebViewProps, 'source' \| 'style' \| 'onMessage'> | No | Additional props to be passed to the underlying WebView component. |
37+
| lang | string | No | The language code to use for reCAPTCHA. |
38+
| size | 'normal' \| 'compact' \| 'invisible' | No | The size of the reCAPTCHA widget. Possible values: 'normal', 'compact', 'invisible'. Default is 'normal'. |
39+
| theme | 'light' \| 'dark' | No | The theme of the reCAPTCHA widget. Possible values: 'light', 'dark'. Default is 'light'. |
40+
| enterprise | boolean | No | Specifies whether to use the new reCAPTCHA Enterprise API. Default is false. |
41+
| action | string | No | An additional parameter for specifying the action name associated with the protected element. |
42+
| recaptchaDomain | string | No | The domain of the reCAPTCHA service. Defaults to 'www.google.com'. |
43+
| gstaticDomain | string | No | The domain of the Google static content. Defaults to 'www.gstatic.com'. |
44+
| hideBadge | boolean | No | Specifies whether to hide the reCAPTCHA badge. Defaults to false. |
45+
| style | StyleProp\<ViewStyle\> | No | The style object or stylesheet for the root container of the component. |
2446

25-
## License
2647

2748
MIT
2849

example/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Example Usage
2+
3+
The reCAPTCHA component is implemented in such a way that it stretches to the full available width and height by default. Users are expected to implement their own modal window for displaying the reCAPTCHA challenge.
4+
5+
## Implementation
6+
7+
To see an example implementation of how to use `react-native-google-recaptcha-provider`, you can refer to the `ModalExample.tsx`. This file demonstrates how to integrate the reCAPTCHA component within a modal window.
8+
9+
10+
## Screenshots
11+
12+
<img src="../screenshot/1.png" alt="1" width="300"/>
13+
<img src="../screenshot/2.png" alt="1" width="300"/>

example/babel.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = function (api) {
1717
},
1818
},
1919
],
20+
['module:react-native-dotenv'],
2021
],
2122
};
2223
};

example/package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,18 @@
1212
"expo": "~50.0.17",
1313
"expo-status-bar": "~1.11.1",
1414
"react": "18.2.0",
15-
"react-native": "0.73.6",
1615
"react-dom": "18.2.0",
17-
"react-native-web": "~0.19.6"
16+
"react-native": "0.73.6",
17+
"react-native-safe-area-context": "^4.10.1",
18+
"react-native-web": "~0.19.6",
19+
"react-native-webview": "^13.8.7"
1820
},
1921
"devDependencies": {
2022
"@babel/core": "^7.20.0",
21-
"babel-plugin-module-resolver": "^5.0.0",
2223
"@expo/webpack-config": "^18.0.1",
23-
"babel-loader": "^8.1.0"
24+
"babel-loader": "^8.1.0",
25+
"babel-plugin-module-resolver": "^5.0.0",
26+
"react-native-dotenv": "^3.4.11"
2427
},
2528
"private": true
2629
}

example/src/App.tsx

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
1-
import * as React from 'react';
1+
import React, { useState } from 'react';
22

3-
import { StyleSheet, View, Text } from 'react-native';
4-
import { multiply } from 'react-native-google-recaptcha-provider';
3+
import { StyleSheet, Button, Alert } from 'react-native';
4+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
5+
import { RecaptchaModal } from './ModalExample';
56

6-
export default function App() {
7-
const [result, setResult] = React.useState<number | undefined>();
8-
9-
React.useEffect(() => {
10-
multiply(3, 7).then(setResult);
11-
}, []);
7+
export default function Root() {
8+
return (
9+
<SafeAreaProvider style={styles.root}>
10+
<App />
11+
</SafeAreaProvider>
12+
);
13+
}
1214

15+
function App() {
16+
const [modalIsVisible, setModalIsVisible] = useState(false);
1317
return (
14-
<View style={styles.container}>
15-
<Text>Result: {result}</Text>
16-
</View>
18+
<SafeAreaView style={styles.container}>
19+
<Button title="Open modal" onPress={() => setModalIsVisible(true)} />
20+
{modalIsVisible && (
21+
<RecaptchaModal
22+
onClose={() => setModalIsVisible(false)}
23+
onVerify={(_) => {
24+
setModalIsVisible(false);
25+
Alert.alert('Token', _);
26+
}}
27+
/>
28+
)}
29+
</SafeAreaView>
1730
);
1831
}
1932

2033
const styles = StyleSheet.create({
34+
root: {
35+
flex: 1,
36+
},
2137
container: {
2238
flex: 1,
23-
alignItems: 'center',
2439
justifyContent: 'center',
25-
},
26-
box: {
27-
width: 60,
28-
height: 60,
29-
marginVertical: 20,
40+
alignItems: 'center',
3041
},
3142
});

example/src/ModalExample.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { RecaptchaProps } from 'react-native-google-recaptcha-provider';
2+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
3+
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
4+
import React from 'react';
5+
import { RecaptchaProvider } from './RecaptchaProvider';
6+
7+
type RecaptchaModalProps = Pick<RecaptchaProps, 'onVerify' | 'onClose'> & {};
8+
export const RecaptchaModal = (props: RecaptchaModalProps) => {
9+
const insets = useSafeAreaInsets();
10+
const recaptchaTop = insets.top + CLOSE_SIZE;
11+
return (
12+
<View style={styles.modal}>
13+
<RecaptchaProvider
14+
style={{ top: recaptchaTop, bottom: insets.bottom }}
15+
{...props}
16+
/>
17+
<TouchableOpacity
18+
hitSlop={10}
19+
onPress={props.onClose}
20+
style={[styles.close, { marginTop: insets.top }]}
21+
>
22+
<Text style={styles.closeText}>&times;</Text>
23+
</TouchableOpacity>
24+
</View>
25+
);
26+
};
27+
28+
const CLOSE_SIZE = 50;
29+
const styles = StyleSheet.create({
30+
modal: {
31+
...StyleSheet.absoluteFillObject,
32+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
33+
},
34+
close: {
35+
justifyContent: 'center',
36+
alignItems: 'center',
37+
height: CLOSE_SIZE,
38+
width: CLOSE_SIZE,
39+
marginLeft: 'auto',
40+
marginRight: 20,
41+
borderRadius: 25,
42+
backgroundColor: '#ffffff',
43+
},
44+
closeText: {
45+
fontSize: 24,
46+
},
47+
});

example/src/RecaptchaProvider.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {
2+
Recaptcha,
3+
type RecaptchaProps,
4+
} from 'react-native-google-recaptcha-provider';
5+
import React from 'react';
6+
import { BASE_URL, SITE_KEY } from '@env';
7+
8+
export const RecaptchaProvider = (
9+
props: Omit<RecaptchaProps, 'siteKey' | 'baseUrl'>
10+
) => {
11+
return (
12+
<Recaptcha lang="en" siteKey={SITE_KEY} baseUrl={BASE_URL} {...props} />
13+
);
14+
};

example/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"extends": "../tsconfig",
33
"compilerOptions": {
4-
// Avoid expo-cli auto-generating a tsconfig
4+
"typeRoots": ["./types"]
55
}
66
}

example/types/env.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module '@env' {
2+
export const SITE_KEY: string;
3+
export const BASE_URL: string;
4+
}

package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-native-google-recaptcha-provider",
33
"version": "0.1.0",
4-
"description": "Google reCAPTCHA provider for react native projects",
4+
"description": "Google reCAPTCHA provider for react native (android & iOS) projects",
55
"main": "lib/commonjs/index",
66
"module": "lib/module/index",
77
"types": "lib/typescript/src/index.d.ts",
@@ -35,9 +35,13 @@
3535
"release": "release-it"
3636
},
3737
"keywords": [
38+
"recaptcha",
39+
"google recaptcha",
40+
"recaptcha provider",
3841
"react-native",
3942
"ios",
40-
"android"
43+
"android",
44+
"enterprise"
4145
],
4246
"repository": {
4347
"type": "git",
@@ -69,6 +73,7 @@
6973
"react": "18.2.0",
7074
"react-native": "0.73.6",
7175
"react-native-builder-bob": "^0.23.2",
76+
"react-native-webview": "^13.8.7",
7277
"release-it": "^15.0.0",
7378
"typescript": "^5.2.2"
7479
},
@@ -77,7 +82,8 @@
7782
},
7883
"peerDependencies": {
7984
"react": "*",
80-
"react-native": "*"
85+
"react-native": "*",
86+
"react-native-webview": "*"
8187
},
8288
"workspaces": [
8389
"example"

0 commit comments

Comments
 (0)