diff --git a/packages/widget/src/components/index.ts b/packages/widget/src/components/index.ts index 26e08c8a..69275e32 100644 --- a/packages/widget/src/components/index.ts +++ b/packages/widget/src/components/index.ts @@ -1,4 +1,5 @@ export { AmountSelector } from './amount-selector'; export { NetworkSelector } from './network-selector'; +export { OverlayComponent } from './overlay-component'; export { ConnectWalletButton } from './buttons'; export { AddressInput } from './address-input'; diff --git a/packages/widget/src/components/overlay-component/index.ts b/packages/widget/src/components/overlay-component/index.ts new file mode 100644 index 00000000..98171cbb --- /dev/null +++ b/packages/widget/src/components/overlay-component/index.ts @@ -0,0 +1 @@ +export { OverlayComponent } from './overlay-component'; diff --git a/packages/widget/src/components/overlay-component/overlay-component.ts b/packages/widget/src/components/overlay-component/overlay-component.ts new file mode 100644 index 00000000..4ecc9259 --- /dev/null +++ b/packages/widget/src/components/overlay-component/overlay-component.ts @@ -0,0 +1,22 @@ +import { html } from 'lit'; +import type { HTMLTemplateResult } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import { BaseComponent } from '../base-component/base-component'; +import { styles } from './styles'; + +@customElement('sygma-overlay-component') +export class OverlayComponent extends BaseComponent { + static styles = styles; + + render(): HTMLTemplateResult { + return html`
+
+
`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'sygma-overlay-component': OverlayComponent; + } +} diff --git a/packages/widget/src/components/overlay-component/styles.ts b/packages/widget/src/components/overlay-component/styles.ts new file mode 100644 index 00000000..0be7c086 --- /dev/null +++ b/packages/widget/src/components/overlay-component/styles.ts @@ -0,0 +1,35 @@ +import { css } from 'lit'; + +export const styles = css` + .overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: rgba(255, 255, 255, 0.7); + border-radius: 0.75rem; + } + + .loadingSpinner { + border: 0.25rem solid var(--blue-600); + border-top: 0.25rem solid var(--white); + border-radius: 50%; + width: 4rem; + height: 4rem; + animation: spin 1s linear infinite; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } +`; diff --git a/packages/widget/src/controllers/widget.ts b/packages/widget/src/controllers/widget.ts index cacdc0a8..6621ea7e 100644 --- a/packages/widget/src/controllers/widget.ts +++ b/packages/widget/src/controllers/widget.ts @@ -9,7 +9,7 @@ import { SubstrateAssetTransfer } from '@buildwithsygma/sygma-sdk-core/substrate import type { ReactiveController, ReactiveElement } from 'lit'; export class WidgetController implements ReactiveController { - public isLoading: boolean = false; + public isLoading: boolean; public isReadyForTransfer: boolean = false; public sourceNetwork?: Domain; public destinationNetwork?: Domain; @@ -32,11 +32,13 @@ export class WidgetController implements ReactiveController { host: ReactiveElement, options: { env?: Environment; + isLoading?: boolean; } ) { (this.host = host).addController(this); this.env = options.env ?? Environment.MAINNET; this.config = new Config(); + this.isLoading = options.isLoading ?? false; } hostConnected(): void { diff --git a/packages/widget/src/styles.ts b/packages/widget/src/styles.ts index f5ac17d1..6bd59b3e 100644 --- a/packages/widget/src/styles.ts +++ b/packages/widget/src/styles.ts @@ -22,10 +22,10 @@ export const styles = css` } .widgetContainer { + position: relative; display: flex; flex-direction: column; align-items: stretch; - gap: 16px; padding: 24px; width: 21.875rem; /* TODO: remove these hardcoded values */ @@ -40,6 +40,14 @@ export const styles = css` font-family: Inter, sans-serif; } + .noPointerEvents { + pointer-events: none; + } + + .networkSelectionWrapper { + margin: 1rem 0 0.5rem 0; + } + .widgetHeader { display: flex; justify-content: space-between; diff --git a/packages/widget/src/widget.ts b/packages/widget/src/widget.ts index cc15a830..cceb34b3 100644 --- a/packages/widget/src/widget.ts +++ b/packages/widget/src/widget.ts @@ -1,6 +1,7 @@ import type { HTMLTemplateResult } from 'lit'; import { html } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; +import { when } from 'lit/directives/when.js'; import { sygmaLogo } from './assets'; import './components'; import { Directions } from './components/network-selector/network-selector'; @@ -13,6 +14,9 @@ import { BaseComponent } from './components/base-component/base-component'; class SygmaProtocolWidget extends BaseComponent { static styles = styles; + @state() + private isLoading = false; + private widgetController = new WidgetController(this, {}); private renderConnect(): HTMLTemplateResult { @@ -29,7 +33,9 @@ class SygmaProtocolWidget extends BaseComponent { render(): HTMLTemplateResult { return html` -
+
[Brand] Transfer
${this.renderConnect()} @@ -89,6 +95,10 @@ class SygmaProtocolWidget extends BaseComponent {
${sygmaLogo} Powered by Sygma
+ ${when( + this.isLoading, + () => html`` + )}
`; diff --git a/packages/widget/tests/unit/components/overlay-component/overlay-component.test.ts b/packages/widget/tests/unit/components/overlay-component/overlay-component.test.ts new file mode 100644 index 00000000..e670e693 --- /dev/null +++ b/packages/widget/tests/unit/components/overlay-component/overlay-component.test.ts @@ -0,0 +1,25 @@ +import { afterEach, assert, describe, it } from 'vitest'; +import { fixture, fixtureCleanup } from '@open-wc/testing-helpers'; +import { html } from 'lit'; +import { OverlayComponent } from '../../../../src/components'; + +describe('loader-component', function () { + afterEach(() => { + fixtureCleanup(); + }); + + it('is defined', () => { + const el = document.createElement('sygma-overlay-component'); + assert.instanceOf(el, OverlayComponent); + }); + + it('renders loader', async () => { + const el = await fixture(html` + + `); + + const overlay = el.shadowRoot!.querySelector('.overlay') as HTMLElement; + + assert.isNotNull(overlay); + }); +});