diff --git a/package.json b/package.json
index 10c6def..ecb4315 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@arcana/auth",
- "version": "1.0.7",
+ "version": "1.0.8",
"description": "Arcana Auth",
"main": "dist/standalone/auth.esm.js",
"type": "module",
@@ -61,6 +61,7 @@
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-typescript": "^8.3.3",
"@types/jest": "^27.4.1",
+ "@types/validator": "^13.11.1",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"babel-jest": "^29.0.2",
@@ -90,7 +91,8 @@
"dependencies": {
"@metamask/safe-event-emitter": "^2.0.0",
"eth-rpc-errors": "^4.0.3",
- "penpal": "^6.0.1"
+ "penpal": "^6.0.1",
+ "validator": "^13.11.0"
},
"resolutions": {
"terser": "^5.15.0"
diff --git a/src/index.ts b/src/index.ts
index c81dc21..13164b7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -26,6 +26,7 @@ import {
ThemeConfig,
UserInfo,
} from './typings'
+import isEmail from 'validator/es/lib/isEmail'
import { getAppInfo, getImageUrls } from './appInfo'
import { ArcanaAuthError, ErrorNotInitialized } from './errors'
import { LOG_LEVEL, setExceptionReporter, setLogLevel } from './logger'
@@ -140,6 +141,7 @@ class AuthProvider {
loginList: logins,
mode: this.theme,
logo: this.logo.vertical,
+ options: this.params.connectOptions,
})
}
return new Promise((resolve, reject) => {
@@ -195,6 +197,10 @@ class AuthProvider {
if (await this.isLoggedIn()) {
return this._provider
}
+
+ if (!isEmail(email)) {
+ throw new Error('Invalid email')
+ }
await this._provider.initPasswordlessLogin(email)
if (emailSentHook) {
emailSentHook()
@@ -359,7 +365,7 @@ class AuthProvider {
if (this.connected) {
return resolve(this._provider)
}
- this._provider.on('connect', () => {
+ this._provider.once('connect', () => {
return resolve(this._provider)
})
})
diff --git a/src/typings.ts b/src/typings.ts
index 7d14b8b..33ef2eb 100644
--- a/src/typings.ts
+++ b/src/typings.ts
@@ -94,6 +94,7 @@ export interface UserInfo {
picture?: string
address: string
publicKey: string
+ loginToken: string
}
export type Logins =
| 'google'
@@ -198,6 +199,10 @@ export interface ChainConfigInput {
chainId: string
}
+export interface ConnectOptions {
+ compact: boolean
+}
+
export interface ConstructorParams {
network: ('testnet' | 'dev' | 'mainnet') | NetworkConfig
debug: boolean
@@ -208,6 +213,7 @@ export interface ConstructorParams {
position: Position
setWindowProvider: boolean
appMode?: AppMode
+ connectOptions: ConnectOptions
}
type RequestArguments = {
diff --git a/src/ui/components.tsx b/src/ui/components.tsx
index 364211c..7397f40 100644
--- a/src/ui/components.tsx
+++ b/src/ui/components.tsx
@@ -1,34 +1,41 @@
import { ARCANA_LOGO, getSocialLogo } from './icons'
-import { StateUpdater, useState } from 'preact/hooks'
+import { StateUpdater, useEffect, useState } from 'preact/hooks'
import { ModalParams } from './typings'
import { Theme } from '../typings'
import { JSXInternal } from 'preact/src/jsx'
+import isEmail from 'validator/es/lib/isEmail'
import ProgressOval from './loader'
import './style.css'
-const Header = ({ mode, logo }: { mode: Theme; logo: string }) => {
- const [renderLogoContainer, setRenderLogoContainer] = useState(true)
- const removeLogoContainer = () => {
- setRenderLogoContainer(false)
+const Header = ({ compact, logo }: { compact: boolean; logo: string }) => {
+ const [loaded, setLoaded] = useState(false)
+ const showLogoContainer = () => {
+ setLoaded(false)
}
return (
<>
- {renderLogoContainer && logo && (
-
-

+ {!loaded ?
: ''}
+
+

+
+ {!compact ? (
+
+
Welcome
+
+ We’ll email you a login link for a password-free sign in.
+
+ ) : (
+ ''
)}
-
-
Welcome
-
- We’ll email you a login link for a password-free sign in.
-
-
>
)
}
@@ -41,8 +48,10 @@ const EmailLogin = ({
email: string
setEmail: StateUpdater
} & Pick) => {
+ const [disabled, setDisabled] = useState(true)
const onInput: JSXInternal.GenericEventHandler = (e) => {
setEmail(e.currentTarget.value)
+ setDisabled(!isEmail(e.currentTarget.value))
}
const clickHandler = async (
@@ -55,19 +64,21 @@ const EmailLogin = ({
await loginWithLink(email)
return
}
+
+ useEffect(() => {
+ setDisabled(!isEmail(email))
+ }, [])
return (
)
@@ -109,7 +120,7 @@ const Footer = ({ mode }: { mode: Theme }) => {
const logo = ARCANA_LOGO[mode]
return (
@@ -120,6 +131,7 @@ const Loader = (props: {
text: string
children: preact.ComponentChildren
mode: Theme
+ compact: boolean
header?: JSXInternal.Element
}) => {
return (
@@ -127,7 +139,11 @@ const Loader = (props: {
{props.header ? (
props.header
) : (
-
+
)}
{props.text ? {props.text}
: ''}
{props.children ? <>{props.children}> : ''}
diff --git a/src/ui/loader.tsx b/src/ui/loader.tsx
index f0c4cc2..06308c1 100644
--- a/src/ui/loader.tsx
+++ b/src/ui/loader.tsx
@@ -4,15 +4,17 @@ interface LoaderProps {
stroke: number
secondaryColor: string
strokeColor?: string
+ compact: boolean
}
export default function Loader(props: LoaderProps) {
+ const width = props.compact ? 60 : 80;
const { stroke = 8, secondaryColor } = props
return (