Skip to content

Commit 79c9d0b

Browse files
Fixed trim component state (#259)
* Moved state to functional component * Fixed tests * Updated changelog * Added setupTests file
1 parent d36f12b commit 79c9d0b

File tree

14 files changed

+168
-135
lines changed

14 files changed

+168
-135
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
- [Fixed trim component state](https://github.com/multiversx/mx-sdk-dapp-ui/pull/259)
11+
1012
## [[0.1.0](https://github.com/multiversx/mx-sdk-dapp-ui/pull/256)] - 2025-10-29
1113

1214
- [Changed ppu to gasPriceOption in sign transactions panel](https://github.com/multiversx/mx-sdk-dapp-ui/pull/255)

src/common/Trim/Trim.tsx

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,132 @@
11
import { h } from '@stencil/core';
22
import { DataTestIdsEnum } from 'constants/dataTestIds.enum';
33
import { ELLIPSIS } from 'constants/htmlStrings';
4+
import { safeWindow } from 'constants/window.constants';
45

56
import styles from './trim.styles'
67

78
interface TrimPropsType {
89
dataTestId?: string;
910
class?: string;
1011
text: string;
11-
shouldTrim?: boolean;
12-
trimFontSize?: string;
13-
onTrimElementReference?: (element: HTMLDivElement) => void;
14-
onFullWidthTrimElementReference?: (element: HTMLDivElement) => void;
1512
}
1613

1714
export function Trim({
1815
dataTestId = DataTestIdsEnum.trim,
1916
class: className,
20-
text,
21-
shouldTrim = false,
22-
trimFontSize = '1rem',
23-
onTrimElementReference,
24-
onFullWidthTrimElementReference
17+
text
2518
}: TrimPropsType) {
19+
let fullWidthUntrimmedElementReference: HTMLDivElement;
20+
let trimElementReference: HTMLDivElement;
21+
let resizeObserver: ResizeObserver;
22+
let currentTrimFontSize = '1rem';
23+
let trimFullElement: HTMLDivElement;
24+
let trimWrapperElement: HTMLDivElement;
25+
26+
const handleTrimElementReference = (element: HTMLDivElement) => {
27+
if (element) {
28+
trimElementReference = element;
29+
setupResizeObserver();
30+
requestAnimationFrame(checkOverflow);
31+
}
32+
}
33+
34+
const handleFullWidthTrimElementReference = (element: HTMLDivElement) => {
35+
if (element) {
36+
fullWidthUntrimmedElementReference = element;
37+
}
38+
}
39+
40+
const handleTrimFullRef = (element: HTMLDivElement) => {
41+
if (element) {
42+
trimFullElement = element;
43+
}
44+
};
45+
46+
const handleTrimWrapperRef = (element: HTMLDivElement) => {
47+
if (element) {
48+
trimWrapperElement = element;
49+
}
50+
};
51+
52+
const setupResizeObserver = () => {
53+
if (resizeObserver) {
54+
resizeObserver.disconnect();
55+
}
56+
57+
resizeObserver = new ResizeObserver(() => {
58+
checkOverflow();
59+
});
60+
61+
if (trimElementReference) {
62+
resizeObserver.observe(trimElementReference);
63+
}
64+
}
65+
66+
const checkOverflow = () => {
67+
if (!fullWidthUntrimmedElementReference || !trimElementReference || !trimFullElement || !trimWrapperElement) {
68+
return;
69+
}
70+
71+
const hiddenFullWidthElementWidth = fullWidthUntrimmedElementReference.scrollWidth;
72+
const trimmedElementWidth = trimElementReference.clientWidth;
73+
const isTrimElementOverflowing = hiddenFullWidthElementWidth > trimmedElementWidth;
74+
75+
if (safeWindow) {
76+
currentTrimFontSize = safeWindow.getComputedStyle(trimElementReference).fontSize;
77+
}
78+
79+
const getIdentifierClass = (classes: string) => classes.split(' ')[0];
80+
81+
const trimLeftSelector = `.${getIdentifierClass(styles.trimLeft)}`;
82+
const trimRightSelector = `.${getIdentifierClass(styles.trimRight)}`;
83+
84+
const trimLeftElement = trimElementReference.querySelector(trimLeftSelector) as HTMLElement;
85+
const trimRightElement = trimElementReference.querySelector(trimRightSelector) as HTMLElement;
86+
if (trimLeftElement) {
87+
trimLeftElement.style.fontSize = currentTrimFontSize;
88+
}
89+
90+
if (trimRightElement) {
91+
trimRightElement.style.fontSize = currentTrimFontSize;
92+
}
93+
94+
const trimFullVisibleClasses = styles.trimFullVisible.split(/\s+/);
95+
const trimWrapperVisibleClasses = styles.trimWrapperVisible.split(/\s+/);
96+
97+
if (isTrimElementOverflowing) {
98+
trimFullElement.classList.remove(...trimFullVisibleClasses);
99+
trimWrapperElement.classList.add(...trimWrapperVisibleClasses);
100+
} else {
101+
trimFullElement.classList.add(...trimFullVisibleClasses);
102+
trimWrapperElement.classList.remove(...trimWrapperVisibleClasses);
103+
}
104+
};
105+
26106
const middleTextIndex = Math.floor(text.length / 2);
27107
const leftHandText = text.slice(0, middleTextIndex);
28108
const rightHandText = text.slice(middleTextIndex);
29109

30110
return (
31111
<div
32112
data-testid={dataTestId}
33-
ref={onTrimElementReference}
113+
ref={handleTrimElementReference}
34114
class={{ [styles.trim]: true, [className]: Boolean(className) }}
35115
>
36116
<div
37117
data-testid={DataTestIdsEnum.trimFullAddress}
38-
ref={onFullWidthTrimElementReference}
39-
class={{ [styles.trimFull]: true, [styles.trimFullVisible]: !shouldTrim }}
118+
ref={el => {
119+
handleFullWidthTrimElementReference(el);
120+
handleTrimFullRef(el);
121+
}}
122+
class={styles.trimFull}
40123
>
41124
{text}
42125
</div>
43126

44-
<div class={{ [styles.trimWrapper]: true, [styles.trimWrapperVisible]: shouldTrim }}>
127+
<div ref={handleTrimWrapperRef} class={styles.trimWrapper}>
45128
<div class={styles.trimLeftWrapper}>
46-
<div class={styles.trimLeft} style={{ fontSize: trimFontSize }}>
129+
<div class={styles.trimLeft} style={{ fontSize: currentTrimFontSize }}>
47130
{leftHandText}
48131
</div>
49132
</div>
@@ -53,7 +136,7 @@ export function Trim({
53136
</div>
54137

55138
<div class={styles.trimRightWrapper} style={{ direction: 'rtl' }}>
56-
<div class={styles.trimRight} style={{ fontSize: trimFontSize }}>
139+
<div class={styles.trimRight} style={{ fontSize: currentTrimFontSize }}>
57140
{rightHandText}
58141
</div>
59142
</div>

src/components/common/trim/tests/trim.e2e.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,10 @@ describe('Trim tests', () => {
2121
});
2222

2323
const trimElement = page.root;
24-
const component = page.rootInstance;
25-
26-
component.shouldTrim = false;
27-
await page.waitForChanges();
2824

2925
const fullTextElement = trimElement.querySelector('[data-testid="trimFullAddress"]');
3026
expect(fullTextElement).toBeTruthy();
3127
expect(fullTextElement.textContent).toBe('Short text');
32-
expect(fullTextElement.classList.contains('trim-full-visible')).toBe(true);
3328
});
3429

3530
it('should handle overflow and truncate text', async () => {
@@ -46,7 +41,6 @@ describe('Trim tests', () => {
4641

4742
const trimWrapper = trimElement.querySelector('.trim-wrapper');
4843
expect(trimWrapper).toBeTruthy();
49-
expect(trimWrapper.classList.contains('trim-wrapper-visible')).toBe(true);
5044

5145
const leftWrapper = trimWrapper.querySelector('.trim-left-wrapper');
5246
const ellipsisWrapper = trimWrapper.querySelector('.trim-ellipsis-wrapper');

src/components/common/trim/trim.tsx

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,23 @@
1-
import { Component, h, Prop, State } from '@stencil/core';
1+
import { Component, h, Prop } from '@stencil/core';
22
import { Trim as TrimComponent } from 'common/Trim/Trim';
33
import { DataTestIdsEnum } from 'constants/dataTestIds.enum';
4-
import { safeWindow } from 'constants/window.constants';
54

65
@Component({
76
tag: 'mvx-trim',
87
styleUrl: 'trim.scss',
98
shadow: false,
109
})
1110
export class Trim {
12-
@State() shouldTrim: boolean = false;
13-
@State() trimFontSize: string = '1rem';
14-
1511
@Prop() dataTestId?: string = DataTestIdsEnum.trim;
1612
@Prop() class?: string;
1713
@Prop() text: string;
1814

19-
private fullWidthUntrimmedElementReference: HTMLDivElement;
20-
private trimElementReference: HTMLDivElement;
21-
private resizeObserver: ResizeObserver;
22-
23-
componentDidLoad() {
24-
this.setupResizeObserver();
25-
requestAnimationFrame(this.checkOverflow);
26-
}
27-
28-
disconnectedCallback() {
29-
this.resizeObserver?.disconnect?.();
30-
}
31-
32-
private handleTrimElementReference(element: HTMLDivElement) {
33-
this.trimElementReference = element;
34-
}
35-
36-
private handleFullWidthTrimElementReference(element: HTMLDivElement) {
37-
this.fullWidthUntrimmedElementReference = element;
38-
}
39-
40-
private setupResizeObserver() {
41-
this.resizeObserver = new ResizeObserver(() => {
42-
this.checkOverflow();
43-
});
44-
45-
if (this.trimElementReference) {
46-
this.resizeObserver.observe(this.trimElementReference);
47-
}
48-
}
49-
50-
private checkOverflow = () => {
51-
if (!this.fullWidthUntrimmedElementReference || !this.trimElementReference) {
52-
return;
53-
}
54-
55-
const hiddenFullWidthElementWidth = this.fullWidthUntrimmedElementReference.offsetWidth;
56-
const trimmedElementWidth = this.trimElementReference.offsetWidth;
57-
const isTrimElementOverflowing = hiddenFullWidthElementWidth > trimmedElementWidth;
58-
59-
if (safeWindow) {
60-
this.trimFontSize = safeWindow.getComputedStyle(this.trimElementReference).fontSize;
61-
}
62-
63-
if (this.shouldTrim !== isTrimElementOverflowing) {
64-
this.shouldTrim = isTrimElementOverflowing;
65-
}
66-
};
67-
6815
render() {
6916
return (
7017
<TrimComponent
7118
class={this.class}
7219
dataTestId={this.dataTestId}
7320
text={this.text}
74-
shouldTrim={this.shouldTrim}
75-
trimFontSize={this.trimFontSize}
76-
onTrimElementReference={this.handleTrimElementReference.bind(this)}
77-
onFullWidthTrimElementReference={this.handleFullWidthTrimElementReference.bind(this)}
7821
/>
7922
);
8023
}

src/components/controlled/transactions-table/components/TransactionAccount/components/TransactionAccountName/tests/transaction-account-name.spec.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('TransactionAccountName tests', () => {
3333

3434
expect(page.root).toEqualHtml(`
3535
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:truncate mvx:w-max mvx:whitespace-nowrap transaction-account-name trim" data-testid="${DataTestIdsEnum.trim}">
36-
<div class="mvx:!text-inherit mvx:absolute mvx:leading-5 mvx:relative mvx:text-transparent trim-full trim-full-visible" data-testid="${DataTestIdsEnum.trimFullAddress}">
36+
<div class="mvx:absolute mvx:leading-5 mvx:text-transparent trim-full" data-testid="${DataTestIdsEnum.trimFullAddress}">
3737
erd1q...
3838
</div>
3939
<div class="mvx:hidden trim-wrapper">
@@ -65,7 +65,7 @@ describe('TransactionAccountName tests', () => {
6565

6666
expect(page.root).toEqualHtml(`
6767
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:truncate mvx:w-max mvx:whitespace-nowrap transaction-account-name trim" data-testid="${DataTestIdsEnum.trim}">
68-
<div class="mvx:!text-inherit mvx:absolute mvx:leading-5 mvx:relative mvx:text-transparent trim-full trim-full-visible" data-testid="${DataTestIdsEnum.trimFullAddress}">
68+
<div class="mvx:absolute mvx:leading-5 mvx:text-transparent trim-full" data-testid="${DataTestIdsEnum.trimFullAddress}">
6969
erd1q...
7070
</div>
7171
<div class="mvx:hidden trim-wrapper">
@@ -96,7 +96,7 @@ describe('TransactionAccountName tests', () => {
9696
});
9797

9898
expect(page.root).toEqualHtml(`
99-
<div class="custom-class transaction-account-name mvx:w-max mvx:truncate" title="">
99+
<div class="custom-class transaction-account-name mvx:w-max mvx:truncate">
100100
Bob
101101
</div>
102102
`);
@@ -109,7 +109,7 @@ describe('TransactionAccountName tests', () => {
109109
});
110110

111111
expect(page.root).toEqualHtml(`
112-
<div class="transaction-account-name mvx:w-max mvx:truncate" title="">
112+
<div class="transaction-account-name mvx:w-max mvx:truncate">
113113
Charlie
114114
</div>
115115
`);

src/components/controlled/transactions-table/components/TransactionHash/tests/transaction-hash.spec.tsx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ describe('TransactionHash tests', () => {
5353
</svg>
5454
<a class="explorer-link mvx:decoration-0 mvx:flex mvx:text-primary! transaction-hash-explorer-link" data-testid="transactionLink" href="https://example.com/tx/123" rel="noreferrer" target="_blank">
5555
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:whitespace-nowrap trim" data-testid="trim">
56-
<div class="mvx:!text-inherit mvx:absolute mvx:leading-5 mvx:relative mvx:text-transparent trim-full trim-full-visible" data-testid="trimFullAddress">
56+
<div class="mvx:absolute mvx:leading-5 mvx:text-transparent trim-full" data-testid="trimFullAddress">
5757
0x123456789abcdef
5858
</div>
5959
<div class="mvx:hidden trim-wrapper">
@@ -114,7 +114,7 @@ describe('TransactionHash tests', () => {
114114
</svg>
115115
<a class="explorer-link mvx:decoration-0 mvx:flex mvx:text-primary! transaction-hash-explorer-link" data-testid="transactionLink" href="https://example.com/tx/initial" rel="noreferrer" target="_blank">
116116
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:whitespace-nowrap trim" data-testid="trim">
117-
<div class="mvx:!text-inherit mvx:absolute mvx:leading-5 mvx:relative mvx:text-transparent trim-full trim-full-visible" data-testid="trimFullAddress">
117+
<div class="mvx:absolute mvx:leading-5 mvx:text-transparent trim-full" data-testid="trimFullAddress">
118118
0xInitialHash
119119
</div>
120120
<div class="mvx:hidden trim-wrapper">
@@ -169,36 +169,36 @@ describe('TransactionHash tests', () => {
169169
});
170170

171171
expect(page.root).toEqualHtml(`
172-
<div class="mvx:flex mvx:gap-1 mvx:items-center mvx:justify-center transaction-hash">
173-
<svg class="mvx:flex mvx:items-center mvx:justify-center transaction-hash-icon" height="20" viewBox="0 0 640 640" width="20" xmlns="http://www.w3.org/2000/svg">
174-
<path d="M320 576C178.6 576 64 461.4 64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576zM320 112C205.1 112 112 205.1 112 320C112 434.9 205.1 528 320 528C434.9 528 528 434.9 528 320C528 205.1 434.9 112 320 112zM390.7 233.9C398.5 223.2 413.5 220.8 424.2 228.6C434.9 236.4 437.3 251.4 429.5 262.1L307.4 430.1C303.3 435.8 296.9 439.4 289.9 439.9C282.9 440.4 276 437.9 271.1 433L215.2 377.1C205.8 367.7 205.8 352.5 215.2 343.2C224.6 333.9 239.8 333.8 249.1 343.2L285.1 379.2L390.7 234z" fill="currentColor"></path>
175-
</svg>
176-
<a class="explorer-link mvx:decoration-0 mvx:flex mvx:text-primary! transaction-hash-explorer-link" data-testid="transactionLink" href="https://example.com/tx/updated" rel="noreferrer" target="_blank">
177-
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:whitespace-nowrap trim" data-testid="trim">
178-
<div class="mvx:!text-inherit mvx:absolute mvx:leading-5 mvx:relative mvx:text-transparent trim-full trim-full-visible" data-testid="trimFullAddress">
179-
0xUpdatedHash
180-
</div>
181-
<div class="mvx:hidden trim-wrapper">
182-
<div class="mvx:flex-shrink mvx:overflow-hidden mvx:text-[1px] mvx:text-ellipsis mvx:text-left trim-left-wrapper">
183-
<div class="mvx:-webkit-letter-spacing mvx:inline mvx:leading-5 mvx:pointer-events-none mvx:select-none mvx:text-base trim-left" style="font-size: 1rem;">
184-
0xUpda
185-
</div>
186-
</div>
187-
<div class="mvx:block mvx:flex-shrink-0 mvx:pointer-events-none mvx:select-none trim-ellipsis-wrapper">
188-
<div class="mvx:block mvx:leading-5 trim-ellipsis">
189-
...
190-
</div>
191-
</div>
192-
<div class="mvx:flex-shrink mvx:overflow-hidden mvx:text-[1px] mvx:text-ellipsis mvx:text-right mvx:whitespace-nowrap trim-right-wrapper" style="direction: rtl;">
193-
<div class="mvx:-webkit-letter-spacing mvx:inline mvx:leading-5 mvx:pointer-events-none mvx:select-none mvx:text-base mvx:text-clip trim-right" style="font-size: 1rem;">
194-
tedHash
195-
</div>
196-
</div>
197-
</div>
198-
</div>
199-
</a>
200-
</div>
201-
`);
172+
<div class="mvx:flex mvx:gap-1 mvx:items-center mvx:justify-center transaction-hash">
173+
<svg class="mvx:flex mvx:items-center mvx:justify-center transaction-hash-icon" height="20" viewBox="0 0 640 640" width="20" xmlns="http://www.w3.org/2000/svg">
174+
<path d="M320 576C178.6 576 64 461.4 64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576zM320 112C205.1 112 112 205.1 112 320C112 434.9 205.1 528 320 528C434.9 528 528 434.9 528 320C528 205.1 434.9 112 320 112zM390.7 233.9C398.5 223.2 413.5 220.8 424.2 228.6C434.9 236.4 437.3 251.4 429.5 262.1L307.4 430.1C303.3 435.8 296.9 439.4 289.9 439.9C282.9 440.4 276 437.9 271.1 433L215.2 377.1C205.8 367.7 205.8 352.5 215.2 343.2C224.6 333.9 239.8 333.8 249.1 343.2L285.1 379.2L390.7 234z" fill="currentColor"></path>
175+
</svg>
176+
<a class="explorer-link mvx:decoration-0 mvx:flex mvx:text-primary! transaction-hash-explorer-link" data-testid="transactionLink" href="https://example.com/tx/updated" rel="noreferrer" target="_blank">
177+
<div class="mvx:flex mvx:max-w-full mvx:overflow-hidden mvx:relative mvx:whitespace-nowrap trim" data-testid="trim">
178+
<div class="mvx:absolute mvx:leading-5 mvx:text-transparent trim-full" data-testid="trimFullAddress">
179+
0xUpdatedHash
180+
</div>
181+
<div class="mvx:hidden trim-wrapper">
182+
<div class="mvx:flex-shrink mvx:overflow-hidden mvx:text-[1px] mvx:text-ellipsis mvx:text-left trim-left-wrapper">
183+
<div class="mvx:-webkit-letter-spacing mvx:inline mvx:leading-5 mvx:pointer-events-none mvx:select-none mvx:text-base trim-left" style="font-size: 1rem;">
184+
0xUpda
185+
</div>
186+
</div>
187+
<div class="mvx:block mvx:flex-shrink-0 mvx:pointer-events-none mvx:select-none trim-ellipsis-wrapper">
188+
<div class="mvx:block mvx:leading-5 trim-ellipsis">
189+
...
190+
</div>
191+
</div>
192+
<div class="mvx:flex-shrink mvx:overflow-hidden mvx:text-[1px] mvx:text-ellipsis mvx:text-right mvx:whitespace-nowrap trim-right-wrapper" style="direction: rtl;">
193+
<div class="mvx:-webkit-letter-spacing mvx:inline mvx:leading-5 mvx:pointer-events-none mvx:select-none mvx:text-base mvx:text-clip trim-right" style="font-size: 1rem;">
194+
tedHash
195+
</div>
196+
</div>
197+
</div>
198+
</div>
199+
</a>
200+
</div>
201+
`);
202202
});
203203

204204
it('renders null when transaction is not provided', async () => {

0 commit comments

Comments
 (0)