Skip to content

Commit

Permalink
refactor: improvements to siwe flow and modal animations (#2672)
Browse files Browse the repository at this point in the history
  • Loading branch information
enesozturk authored Aug 9, 2024
1 parent a6e707e commit e522f82
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 118 deletions.
14 changes: 13 additions & 1 deletion packages/core/src/controllers/ModalController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { RouterController } from './RouterController.js'
export interface ModalControllerState {
loading: boolean
open: boolean
shake: boolean
}

export interface ModalControllerArguments {
Expand All @@ -24,7 +25,8 @@ type StateKey = keyof ModalControllerState
// -- State --------------------------------------------- //
const state = proxy<ModalControllerState>({
loading: false,
open: false
open: false,
shake: false
})

// -- Controller ---------------------------------------- //
Expand Down Expand Up @@ -72,5 +74,15 @@ export const ModalController = {
setLoading(loading: ModalControllerState['loading']) {
state.loading = loading
PublicStateController.set({ loading })
},

shake() {
if (state.shake) {
return
}
state.shake = true
setTimeout(() => {
state.shake = false
}, 500)
}
}
38 changes: 24 additions & 14 deletions packages/scaffold-ui/src/modal/w3m-modal/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
AccountController,
ApiController,
ConnectionController,
CoreHelperUtil,
EventsController,
ModalController,
Expand Down Expand Up @@ -39,19 +38,24 @@ export class W3mModal extends LitElement {

@state() private loading = ModalController.state.loading

@state() private shake = ModalController.state.shake

public constructor() {
super()
this.initializeTheming()
ApiController.prefetch()
this.unsubscribe.push(
ModalController.subscribeKey('open', val => (val ? this.onOpen() : this.onClose())),
ModalController.subscribeKey('loading', val => {
this.loading = val
this.onNewAddress(AccountController.state.caipAddress)
}),
AccountController.subscribeKey('isConnected', val => (this.connected = val)),
AccountController.subscribeKey('caipAddress', val => this.onNewAddress(val)),
OptionsController.subscribeKey('isSiweEnabled', val => (this.isSiweEnabled = val))
...[
ModalController.subscribeKey('open', val => (val ? this.onOpen() : this.onClose())),
ModalController.subscribeKey('shake', val => (this.shake = val)),
ModalController.subscribeKey('loading', val => {
this.loading = val
this.onNewAddress(AccountController.state.caipAddress)
}),
AccountController.subscribeKey('isConnected', val => (this.connected = val)),
AccountController.subscribeKey('caipAddress', val => this.onNewAddress(val)),
OptionsController.subscribeKey('isSiweEnabled', val => (this.isSiweEnabled = val))
]
)
EventsController.sendEvent({ type: 'track', event: 'MODAL_LOADED' })
}
Expand All @@ -66,7 +70,7 @@ export class W3mModal extends LitElement {
return this.open
? html`
<wui-flex @click=${this.onOverlayClick.bind(this)}>
<wui-card role="alertdialog" aria-modal="true" tabindex="0">
<wui-card shake="${this.shake}" role="alertdialog" aria-modal="true" tabindex="0">
<w3m-header></w3m-header>
<w3m-router></w3m-router>
<w3m-snackbar></w3m-snackbar>
Expand All @@ -85,14 +89,20 @@ export class W3mModal extends LitElement {
}

private async handleClose() {
const isSiweSignScreen = RouterController.state.view === 'ConnectingSiwe'
const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction'

if (this.isSiweEnabled) {
const { SIWEController } = await import('@web3modal/siwe')

if (SIWEController.state.status !== 'success' && this.connected) {
await ConnectionController.disconnect()
const isUnauthenticated = SIWEController.state.status !== 'success'
if (isUnauthenticated && (isSiweSignScreen || isApproveSignScreen)) {
ModalController.shake()
} else {
ModalController.close()
}
} else {
ModalController.close()
}
ModalController.close()
}

private initializeTheming() {
Expand Down
84 changes: 62 additions & 22 deletions packages/scaffold-ui/src/modal/w3m-modal/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,21 @@ export default css`
opacity: 1;
}
@keyframes zoom-in {
0% {
transform: scale(0.95) translateY(0);
}
100% {
transform: scale(1) translateY(0);
}
}
@keyframes slide-in {
0% {
transform: scale(1) translateY(50px);
}
100% {
transform: scale(1) translateY(0);
}
}
wui-card {
max-width: var(--w3m-modal-width);
width: 100%;
position: relative;
animation-duration: 0.2s;
animation-name: zoom-in;
animation: zoom-in 0.2s var(--wui-ease-out-power-2);
animation-fill-mode: backwards;
animation-timing-function: var(--wui-ease-out-power-2);
outline: none;
}
wui-card[shake='true'] {
animation:
zoom-in 0.2s var(--wui-ease-out-power-2),
w3m-shake 0.5s var(--wui-ease-out-power-2);
}
wui-flex {
overflow-x: hidden;
overflow-y: auto;
Expand Down Expand Up @@ -81,7 +67,61 @@ export default css`
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: none;
animation-name: slide-in;
animation: slide-in 0.2s var(--wui-ease-out-power-2);
}
wui-card[shake='true'] {
animation:
slide-in 0.2s var(--wui-ease-out-power-2),
w3m-shake 0.5s var(--wui-ease-out-power-2);
}
}
@keyframes zoom-in {
0% {
transform: scale(0.95) translateY(0);
}
100% {
transform: scale(1) translateY(0);
}
}
@keyframes slide-in {
0% {
transform: scale(1) translateY(50px);
}
100% {
transform: scale(1) translateY(0);
}
}
@keyframes w3m-shake {
0% {
transform: scale(1) rotate(0deg);
}
20% {
transform: scale(1) rotate(-1deg);
}
40% {
transform: scale(1) rotate(1.5deg);
}
60% {
transform: scale(1) rotate(-1.5deg);
}
80% {
transform: scale(1) rotate(1deg);
}
100% {
transform: scale(1) rotate(0deg);
}
}
@keyframes w3m-view-height {
from {
height: var(--prev-height);
}
to {
height: var(--new-height);
}
}
`
50 changes: 22 additions & 28 deletions packages/scaffold-ui/src/modal/w3m-router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { customElement } from '@web3modal/ui'
import { LitElement, html } from 'lit'
import { state } from 'lit/decorators.js'
import styles from './styles.js'
import { ConstantsUtil } from '../../utils/ConstantsUtil.js'

@customElement('w3m-router')
export class W3mRouter extends LitElement {
Expand All @@ -21,23 +22,26 @@ export class W3mRouter extends LitElement {
// -- State & Properties -------------------------------- //
@state() private view = RouterController.state.view

@state() private viewDirection = ''

public constructor() {
super()
this.unsubscribe.push(RouterController.subscribeKey('view', val => this.onViewChange(val)))
}

public override firstUpdated() {
this.resizeObserver = new ResizeObserver(async ([content]) => {
this.resizeObserver = new ResizeObserver(([content]) => {
const height = `${content?.contentRect.height}px`
if (this.prevHeight !== '0px') {
await this.animate([{ height: this.prevHeight }, { height }], {
duration: 150,
easing: 'ease',
fill: 'forwards'
}).finished
this.style.setProperty('--prev-height', this.prevHeight)
this.style.setProperty('--new-height', height)
this.style.animation = 'w3m-view-height 150ms forwards ease'
this.style.height = 'auto'
}
this.prevHeight = height
setTimeout(() => {
this.prevHeight = height
this.style.animation = 'unset'
}, ConstantsUtil.ANIMATION_DURATIONS.ModalHeight)
})
this.resizeObserver.observe(this.getWrapper())
}
Expand All @@ -49,7 +53,9 @@ export class W3mRouter extends LitElement {

// -- Render -------------------------------------------- //
public override render() {
return html`<div>${this.viewTemplate()}</div>`
return html`<div class="w3m-router-container" view-direction="${this.viewDirection}">
${this.viewTemplate()}
</div>`
}

// -- Private ------------------------------------------- //
Expand Down Expand Up @@ -154,33 +160,21 @@ export class W3mRouter extends LitElement {
}
}

private async onViewChange(newView: RouterControllerState['view']) {
private onViewChange(newView: RouterControllerState['view']) {
TooltipController.hide()

let direction = ConstantsUtil.VIEW_DIRECTION.Next
const { history } = RouterController.state
let xOut = -10
let xIn = 10
if (history.length < this.prevHistoryLength) {
xOut = 10
xIn = -10
direction = ConstantsUtil.VIEW_DIRECTION.Prev
}

this.prevHistoryLength = history.length
await this.animate(
[
{ opacity: 1, transform: 'translateX(0px)' },
{ opacity: 0, transform: `translateX(${xOut}px)` }
],
{ duration: 150, easing: 'ease', fill: 'forwards' }
).finished
this.view = newView
await this.animate(
[
{ opacity: 0, transform: `translateX(${xIn}px)` },
{ opacity: 1, transform: 'translateX(0px)' }
],
{ duration: 150, easing: 'ease', fill: 'forwards', delay: 50 }
).finished
this.viewDirection = direction

setTimeout(() => {
this.view = newView
}, ConstantsUtil.ANIMATION_DURATIONS.ViewTransition)
}

private getWrapper() {
Expand Down
66 changes: 65 additions & 1 deletion packages/scaffold-ui/src/modal/w3m-router/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,71 @@ import { css } from 'lit'

export default css`
:host {
--prev-height: 0px;
--new-height: 0px;
display: block;
will-change: transform, opacity;
}
div.w3m-router-container {
transform: translateY(0);
opacity: 1;
}
div.w3m-router-container[view-direction='prev'] {
animation:
slide-left-out 150ms forwards ease,
slide-left-in 150ms forwards ease;
animation-delay: 0ms, 200ms;
}
div.w3m-router-container[view-direction='next'] {
animation:
slide-right-out 150ms forwards ease,
slide-right-in 150ms forwards ease;
animation-delay: 0ms, 200ms;
}
@keyframes slide-left-out {
from {
transform: translateX(0px);
opacity: 1;
}
to {
transform: translateX(10px);
opacity: 0;
}
}
@keyframes slide-left-in {
from {
transform: translateX(-10px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slide-right-out {
from {
transform: translateX(0px);
opacity: 1;
}
to {
transform: translateX(-10px);
opacity: 0;
}
}
@keyframes slide-right-in {
from {
transform: translateX(10px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
`
Loading

0 comments on commit e522f82

Please sign in to comment.