From be899d15d3edb0f0bdd1aac372a0194e4689bd33 Mon Sep 17 00:00:00 2001 From: DanutIlie <42973343+DanutIlie@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:15:09 +0200 Subject: [PATCH] Enhance toast progress component (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enhance toast progress component * Updated toast styles * remove unused params * Updated animation * update changelog * Removed leftover console.log --------- Co-authored-by: Miro Mărgineanu --- CHANGELOG.md | 1 + src/components.d.ts | 8 +- .../transaction-toast-progress/readme.md | 8 +- .../transaction-toast-progress.css | 110 ++++++++++++++++-- .../transaction-toast-progress.tsx | 100 +++++++++++++--- .../transaction-toast/transaction-toast.tsx | 6 +- .../transaction-toast.type.ts | 4 +- 7 files changed, 197 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40d6acf..ec70519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [Enhance toast progress component](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/31) - [Added transactions table styling](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/30) - [Added react output config](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/29) - [Added Trim and CopyButton components](https://github.com/multiversx/mx-sdk-dapp-core-ui/pull/28) diff --git a/src/components.d.ts b/src/components.d.ts index 1a77dba..cdfb4b9 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -165,8 +165,8 @@ export namespace Components { "transactionClass"?: string; } interface TransactionToastProgress { - "currentRemaining"?: number; - "progressClass": string; + "endTime"?: number; + "startTime"?: number; } interface TransactionToastWrapper { "wrapperClass": string; @@ -669,8 +669,8 @@ declare namespace LocalJSX { "transactionClass"?: string; } interface TransactionToastProgress { - "currentRemaining"?: number; - "progressClass"?: string; + "endTime"?: number; + "startTime"?: number; } interface TransactionToastWrapper { "wrapperClass"?: string; diff --git a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/readme.md b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/readme.md index 29a0283..9b8992c 100644 --- a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/readme.md +++ b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/readme.md @@ -7,10 +7,10 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------ | ------------------- | ----------- | -------- | ------------------------------ | -| `currentRemaining` | `current-remaining` | | `number` | `undefined` | -| `progressClass` | `progress-class` | | `string` | `'transaction-toast-progress'` | +| Property | Attribute | Description | Type | Default | +| ----------- | ------------ | ----------- | -------- | ----------- | +| `endTime` | `end-time` | | `number` | `undefined` | +| `startTime` | `start-time` | | `number` | `undefined` | ## Dependencies diff --git a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.css b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.css index 06ba177..ac135b2 100644 --- a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.css +++ b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.css @@ -1,16 +1,108 @@ +@keyframes progressiveFixedWidthExpansion { + from { + width: min(var(--start-width, 0%), 80%); + } + + to { + width: 80%; + } +} + +@keyframes progressiveInfiniteWidthExpansion { + from { + width: min(var(--start-width, 0%), 100%); + } + + to { + width: 100%; + } +} + +@keyframes quickWidthExpansion { + from { + width: 0%; + } + + to { + width: 100%; + } +} + .transaction-toast-progress { position: relative; } -.transaction-toast-bar { +.transaction-toast-bar-wrapper { + transition: opacity 250ms ease-in; + background-color: lightgray; position: absolute; pointer-events: none; - left: -0.5rem; - right: -0.5rem; - bottom: -0.5rem; - top: -0.5rem; - background-color: gray; - opacity: 0.25; - transition: width 0.6s ease; - max-width: calc(100% + 1rem); + left: 0; + top: 0; + opacity: 25%; + bottom: 0; + right: 0; + display: flex; + overflow: hidden; + border-radius: 0.25rem; + flex-direction: row-reverse; +} + +.transaction-toast-bar { + height: 100%; + right: 0; + top: 0; + bottom: 0; +} + +.transaction-toast-bar.fixed { + width: min(var(--start-width, 0%), 50%); + background-color: white; + animation-name: progressiveFixedWidthExpansion; + animation-duration: var(--animation-duration, 6s); + animation-timing-function: cubic-bezier(0.5, 0.95, 0, 0.35); + animation-fill-mode: forwards; +} + +.transaction-toast-bar.infinite { + width: 20%; + display: flex; + flex-direction: row-reverse; +} + +.transaction-toast-bar.infinite .transaction-toast-bar-line { + width: 0%; + background-color: white; + animation-name: progressiveInfiniteWidthExpansion; + animation-duration: var(--animation-duration, 60s); + animation-timing-function: cubic-bezier(0.1, 0.95, 0.25, 0.75); + animation-fill-mode: forwards; + animation-delay: var(--animation-delay, 6s); + height: 100%; + position: relative; +} + +.transaction-toast-bar.infinite .transaction-toast-bar-line:before { + position: absolute; + background-color: white; + content: ''; + width: calc(4px / 2); + right: -1px; + top: 0; + bottom: 0; +} + +.transaction-toast-bar.fill { + width: 0%; + position: absolute; + background-color: white; +} + +.transaction-toast-bar.fill.animate { + animation: quickWidthExpansion 250ms linear forwards; +} + +.transaction-toast-bar-content { + z-index: 1; + position: relative; } diff --git a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.tsx b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.tsx index ff3458a..4ca07fa 100644 --- a/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.tsx +++ b/src/components/toasts-list/components/transaction-toast/components/transaction-toast-progress/transaction-toast-progress.tsx @@ -1,4 +1,7 @@ -import { Component, h,Prop } from '@stencil/core'; +import { Component, Fragment, Prop, State, Watch, h } from '@stencil/core'; +import classNames from 'classnames'; + +const DEFAULT_INFINITE_ANIMATION_DURATION = 30; @Component({ tag: 'transaction-toast-progress', @@ -6,26 +9,89 @@ import { Component, h,Prop } from '@stencil/core'; shadow: true, }) export class ToastProgress { - @Prop() progressClass: string = 'transaction-toast-progress'; - @Prop() currentRemaining?: number; + private timeElapsedTimeoutReference?: ReturnType; - render() { - if (!this.currentRemaining) { - return ; + @Prop() startTime?: number; + @Prop() endTime?: number; + + @State() currentTimestamp: number = Date.now() / 1000; + @State() hasTimeElapsed: boolean = false; + @State() expectedTransactionDuration: number = 0; + @State() secondsPassedSinceStart: number = 0; + @State() shouldShowProgressBar: boolean = false; + @State() percentagePassedSinceStart: number = 0; + @State() shouldQuickFill: boolean = false; + @State() infiniteProgressDelay: number = 0; + @State() infinitePercentagePassedSinceStart: number = 0; + @State() infinitePercentageAnimationDuration: number = DEFAULT_INFINITE_ANIMATION_DURATION + (this.endTime - this.startTime) * 2; + + componentWillLoad() { + this.updateProgress(); + } + + @Watch('startTime') + @Watch('endTime') + handleTimeChange() { + this.updateProgress(); + } + + private updateProgress() { + this.shouldShowProgressBar = Boolean(this.endTime) && Boolean(this.startTime); + + if (!this.shouldShowProgressBar) { + this.shouldQuickFill = true; + this.timeElapsedTimeoutReference = setTimeout(() => (this.hasTimeElapsed = true), 500); + return; } + this.currentTimestamp = Date.now() / 1000; + this.expectedTransactionDuration = this.endTime - this.startTime; + this.secondsPassedSinceStart = this.currentTimestamp - this.startTime; + this.percentagePassedSinceStart = this.expectedTransactionDuration > 0 ? (this.secondsPassedSinceStart / this.expectedTransactionDuration) * 100 : 0; + this.infiniteProgressDelay = Math.max(0, this.expectedTransactionDuration - this.secondsPassedSinceStart); + this.infinitePercentagePassedSinceStart = (this.secondsPassedSinceStart / (this.expectedTransactionDuration + this.infinitePercentageAnimationDuration)) * 100; + } + + disconnectedCallback() { + if (this.timeElapsedTimeoutReference) { + clearTimeout(this.timeElapsedTimeoutReference); + } + } + + render() { return ( -
-
- -
+ +
+
+ +
+
+
+ +
+
+ +
+ +
+ ); } } diff --git a/src/components/toasts-list/components/transaction-toast/transaction-toast.tsx b/src/components/toasts-list/components/transaction-toast/transaction-toast.tsx index e6f67f0..efd4500 100644 --- a/src/components/toasts-list/components/transaction-toast/transaction-toast.tsx +++ b/src/components/toasts-list/components/transaction-toast/transaction-toast.tsx @@ -22,11 +22,7 @@ export class TransactionToast { render() { return ( - + this.handleDeleteToast.emit(this.toastId)} processedTransactionsStatus={this.processedTransactionsStatus} diff --git a/src/components/toasts-list/components/transaction-toast/transaction-toast.type.ts b/src/components/toasts-list/components/transaction-toast/transaction-toast.type.ts index 6a7cf9e..0547d0c 100644 --- a/src/components/toasts-list/components/transaction-toast/transaction-toast.type.ts +++ b/src/components/toasts-list/components/transaction-toast/transaction-toast.type.ts @@ -12,7 +12,9 @@ export interface IToastDataState { export interface ITransactionProgressState { progressClass?: string; - currentRemaining: number; + startTime: number; + endTime: number; + isCrossShard: boolean; } export interface ITransaction {