diff --git a/LENS.md b/LENS.md
index aefe56f4..8efe35f8 100644
--- a/LENS.md
+++ b/LENS.md
@@ -22,9 +22,9 @@ _These instructions assume you're integrating into a React/Next.js app. If you'r
1. Install IDKit JS
```bash
- yarn add @worldcoin/idkit
+ yarn add @worldcoin/idkit@0.3.3
# or
- npm install @worldcoin/idkit
+ npm install @worldcoin/idkit@0.3.3
```
2. Load IDKit JS. Note the action ID below, the Action ID is the **same for all Lens-powered apps.**
diff --git a/cspell.json b/cspell.json
index f124fee9..d4ac9f43 100644
--- a/cspell.json
+++ b/cspell.json
@@ -21,6 +21,7 @@
"TTFB",
"webp",
"zustand",
- "worldid"
+ "worldid",
+ "consts"
]
}
diff --git a/example-nextjs/pages/index.tsx b/example-nextjs/pages/index.tsx
index ad6dd803..7e3c0383 100644
--- a/example-nextjs/pages/index.tsx
+++ b/example-nextjs/pages/index.tsx
@@ -20,10 +20,11 @@ export default function Home() {
{({ open }) => }
diff --git a/example-react/src/App.tsx b/example-react/src/App.tsx
index 67e3fc61..dfe54459 100644
--- a/example-react/src/App.tsx
+++ b/example-react/src/App.tsx
@@ -19,10 +19,11 @@ function App() {
style={{ minHeight: "100vh", display: "flex", justifyContent: "center", alignItems: "center" }}
>
{({ open }) => }
diff --git a/idkit/esbuild/production.js b/idkit/esbuild/production.js
index 0c574d28..13ff4d7c 100644
--- a/idkit/esbuild/production.js
+++ b/idkit/esbuild/production.js
@@ -32,7 +32,8 @@ const configs = {
esm: {
...baseConfig,
- entryPoints: [require.resolve('../src/index.ts')],
+ entryPoints: [require.resolve('../src/index.ts'), require.resolve('../src/internal.ts')],
+ outdir: 'build/',
define: {
...baseConfig.define,
window: 'globalThis',
@@ -51,7 +52,6 @@ const configs = {
],
sourcemap: true,
format: 'esm',
- outfile: 'build/index.js',
},
iife: {
diff --git a/idkit/src/components/CountryCodeSelect.tsx b/idkit/src/components/CountryCodeSelect.tsx
deleted file mode 100644
index 4740fd7c..00000000
--- a/idkit/src/components/CountryCodeSelect.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import { classNames } from '@/lib/utils'
-import CheckIcon from './Icons/CheckIcon'
-import ReactCountryFlag from 'react-country-flag'
-import { allCountries } from 'country-telephone-data'
-import ChevronDownIcon from './Icons/ChevronDownIcon'
-import { Listbox, Transition } from '@headlessui/react'
-import { Fragment, useCallback, useEffect, useRef, useState } from 'react'
-
-type Props = {
- value: string
- onChange: (value: string) => void
-}
-
-const CountryCodeSelect = ({ value, onChange }: Props) => {
- const [countryCode, setCountryCode] = useState('us')
- const listRef = useRef(null)
-
- // FIXME: temporary solution for scroll list
- useEffect(() => {
- const List = listRef.current
-
- if (!List) {
- return
- }
-
- let touchY = 0
-
- const handleWheel = (e: WheelEvent) => {
- List.scrollTop += e.deltaY
- }
-
- const handleTouchStart = (e: TouchEvent) => {
- touchY = List.scrollTop + e.touches[0].pageY
- }
-
- const handleTouchMove = (e: TouchEvent) => {
- List.scrollTop = touchY - e.touches[0].pageY
- }
-
- List.addEventListener('wheel', handleWheel)
- List.addEventListener('touchstart', handleTouchStart)
- List.addEventListener('touchmove', handleTouchMove)
-
- return () => {
- List.removeEventListener('wheel', handleWheel)
- List.removeEventListener('touchstart', handleTouchStart)
- List.removeEventListener('touchmove', handleTouchMove)
- }
- }, [])
-
- const handleSetListHeight = useCallback(() => {
- const List = listRef.current
- if (!List) return
-
- const bounds = List.getBoundingClientRect()
-
- List.style.maxHeight = `${window.innerHeight - bounds.top - 12}px`
- }, [])
-
- useEffect(() => {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- onChange(allCountries.find(country => country.iso2 === countryCode)!.dialCode)
- }, [countryCode, onChange])
-
- return (
-
- {({ open }) => (
- <>
-
- Country Code
-
-
-
- +{value}
-
-
-
-
-
-
- {allCountries.map(country => (
-
- classNames(
- 'dark:text-white',
- selected
- ? 'bg-0d151d dark:bg-white text-white dark:text-0d151d font-medium'
- : active
- ? 'bg-0d151d/5 dark:bg-ece8fb/10'
- : 'text-gray-900 dark:text-white',
- 'relative flex items-center justify-between px-2 py-2 w-full rounded-xl text-sm focus:bg-gray-100 dark:focus:bg-ece8fb/25',
- 'focus:outline-none select-none'
- )
- }
- value={country.iso2}
- >
- {({ selected }) => (
- <>
-
-
-
{country.name}
- {selected ? (
-
-
-
- ) : null}
-
-
- +{country.dialCode}
-
- >
- )}
-
- ))}
-
-
-
- >
- )}
-
- )
-}
-
-export default CountryCodeSelect
diff --git a/idkit/src/components/IDKitWidget/BaseWidget.tsx b/idkit/src/components/IDKitWidget/BaseWidget.tsx
index 5f0a7abc..1948aba6 100644
--- a/idkit/src/components/IDKitWidget/BaseWidget.tsx
+++ b/idkit/src/components/IDKitWidget/BaseWidget.tsx
@@ -19,11 +19,8 @@ import { classNames, getCopy } from '@/lib/utils'
import type { WidgetProps } from '@/types/config'
import { Fragment, useEffect, useMemo } from 'react'
import WorldIDWordmark from '../Icons/WorldIDWordmark'
-import EnterPhoneState from './States/EnterPhoneState'
-import VerifyCodeState from './States/VerifyCodeState'
import { AnimatePresence, motion } from 'framer-motion'
import ArrowLongLeftIcon from '../Icons/ArrowLongLeftIcon'
-import SelectMethodState from './States/SelectMethodState'
import HostAppVerificationState from './States/HostAppVerificationState'
const getParams = ({
@@ -46,14 +43,14 @@ const getParams = ({
isOpen: open,
onOpenChange,
canGoBack: computed.canGoBack(stage),
- defaultStage: computed.getDefaultStage(),
})
const IDKitWidget: FC = ({
children,
- actionId,
+ app_id,
+ action,
+ action_description,
theme,
- methods,
signal,
walletConnectProjectId,
handleVerify,
@@ -68,7 +65,6 @@ const IDKitWidget: FC = ({
stage,
setStage,
canGoBack,
- defaultStage,
setOptions,
copy: _copy,
theme: _theme,
@@ -77,21 +73,38 @@ const IDKitWidget: FC = ({
useEffect(() => {
setOptions(
- { actionId, signal, walletConnectProjectId, methods, onSuccess, handleVerify, autoClose, copy, theme },
+ {
+ app_id,
+ action,
+ action_description,
+ signal,
+ walletConnectProjectId,
+ onSuccess,
+ handleVerify,
+ autoClose,
+ copy,
+ theme,
+ },
ConfigSource.PROPS
)
- }, [actionId, signal, walletConnectProjectId, methods, onSuccess, theme, handleVerify, autoClose, copy, setOptions])
+ }, [
+ copy,
+ app_id,
+ action,
+ theme,
+ signal,
+ autoClose,
+ onSuccess,
+ setOptions,
+ handleVerify,
+ action_description,
+ walletConnectProjectId,
+ ])
const StageContent = useMemo(() => {
switch (stage) {
- case IDKITStage.SELECT_METHOD:
- return SelectMethodState
- case IDKITStage.ENTER_PHONE:
- return EnterPhoneState
case IDKITStage.WORLD_ID:
return WorldIDState
- case IDKITStage.ENTER_CODE:
- return VerifyCodeState
case IDKITStage.SUCCESS:
return SuccessState
case IDKITStage.ERROR:
@@ -151,7 +164,7 @@ const IDKitWidget: FC = ({
)
}
diff --git a/idkit/src/components/PhoneInput.tsx b/idkit/src/components/PhoneInput.tsx
deleted file mode 100644
index d36e4994..00000000
--- a/idkit/src/components/PhoneInput.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { phone } from 'phone'
-import useIDKitStore from '@/store/idkit'
-import type { IDKitStore } from '@/store/idkit'
-import CountryCodeSelect from './CountryCodeSelect'
-import { Fragment, memo, useEffect, useState } from 'react'
-
-const getParams = ({ setPhoneNumber }: IDKitStore) => ({ setFullPhone: setPhoneNumber })
-
-const PhoneInput = ({ disabled, onSubmit }: { disabled?: boolean; onSubmit?: () => Promise | void }) => {
- const { setFullPhone } = useIDKitStore(getParams)
- const [countryCode, setCountryCode] = useState('1')
- const [phoneNumber, setPhoneNumber] = useState('')
-
- useEffect(() => {
- const validatedPhone = phone(`+${countryCode} ${phoneNumber}`)
- if (!validatedPhone.isValid) {
- setFullPhone('')
- return
- }
-
- setFullPhone(validatedPhone.phoneNumber)
- }, [countryCode, phoneNumber, setFullPhone])
-
- return (
-
-
-
-
-
-
-
-
setPhoneNumber(e.target.value)}
- className="placeholder:text-9eafc0 block w-full rounded-md border-transparent bg-transparent pl-6 focus:border-transparent focus:ring-transparent dark:text-white sm:text-sm"
- disabled={disabled}
- onKeyDown={e => e.key === 'Enter' && void onSubmit?.()}
- />
-
-
- )
-}
-
-export default memo(PhoneInput)
diff --git a/idkit/src/components/ResendButton.tsx b/idkit/src/components/ResendButton.tsx
deleted file mode 100644
index 3dd78efe..00000000
--- a/idkit/src/components/ResendButton.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { memo, useState } from 'react'
-import Countdown from 'react-countdown'
-import useIDKitStore from '@/store/idkit'
-import { ErrorCodes, IDKITStage } from '@/types'
-import { PhoneVerificationChannel } from '@/types'
-import { isRequestCodeError, requestCode } from '@/services/phone'
-import { getTelemetryId, telemetryRetryCode } from '@/lib/telemetry'
-
-const ONE_MINUTE = 59 * 1000
-
-const renderer = ({ minutes, seconds, completed }: { minutes: number; seconds: number; completed: boolean }) => {
- if (completed) return
-
- return (
-
- in {minutes}:{seconds < 10 ? `0${seconds}` : seconds}
-
- )
-}
-
-const ResendButton = () => {
- const { phoneNumber, stringifiedActionId, setProcessing, setStage, setErrorState } = useIDKitStore()
- const [nextTime, setNextTime] = useState(new Date().getTime() + ONE_MINUTE)
-
- const handleRetry = async (channel: PhoneVerificationChannel) => {
- setNextTime(new Date().getTime() + ONE_MINUTE)
- try {
- setProcessing(true)
- await requestCode(phoneNumber, stringifiedActionId, channel, getTelemetryId())
- telemetryRetryCode(channel)
- setProcessing(false)
- } catch (error) {
- setProcessing(false)
- setNextTime(undefined)
- if (isRequestCodeError(error) && error.code !== 'server_error') {
- setErrorState({ code: ErrorCodes.GENERIC_ERROR })
- console.error(error)
- } else {
- setStage(IDKITStage.ERROR)
- }
- }
- }
-
- return (
- <>
- void handleRetry(PhoneVerificationChannel.SMS)}
- >
- Resend{' '}
- {nextTime && (
- setNextTime(undefined)} date={nextTime} renderer={renderer} />
- )}
- {' '}
- or{' '}
- void handleRetry(PhoneVerificationChannel.Call)}
- >
- Call me
-
- >
- )
-}
-
-export default memo(ResendButton)
diff --git a/idkit/src/components/SMSCodeInput.tsx b/idkit/src/components/SMSCodeInput.tsx
deleted file mode 100644
index e50b2f72..00000000
--- a/idkit/src/components/SMSCodeInput.tsx
+++ /dev/null
@@ -1,176 +0,0 @@
-import { classNames } from '@/lib/utils'
-import useIDKitStore from '@/store/idkit'
-import type { IDKitStore } from '@/store/idkit'
-import type { ChangeEvent, ClipboardEvent, KeyboardEvent, RefObject } from 'react'
-import { createRef, memo, useCallback, useEffect, useMemo, useState } from 'react'
-
-type Array6 = [T, T, T, T, T, T]
-
-const fillValues = (value: string): Array6 => {
- return new Array(6).fill('').map((_, index) => value[index] || '') as Array6
-}
-
-const getParams = ({ code, setCode }: IDKitStore) => ({ code, setCode })
-
-const SMSCodeInput = ({ submitRef, disabled }: { submitRef: RefObject; disabled?: boolean }) => {
- const { code, setCode } = useIDKitStore(getParams)
-
- const inputsRefs = useMemo(() => new Array(6).fill(null).map(() => createRef()), [])
- const [values, setValues] = useState>(fillValues(''))
- const [focusedIndex, setFocusedIndex] = useState(-1)
-
- useEffect(() => {
- if (!code) {
- setValues(fillValues(''))
- }
- }, [code])
-
- const selectInputContent = useCallback(
- (index: number) => {
- requestAnimationFrame(() => {
- inputsRefs[index].current?.select()
- })
- },
- [inputsRefs]
- )
-
- const setValue = useCallback(
- (value: string, index: number) => {
- const nextValues = [...values]
- nextValues[index] = value
-
- setValues(nextValues as Array6)
-
- const stringifiedValues = nextValues.join('')
-
- setCode('')
- if (stringifiedValues.length !== 6) return
-
- setCode(stringifiedValues)
- },
- [setCode, values]
- )
-
- const focusInput = useCallback(
- (index: number) => {
- requestAnimationFrame(() => {
- inputsRefs[index]?.current?.focus()
- })
- },
- [inputsRefs]
- )
-
- const blurInput = useCallback(
- (index: number) => {
- requestAnimationFrame(() => {
- inputsRefs[index].current?.blur()
- })
- },
- [inputsRefs]
- )
-
- const onInputFocus = (index: number) => {
- if (!inputsRefs[index]?.current) return
-
- setFocusedIndex(index)
- selectInputContent(index)
- }
-
- const onInputChange = useCallback(
- (event: ChangeEvent, index: number) => {
- const value = event.target.value.replace(values[index], '')
-
- if (!/^\d/.test(value)) return selectInputContent(index)
-
- if (value.length > 1) {
- setValues(fillValues(event.target.value))
-
- if (event.target.value.length !== 6) return
-
- setCode(event.target.value)
- return blurInput(index)
- }
-
- setValue(value, index)
-
- if (index === 5) {
- requestAnimationFrame(() => {
- submitRef.current?.focus()
- })
- } else focusInput(index + 1)
- },
- [blurInput, submitRef, focusInput, selectInputContent, setCode, setValue, values]
- )
-
- const onInputKeyDown = useCallback(
- (event: KeyboardEvent, index: number) => {
- if (event.key === 'Backspace' || event.key === 'Delete') {
- event.preventDefault()
-
- setValue('', focusedIndex)
- return focusInput(index - 1)
- }
-
- if (event.key === values[index]) {
- if (index === 5) return blurInput(index)
-
- focusInput(index + 1)
- }
- },
- [focusInput, blurInput, focusedIndex, setValue, values]
- )
-
- const onInputPaste = useCallback(
- (event: ClipboardEvent, index: number) => {
- event.preventDefault()
-
- const pastedValue = event.clipboardData.getData('text')
- const nextValues = pastedValue.slice(0, 6)
-
- if (!/^\d/.test(nextValues)) return
-
- setValues(fillValues(nextValues))
- if (nextValues.length !== 6) return focusInput(nextValues.length)
-
- setCode(nextValues)
- blurInput(index)
- },
- [blurInput, focusInput, setCode]
- )
-
- useEffect(() => {
- focusInput(0)
- }, [focusInput, inputsRefs])
-
- return (
-
- )
-}
-
-export default memo(SMSCodeInput)
diff --git a/idkit/src/index.html b/idkit/src/index.html
index 99e450fe..b0263d5c 100644
--- a/idkit/src/index.html
+++ b/idkit/src/index.html
@@ -41,7 +41,9 @@ idkit-js