Skip to content

Commit

Permalink
feat: add support for refreshExpired option and remove `autoResetOn…
Browse files Browse the repository at this point in the history
…Expire` prop

BREAKING CHANGE: `autoResetOnExpire` prop is not valid anymore - use `options.refreshExpired` instead. [Check this snippet](https://github.com/marsidev/react-turnstile#handling-widget-expiring)
  • Loading branch information
marsidev committed Mar 13, 2023
1 parent db3cd84 commit 64f1020
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 59 deletions.
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,27 +97,27 @@ function Widget() {
| **Prop** | **Type** | **Description** | **Required** |
|-------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|
| siteKey | `string` | Your sitekey key, get one from [here](https://developers.cloudflare.com/turnstile/get-started/). ||
| options | `object` | Widget render options. More info about this options [below](https://github.com/marsidev/react-turnstile/#render-options). | |
| options | `object` | Widget render options. More info about this options [below](#render-options). | |
| scriptOptions | `object` | You can customize the injected `script` tag with this prop. It allows you to add `async`, `defer`, `nonce` attributes to the script tag. You can also control whether the injected script will be added to the document body or head with `appendTo` attribute. | |
| onSuccess | `function` | Callback that is invoked upon success of the challenge. The callback is passed a token that can be validated. | |
| onExpire | `function` | Callback that is invoked when a challenge expires. | |
| onExpire | `function` | Callback that is invoked when a challenge expires. Read [the docs](https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#refreshing-a-widget) for more info about handling expired widgets. | |
| onError | `function` | Callback that is invoked when there is a network error. | |
| autoResetOnExpire | `boolean` | Controls whether the widget should automatically reset when it expires. If is set to `true`, you don't need to use the `onExpire` callback. Default to `true`. | |
### Render options
| **Option** | **Type** | **Default** | **Description** |
|-------------------|-----------|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| action | `string` | `undefined` | A customer value that can be used to differentiate widgets under the same `sitekey` in analytics and which is returned upon validation. This can only contain up to 32 alphanumeric characters including `_` and `-`. |
| cData | `string` | `undefined` | A customer payload that can be used to attach customer data to the challenge throughout its issuance and which is returned upon validation. This can only contain up to 255 alphanumeric characters including `_` and `-`. |
| theme | `string` | `'auto'` | The widget theme. You can choose between `light`, `dark` or `auto`. |
| language | `string` | `'auto'` | Language to display, must be either: `auto` (default) to use the language that the visitor has chosen, or an ISO 639-1 two-letter language code (e.g. `en`) or language and country code (e.g. `pt-BR`). The following languages are currently supported: `ar-EG`, `de`, `en`, `es`, `fa`, `fr`, `id`, `it`, `ja`, `ko`, `nl`, `pl`, `pt-BR`, `ru`, `tr`, `zh-CN` and `zh-TW`. |
| tabIndex | `number` | `0` | The `tabindex` of Turnstile’s iframe for accessibility purposes. |
| action | `string` | `undefined` | A customer value that can be used to differentiate widgets under the same `sitekey` in analytics and which is returned upon validation. This can only contain up to 32 alphanumeric characters including `_` and `-`. |
| cData | `string` | `undefined` | A customer payload that can be used to attach customer data to the challenge throughout its issuance and which is returned upon validation. This can only contain up to 255 alphanumeric characters including `_` and `-`. |
| responseField | `boolean` | `true` | A boolean that controls if an input element with the response token is created. |
| responseFieldName | `string` | `'cf-turnstile-response'` | Name of the input element. |
| size | `string` | `'normal'` | The widget size. Can take the following values: `'normal'`, `'compact'`, or `'invisible'`. The normal size is 300x65px, the compact size is 130x120px. Use `invisible` if your key type is `invisible`, this option will prevent creating placeholder for the widget. |
| retry | `string` | `'auto'` | Controls whether the widget should automatically retry to obtain a token if it did not succeed. The default is `'auto'`, which will retry automatically. This can be set to `'never'` to disable retry upon failure. |
| retryInterval | `number` | `8000` | When `retry` is set to `'auto'`, `retryInterval` controls the time between retry attempts in milliseconds. The value must be a positive integer less than `900000`. When `retry` is set to `'never'`, this parameter has no effect. |
| refreshExpired | `string` | `auto` | Automatically refreshes the token when it expires. Can take `auto`, `manual` or `never`. Read [the docs](https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#refreshing-a-widget) for more info about handling expired widgets. |
> * All this options are optional.
> * Read [the docs](https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#configurations) to get more info about this options.
Expand Down Expand Up @@ -159,7 +159,8 @@ function Widget() {
options={{
action: 'submit-form',
theme: 'light',
size: 'compact'
size: 'compact',
language: 'fr',
}}
scriptOptions={{
appendTo: 'body'
Expand Down Expand Up @@ -189,8 +190,6 @@ function Widget() {
}
```
> `onExpire` does not take effect unless you set `autoResetOnExpire` to `false`.
### Getting the token after solving the challenge
```jsx
Expand Down Expand Up @@ -336,7 +335,7 @@ export default async function handler(request, response) {
### Handling widget expiring
> By default, you don't need to handle the widget expiring, unless you set `autoResetOnExpire` to `false`.
> By default, you don't need to handle the widget expiring, unless you set `options.refreshExpired` to `'manual'` or `'never'`.
```jsx
import { useRef } from 'react'
Expand All @@ -348,7 +347,7 @@ function Widget() {
return (
<Turnstile
ref={ref}
autoResetOnExpire={false}
options={{ refreshExpired: 'manual' }}
siteKey='1x00000000000000000000AA'
onExpire={() => ref.current?.reset()}
/>
Expand Down
18 changes: 5 additions & 13 deletions packages/example/src/components/Demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,25 @@ const Demo = () => {
onRestartStates()
}

const onSuccess = (token: string) => {
setToken(token)
setStatus('solved')
}

const onExpire = () => {
setStatus('expired')
turnstileRef.current?.reset()
}

return (
<div className='flex flex-col items-center justify-center w-full min-h-screen py-24'>
<main className='w-full max-w-[740px] flex justify-center flex-col text-white p-4 gap-2'>
<h1 className='font-semibold text-4xl mb-4'>React Turnstile Demo</h1>

<Turnstile
ref={turnstileRef}
autoResetOnExpire={false}
options={{
theme,
size,
language: lang
}}
siteKey={testingSiteKey}
onError={() => setStatus('error')}
onExpire={onExpire}
onSuccess={onSuccess}
onExpire={() => setStatus('expired')}
onSuccess={token => {
setToken(token)
setStatus('solved')
}}
/>

<h2 className='font-semibold text-2xl mt-8'>Configuration</h2>
Expand Down
33 changes: 9 additions & 24 deletions src/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,8 @@ import {
import { RenderOptions, TurnstileInstance, TurnstileProps } from './types'

export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProps>((props, ref) => {
const {
scriptOptions,
options,
siteKey,
onSuccess,
onExpire,
onError,
id,
autoResetOnExpire = true,
style,
...divProps
} = props
const { scriptOptions, options, siteKey, onSuccess, onExpire, onError, id, style, ...divProps } =
props
const config = options ?? {}

const [widgetId, setWidgetId] = useState<string | undefined | null>()
Expand Down Expand Up @@ -93,20 +83,21 @@ export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProp
)

const renderConfig: RenderOptions = {
sitekey: siteKey,
action: config.action,
cData: config.cData,
theme: config.theme ?? 'auto',
sitekey: siteKey,
tabindex: config.tabIndex,
callback: onSuccess,
'expired-callback': onExpire,
'error-callback': onError,
size: getTurnstileSizeOpts(containerSize),
'expired-callback': onExpire,
theme: config.theme ?? 'auto',
language: config.language ?? 'auto',
tabindex: config.tabIndex,
'response-field': config.responseField,
'response-field-name': config.responseFieldName,
size: getTurnstileSizeOpts(containerSize),
retry: config.retry ?? 'auto',
'retry-interval': config.retryInterval ?? 8000,
language: config.language ?? 'auto'
'refresh-expired': config.refreshExpired ?? 'auto'
}

const onLoadScript = () => {
Expand Down Expand Up @@ -140,12 +131,6 @@ export const Turnstile = forwardRef<TurnstileInstance | undefined, TurnstileProp
onLoad: onLoadScript,
onError: onLoadScriptError
})

if (autoResetOnExpire) {
// expire time it's documented as 300 seconds but can happen in around 290 seconds.
const timerId = setInterval(() => window.turnstile?.reset(), 290 * 1000)
return () => clearInterval(timerId)
}
}, [configJson, scriptOptionsJson])

useEffect(
Expand Down
Loading

0 comments on commit 64f1020

Please sign in to comment.