Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

- [Added skip tests if PR is in draft](https://github.com/multiversx/mx-sdk-dapp-ui/pull/265)
- [Refactored unlock panel components](https://github.com/multiversx/mx-sdk-dapp-ui/pull/255)
- [Added github release on publish](https://github.com/multiversx/mx-sdk-dapp-ui/pull/264)

## [[0.1.2](https://github.com/multiversx/mx-sdk-dapp-ui/pull/263)] - 2025-11-06
Expand Down
97 changes: 75 additions & 22 deletions src/common/Trim/Trim.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export function Trim({
let currentTrimFontSize = '1rem';
let trimFullElement: HTMLDivElement;
let trimWrapperElement: HTMLDivElement;
let isCurrentlyOverflowing: boolean | null = null;
let isCheckingOverflow = false;

const handleTrimElementReference = (element: HTMLDivElement) => {
if (element) {
Expand Down Expand Up @@ -64,43 +66,94 @@ export function Trim({
}

const checkOverflow = () => {
if (!fullWidthUntrimmedElementReference || !trimElementReference || !trimFullElement || !trimWrapperElement) {
if (isCheckingOverflow) {
return;
}

const hiddenFullWidthElementWidth = fullWidthUntrimmedElementReference.scrollWidth;
const trimmedElementWidth = trimElementReference.clientWidth;
const isTrimElementOverflowing = hiddenFullWidthElementWidth > trimmedElementWidth;

if (safeWindow) {
currentTrimFontSize = safeWindow.getComputedStyle(trimElementReference).fontSize;
if (!fullWidthUntrimmedElementReference || !trimElementReference || !trimFullElement || !trimWrapperElement) {
return;
}

const getIdentifierClass = (classes: string) => classes.split(' ')[0];

const trimLeftSelector = `.${getIdentifierClass(styles.trimLeft)}`;
const trimRightSelector = `.${getIdentifierClass(styles.trimRight)}`;
isCheckingOverflow = true;

const trimLeftElement = trimElementReference.querySelector(trimLeftSelector) as HTMLElement;
const trimRightElement = trimElementReference.querySelector(trimRightSelector) as HTMLElement;
if (trimLeftElement) {
trimLeftElement.style.fontSize = currentTrimFontSize;
if (resizeObserver) {
resizeObserver.disconnect();
}

if (trimRightElement) {
trimRightElement.style.fontSize = currentTrimFontSize;
}

const getIdentifierClass = (classes: string) => classes.split(' ')[0];

const trimFullVisibleClasses = styles.trimFullVisible.split(/\s+/);
const trimWrapperVisibleClasses = styles.trimWrapperVisible.split(/\s+/);

if (isTrimElementOverflowing) {
const hasFullVisible = trimFullElement.classList.contains(getIdentifierClass(styles.trimFullVisible));
const hasWrapperVisible = trimWrapperElement.classList.contains(getIdentifierClass(styles.trimWrapperVisible));

if (hasFullVisible) {
trimFullElement.classList.remove(...trimFullVisibleClasses);
trimWrapperElement.classList.add(...trimWrapperVisibleClasses);
} else {
trimFullElement.classList.add(...trimFullVisibleClasses);
}
if (hasWrapperVisible) {
trimWrapperElement.classList.remove(...trimWrapperVisibleClasses);
}

const hiddenFullWidthElementWidth = fullWidthUntrimmedElementReference.scrollWidth;
const trimmedElementWidth = trimElementReference.clientWidth;
const isTrimElementOverflowing = hiddenFullWidthElementWidth > trimmedElementWidth;

if (isCurrentlyOverflowing === isTrimElementOverflowing) {
if (hasFullVisible) {
trimFullElement.classList.add(...trimFullVisibleClasses);
}
if (hasWrapperVisible) {
trimWrapperElement.classList.add(...trimWrapperVisibleClasses);
}

isCheckingOverflow = false;

setTimeout(() => {
if (resizeObserver && trimElementReference) {
resizeObserver.observe(trimElementReference);
}
});
return;
}

isCurrentlyOverflowing = isTrimElementOverflowing;

requestAnimationFrame(() => {
if (safeWindow) {
currentTrimFontSize = safeWindow.getComputedStyle(trimElementReference).fontSize;
}

const trimLeftSelector = `.${getIdentifierClass(styles.trimLeft)}`;
const trimRightSelector = `.${getIdentifierClass(styles.trimRight)}`;

const trimLeftElement = trimElementReference.querySelector(trimLeftSelector) as HTMLElement;
const trimRightElement = trimElementReference.querySelector(trimRightSelector) as HTMLElement;
if (trimLeftElement) {
trimLeftElement.style.fontSize = currentTrimFontSize;
}

if (trimRightElement) {
trimRightElement.style.fontSize = currentTrimFontSize;
}

if (isTrimElementOverflowing) {
trimFullElement.classList.remove(...trimFullVisibleClasses);
trimWrapperElement.classList.add(...trimWrapperVisibleClasses);
} else {
trimFullElement.classList.add(...trimFullVisibleClasses);
trimWrapperElement.classList.remove(...trimWrapperVisibleClasses);
}

isCheckingOverflow = false;

requestAnimationFrame(() => {
if (resizeObserver && trimElementReference) {
resizeObserver.observe(trimElementReference);
}
});
});
};

const middleTextIndex = Math.floor(text.length / 2);
Expand Down
12 changes: 1 addition & 11 deletions src/common/UnlockButton/UnlockButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,7 @@ import { safeWindow } from 'constants/window.constants';
import type { IProviderBase } from 'types/provider.types';
import { ProviderTypeEnum } from 'types/provider.types';
import { getDetectedBrowser } from 'utils/getDetectedBrowser';

// prettier-ignore
const styles = {
unlockButton: 'unlock-button mvx:pl-3 mvx:pr-4 mvx:h-15 mvx:flex! mvx:gap-4 mvx:cursor-pointer mvx:items-center mvx:transition-all mvx:duration-200 mvx:ease-in-out mvx:bg-secondary mvx:hover:bg-hover',
unlockButtonIcon: 'unlock-button-icon mvx:-order-1 mvx:h-10 mvx:flex mvx:relative mvx:z-1 mvx:items-center mvx:justify-center mvx:w-10',
unlockButtonIconClipped: 'mvx:items-end mvx:justify-start',
unlockButtonLabel: 'unlock-button-label mvx:text-base mvx:relative mvx:z-1 mvx:text-primary mvx:leading-none',
unlockButtonStatus: 'unlock-button-status mvx:ml-auto mvx:relative mvx:rounded-3xl mvx:z-1 mvx:leading-none mvx:flex mvx:items-center mvx:py-1 mvx:px-2 mvx:font-medium mvx:gap-1 mvx:text-xs mvx:bg-surface mvx:border mvx:border-solid mvx:border-outline',
unlockButtonStatusText: 'unlock-button-status-text mvx:text-accent',
unlockButtonStatusIcon: 'unlock-button-status-icon mvx:flex mvx:items-center mvx:text-accent mvx:w-2.5 mvx:h-2.5',
} satisfies Record<string, string>;
import styles from './unlockButton.styles';

interface UnlockButtonPropsType {
label: string;
Expand Down
10 changes: 10 additions & 0 deletions src/common/UnlockButton/unlockButton.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// prettier-ignore
export default {
unlockButton: 'unlock-button mvx:pl-3 mvx:pr-4 mvx:h-15 mvx:flex mvx:gap-4 mvx:cursor-pointer mvx:items-center mvx:transition-all mvx:duration-200 mvx:ease-in-out mvx:bg-secondary mvx:hover:bg-hover',
unlockButtonIcon: 'unlock-button-icon mvx:-order-1 mvx:h-10 mvx:flex mvx:relative mvx:z-1 mvx:items-center mvx:justify-center mvx:w-10',
unlockButtonIconClipped: 'mvx:items-end mvx:justify-start',
unlockButtonLabel: 'unlock-button-label mvx:text-base mvx:relative mvx:z-1 mvx:text-primary mvx:leading-none',
unlockButtonStatus: 'unlock-button-status mvx:ml-auto mvx:relative mvx:rounded-3xl mvx:z-1 mvx:leading-none mvx:flex mvx:items-center mvx:py-1 mvx:px-2 mvx:font-medium mvx:gap-1 mvx:text-xs mvx:bg-surface mvx:border mvx:border-solid mvx:border-outline',
unlockButtonStatusText: 'unlock-button-status-text mvx:text-accent',
unlockButtonStatusIcon: 'unlock-button-status-icon mvx:flex mvx:items-center mvx:text-accent mvx:w-2.5 mvx:h-2.5',
} satisfies Record<string, string>;
75 changes: 2 additions & 73 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ITransactionListItem as ITransactionListItem1 } from "./components/visu
import { IToastDataState, ITransactionProgressState } from "./components/functional/toasts-list/components/transaction-toast/transaction-toast.type";
import { TransactionStatusEnum } from "./constants/transactionStatus.enum";
import { TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type";
import { IProviderBase, ProviderTypeEnum } from "./types/provider.types";
import { IProviderBase } from "./types/provider.types";
import { IEventBus as IEventBus1, unknown as IWalletConnectPanelData } from "./components.d";
export { IAddressTableData } from "./types/address-table.types";
export { ButtonSizeEnum, ButtonVariantEnum } from "./components/visual/button/button.types";
Expand All @@ -31,7 +31,7 @@ export { ITransactionListItem as ITransactionListItem1 } from "./components/visu
export { IToastDataState, ITransactionProgressState } from "./components/functional/toasts-list/components/transaction-toast/transaction-toast.type";
export { TransactionStatusEnum } from "./constants/transactionStatus.enum";
export { TransactionRowType } from "./components/controlled/transactions-table/transactions-table.type";
export { IProviderBase, ProviderTypeEnum } from "./types/provider.types";
export { IProviderBase } from "./types/provider.types";
export { IEventBus as IEventBus1, unknown as IWalletConnectPanelData } from "./components.d";
export namespace Components {
interface MvxAddressTable {
Expand Down Expand Up @@ -397,20 +397,6 @@ export namespace Components {
"closeWithAnimation": () => Promise<unknown>;
"getEventBus": () => Promise<IEventBus>;
}
interface MvxUnlockPanelFooter {
"walletAddress": string;
}
interface MvxUnlockPanelGroup {
"class"?: string;
/**
* @default []
*/
"providers": IProviderBase[];
}
interface MvxUnlockProviderButton {
"class"?: string;
"provider": IProviderBase<ProviderTypeEnum>;
}
interface MvxWalletConnect {
/**
* @default { wcURI: '' }
Expand Down Expand Up @@ -514,10 +500,6 @@ export interface MvxTransactionToastContentCustomEvent<T> extends CustomEvent<T>
detail: T;
target: HTMLMvxTransactionToastContentElement;
}
export interface MvxUnlockPanelGroupCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLMvxUnlockPanelGroupElement;
}
export interface MvxWalletConnectScanCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLMvxWalletConnectScanElement;
Expand Down Expand Up @@ -1024,35 +1006,6 @@ declare global {
prototype: HTMLMvxUnlockPanelElement;
new (): HTMLMvxUnlockPanelElement;
};
interface HTMLMvxUnlockPanelFooterElement extends Components.MvxUnlockPanelFooter, HTMLStencilElement {
}
var HTMLMvxUnlockPanelFooterElement: {
prototype: HTMLMvxUnlockPanelFooterElement;
new (): HTMLMvxUnlockPanelFooterElement;
};
interface HTMLMvxUnlockPanelGroupElementEventMap {
"login": IProviderBase;
}
interface HTMLMvxUnlockPanelGroupElement extends Components.MvxUnlockPanelGroup, HTMLStencilElement {
addEventListener<K extends keyof HTMLMvxUnlockPanelGroupElementEventMap>(type: K, listener: (this: HTMLMvxUnlockPanelGroupElement, ev: MvxUnlockPanelGroupCustomEvent<HTMLMvxUnlockPanelGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLMvxUnlockPanelGroupElementEventMap>(type: K, listener: (this: HTMLMvxUnlockPanelGroupElement, ev: MvxUnlockPanelGroupCustomEvent<HTMLMvxUnlockPanelGroupElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLMvxUnlockPanelGroupElement: {
prototype: HTMLMvxUnlockPanelGroupElement;
new (): HTMLMvxUnlockPanelGroupElement;
};
interface HTMLMvxUnlockProviderButtonElement extends Components.MvxUnlockProviderButton, HTMLStencilElement {
}
var HTMLMvxUnlockProviderButtonElement: {
prototype: HTMLMvxUnlockProviderButtonElement;
new (): HTMLMvxUnlockProviderButtonElement;
};
interface HTMLMvxWalletConnectElement extends Components.MvxWalletConnect, HTMLStencilElement {
}
var HTMLMvxWalletConnectElement: {
Expand Down Expand Up @@ -1176,9 +1129,6 @@ declare global {
"mvx-trim": HTMLMvxTrimElement;
"mvx-unlock-button": HTMLMvxUnlockButtonElement;
"mvx-unlock-panel": HTMLMvxUnlockPanelElement;
"mvx-unlock-panel-footer": HTMLMvxUnlockPanelFooterElement;
"mvx-unlock-panel-group": HTMLMvxUnlockPanelGroupElement;
"mvx-unlock-provider-button": HTMLMvxUnlockProviderButtonElement;
"mvx-wallet-connect": HTMLMvxWalletConnectElement;
"mvx-wallet-connect-app-gallery-icon": HTMLMvxWalletConnectAppGalleryIconElement;
"mvx-wallet-connect-app-store-icon": HTMLMvxWalletConnectAppStoreIconElement;
Expand Down Expand Up @@ -1561,21 +1511,6 @@ declare namespace LocalJSX {
}
interface MvxUnlockPanel {
}
interface MvxUnlockPanelFooter {
"walletAddress"?: string;
}
interface MvxUnlockPanelGroup {
"class"?: string;
"onLogin"?: (event: MvxUnlockPanelGroupCustomEvent<IProviderBase>) => void;
/**
* @default []
*/
"providers"?: IProviderBase[];
}
interface MvxUnlockProviderButton {
"class"?: string;
"provider"?: IProviderBase<ProviderTypeEnum>;
}
interface MvxWalletConnect {
/**
* @default { wcURI: '' }
Expand Down Expand Up @@ -1680,9 +1615,6 @@ declare namespace LocalJSX {
"mvx-trim": MvxTrim;
"mvx-unlock-button": MvxUnlockButton;
"mvx-unlock-panel": MvxUnlockPanel;
"mvx-unlock-panel-footer": MvxUnlockPanelFooter;
"mvx-unlock-panel-group": MvxUnlockPanelGroup;
"mvx-unlock-provider-button": MvxUnlockProviderButton;
"mvx-wallet-connect": MvxWalletConnect;
"mvx-wallet-connect-app-gallery-icon": MvxWalletConnectAppGalleryIcon;
"mvx-wallet-connect-app-store-icon": MvxWalletConnectAppStoreIcon;
Expand Down Expand Up @@ -1755,9 +1687,6 @@ declare module "@stencil/core" {
"mvx-trim": LocalJSX.MvxTrim & JSXBase.HTMLAttributes<HTMLMvxTrimElement>;
"mvx-unlock-button": LocalJSX.MvxUnlockButton & JSXBase.HTMLAttributes<HTMLMvxUnlockButtonElement>;
"mvx-unlock-panel": LocalJSX.MvxUnlockPanel & JSXBase.HTMLAttributes<HTMLMvxUnlockPanelElement>;
"mvx-unlock-panel-footer": LocalJSX.MvxUnlockPanelFooter & JSXBase.HTMLAttributes<HTMLMvxUnlockPanelFooterElement>;
"mvx-unlock-panel-group": LocalJSX.MvxUnlockPanelGroup & JSXBase.HTMLAttributes<HTMLMvxUnlockPanelGroupElement>;
"mvx-unlock-provider-button": LocalJSX.MvxUnlockProviderButton & JSXBase.HTMLAttributes<HTMLMvxUnlockProviderButtonElement>;
"mvx-wallet-connect": LocalJSX.MvxWalletConnect & JSXBase.HTMLAttributes<HTMLMvxWalletConnectElement>;
"mvx-wallet-connect-app-gallery-icon": LocalJSX.MvxWalletConnectAppGalleryIcon & JSXBase.HTMLAttributes<HTMLMvxWalletConnectAppGalleryIconElement>;
"mvx-wallet-connect-app-store-icon": LocalJSX.MvxWalletConnectAppStoreIcon & JSXBase.HTMLAttributes<HTMLMvxWalletConnectAppStoreIconElement>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { h } from '@stencil/core';
import { Icon } from 'common/Icon';
import styles from './unlockPanelFooter.styles'

import unlockPanelWalletImg from '../../../../../assets/unlock-panel-wallet.webp';

export function UnlockPanelFooter({ walletAddress }: { walletAddress: string }) {
const handleWalletClick = (event: MouseEvent) => {
event.preventDefault();
event.stopPropagation();
window.open(walletAddress, '_blank');
};

const noProtocolWalletAddress = String(walletAddress).replace('https://', '');

return (
<div class={styles.unlockPanelFooter} onClick={handleWalletClick}>
<img src={unlockPanelWalletImg} class={styles.unlockPanelFooterImage} />

<div class={styles.unlockPanelFooterWrapper}>
<div class={styles.unlockPanelFooterTitle}>Don't have a wallet?</div>

<div class={{ [styles.unlockPanelFooterSubtitle]: true, [styles.unlockPanelFooterSubtitleDesktop]: true }}>
Take full control of <br /> your assets.
</div>

<div class={{ [styles.unlockPanelFooterSubtitle]: true, [styles.unlockPanelFooterSubtitleMobile]: true }}>
<span>See which one to get on </span>

<a
target="_blank"
rel="noopener noreferrer"
class={styles.unlockPanelFooterSubtitleLink}
href={walletAddress}
>
{noProtocolWalletAddress}
</a>
</div>

<Icon name="arrow-up-right" class={styles.unlockButton} />
</div>
</div >
);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './UnlockPanelFooter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// prettier-ignore
export default {
unlockButton: 'unlock-panel-footer-icon mvx:text-primary mvx:w-4 mvx:h-auto mvx:hidden mvx:xs:flex mvx:ml-auto mvx:mt-auto',
unlockPanelFooter: 'unlock-panel-footer mvx:mt-auto mvx:flex mvx:cursor-pointer mvx:relative mvx:p-6 mvx:z-1 mvx:rounded-2xl mvx:overflow-hidden mvx:border mvx:border-outline mvx:bg-emphasize mvx:shadow-[0px_-8px_12px_12px_surface] group',
unlockPanelFooterImage: 'unlock-panel-footer-image mvx:pointer-events-none mvx:-mt-8 mvx:mr-12 mvx:-mb-8 mvx:-ml-20 mvx:hidden mvx:max-h-48 mvx:xs:flex',
unlockPanelFooterWrapper: 'unlock-panel-footer-wrapper mvx:flex mvx:flex-col mvx:transition-all mvx:duration-200 mvx:gap-2 mvx:flex-1 mvx:ease-in-out mvx:xs:gap-4 group-hover:mvx:opacity-75',
unlockPanelFooterTitle: 'unlock-panel-footer-title mvx:font-medium mvx:leading-none mvx:text-base mvx:text-primary mvx:xs:pt-4 mvx:xs:text-xl',
unlockPanelFooterSubtitle: 'unlock-panel-footer-subtitle mvx:text-base mvx:leading-tight mvx:opacity-40 mvx:text-primary',
unlockPanelFooterSubtitleDesktop: 'unlock-panel-footer-subtitle-desktop mvx:hidden mvx:xs:flex',
unlockPanelFooterSubtitleMobile: 'unlock-panel-footer-subtitle-mobile mvx:text-xs mvx:xs:hidden',
unlockPanelFooterSubtitleLink: 'unlock-panel-footer-subtitle-link mvx:text-accent'
} satisfies Record<string, string>;
Loading