Skip to content

Commit e29124f

Browse files
marioAntonioTotvsfabiana-monteiro
authored andcommitted
fix(popover): corrige crescimento automatico de width
Quando não passamos valor fixo de width para o popover o componente se adapta ao tamanho do contéudo, respeitando o 'max-width' do componente. Fixes DTHFUI-12553
1 parent 3d9ff33 commit e29124f

2 files changed

Lines changed: 136 additions & 40 deletions

File tree

projects/ui/src/lib/components/po-popover/po-popover.component.spec.ts

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,11 @@ describe('PoPopoverComponent:', () => {
323323
});
324324

325325
it('should open popover', fakeAsync(() => {
326+
spyOn(window, 'requestAnimationFrame').and.callFake((cb: FrameRequestCallback) => {
327+
cb(0);
328+
return 0;
329+
});
330+
326331
const fakeThis = {
327332
addScrollEventListener: () => {},
328333
isHidden: true,
@@ -332,7 +337,19 @@ describe('PoPopoverComponent:', () => {
332337
setElementsControlPosition: () => {},
333338
setOpacity: arg => {},
334339
observeContentResize: () => {},
335-
cd: { detectChanges: () => {} }
340+
cd: { detectChanges: () => {} },
341+
showPopover: undefined as any
342+
};
343+
344+
fakeThis.showPopover = () => {
345+
requestAnimationFrame(() => {
346+
fakeThis.setElementsControlPosition();
347+
fakeThis.setPopoverPosition();
348+
fakeThis.setOpacity(1);
349+
fakeThis.openPopover.emit();
350+
fakeThis.observeContentResize();
351+
fakeThis.cd.detectChanges();
352+
});
336353
};
337354

338355
spyOn(fakeThis, 'addScrollEventListener');
@@ -342,8 +359,6 @@ describe('PoPopoverComponent:', () => {
342359
spyOn(fakeThis.cd, 'detectChanges');
343360
component.open.call(fakeThis);
344361

345-
tick(300);
346-
347362
expect(fakeThis.isHidden).toBeFalsy();
348363
expect(fakeThis.addScrollEventListener).toHaveBeenCalled();
349364
expect(fakeThis.setOpacity).toHaveBeenCalledWith(1);
@@ -352,10 +367,15 @@ describe('PoPopoverComponent:', () => {
352367
expect(fakeThis.cd.detectChanges).toHaveBeenCalled();
353368
}));
354369

355-
it('open: should set widthPopover and call requestAnimationFrame when cornerAligned is true and width is undefined', fakeAsync(() => {
370+
it('open: should set widthPopover from getBoundingClientRect when cornerAligned is true and width is undefined', fakeAsync(() => {
371+
spyOn(window, 'requestAnimationFrame').and.callFake((cb: FrameRequestCallback) => {
372+
cb(0);
373+
return 0;
374+
});
375+
356376
const fakeNativeElement = {
357-
style: { width: '', opacity: 0 },
358-
scrollWidth: 250
377+
style: { width: '', opacity: 0, visibility: '', left: '' },
378+
getBoundingClientRect: () => ({ width: 250 })
359379
};
360380

361381
const fakeThis: any = {
@@ -370,24 +390,19 @@ describe('PoPopoverComponent:', () => {
370390
setElementsControlPosition: () => {},
371391
setOpacity: () => {},
372392
observeContentResize: () => {},
373-
cd: { detectChanges: () => {} }
393+
cd: { detectChanges: () => {} },
394+
showPopover: () => {}
374395
};
375396

376-
spyOn(window, 'requestAnimationFrame').and.callFake((cb: FrameRequestCallback) => {
377-
cb(0);
378-
return 0;
379-
});
380-
381397
component.open.call(fakeThis);
382-
tick(300);
383398

384-
expect(fakeNativeElement.style.width).toBe('auto');
399+
expect(fakeNativeElement.style.visibility).toBe('');
400+
expect(fakeNativeElement.style.left).toBe('');
385401
expect(fakeThis.widthPopover).toBe(250);
386402
expect(window.requestAnimationFrame).toHaveBeenCalled();
387-
expect(fakeThis.setPopoverPosition).toHaveBeenCalled();
388403
}));
389404

390-
it('open: should NOT set widthPopover when cornerAligned is false', fakeAsync(() => {
405+
it('open: should NOT set widthPopover when cornerAligned is false', () => {
391406
const fakeThis: any = {
392407
addScrollEventListener: () => {},
393408
isHidden: true,
@@ -399,16 +414,16 @@ describe('PoPopoverComponent:', () => {
399414
setElementsControlPosition: () => {},
400415
setOpacity: () => {},
401416
observeContentResize: () => {},
402-
cd: { detectChanges: () => {} }
417+
cd: { detectChanges: () => {} },
418+
showPopover: () => {}
403419
};
404420

405421
component.open.call(fakeThis);
406-
tick(300);
407422

408423
expect(fakeThis.widthPopover).toBeUndefined();
409-
}));
424+
});
410425

411-
it('open: should NOT set widthPopover when width input is defined', fakeAsync(() => {
426+
it('open: should NOT set widthPopover when width input is defined', () => {
412427
const fakeThis: any = {
413428
addScrollEventListener: () => {},
414429
isHidden: true,
@@ -420,13 +435,63 @@ describe('PoPopoverComponent:', () => {
420435
setElementsControlPosition: () => {},
421436
setOpacity: () => {},
422437
observeContentResize: () => {},
423-
cd: { detectChanges: () => {} }
438+
cd: { detectChanges: () => {} },
439+
showPopover: () => {}
424440
};
425441

426442
component.open.call(fakeThis);
427-
tick(300);
428443

429444
expect(fakeThis.widthPopover).toBeUndefined();
445+
});
446+
447+
it('open: should recalculate widthPopover on second open after close resets it when cornerAligned is true', fakeAsync(() => {
448+
spyOn(window, 'requestAnimationFrame').and.callFake((cb: FrameRequestCallback) => {
449+
cb(0);
450+
return 0;
451+
});
452+
453+
const fakeNativeElement = {
454+
style: { width: '', opacity: 0, visibility: '', left: '' },
455+
getBoundingClientRect: jasmine.createSpy('getBoundingClientRect').and.returnValue({ width: 200 })
456+
};
457+
458+
const fakeThis: any = {
459+
addScrollEventListener: () => {},
460+
isHidden: true,
461+
cornerAligned: true,
462+
width: undefined,
463+
widthPopover: undefined,
464+
popoverElement: { nativeElement: fakeNativeElement },
465+
openPopover: { emit: () => {} },
466+
closePopover: { emit: () => {} },
467+
setPopoverPosition: () => {},
468+
setElementsControlPosition: () => {},
469+
setOpacity: () => {},
470+
observeContentResize: () => {},
471+
cd: { detectChanges: () => {} },
472+
showPopover: () => {},
473+
disconnectResizeObserver: () => {},
474+
mutationObserver: null,
475+
clickoutListener: undefined,
476+
trigger: 'click'
477+
};
478+
479+
// First open — should calculate widthPopover
480+
component.open.call(fakeThis);
481+
expect(fakeThis.widthPopover).toBe(200);
482+
expect(fakeNativeElement.getBoundingClientRect).toHaveBeenCalledTimes(1);
483+
484+
// Close — widthPopover is reset to undefined
485+
component.close.call(fakeThis);
486+
expect(fakeThis.widthPopover).toBeUndefined();
487+
488+
// Second open — should recalculate because close reset widthPopover
489+
fakeThis.isHidden = true;
490+
fakeNativeElement.getBoundingClientRect.calls.reset();
491+
fakeNativeElement.getBoundingClientRect.and.returnValue({ width: 300 });
492+
component.open.call(fakeThis);
493+
expect(fakeThis.widthPopover).toBe(300);
494+
expect(fakeNativeElement.getBoundingClientRect).toHaveBeenCalledTimes(1);
430495
}));
431496

432497
it('open: should set clickoutListener when trigger is function', () => {
@@ -448,7 +513,8 @@ describe('PoPopoverComponent:', () => {
448513
observeContentResize: () => {},
449514
openPopover: { emit: () => {} },
450515
cd: { detectChanges: () => {} },
451-
isHidden: true
516+
isHidden: true,
517+
showPopover: () => {}
452518
};
453519

454520
component.open.call(fakeThis);
@@ -522,6 +588,26 @@ describe('PoPopoverComponent:', () => {
522588
});
523589

524590
describe('Methods:', () => {
591+
it('showPopover: should call setElementsControlPosition, setPopoverPosition, setOpacity, openPopover.emit, observeContentResize and detectChanges', () => {
592+
spyOn(window, 'requestAnimationFrame').and.callFake((cb: FrameRequestCallback) => {
593+
cb(0);
594+
return 0;
595+
});
596+
spyOn(component, 'setPopoverPosition');
597+
spyOn(component, <any>'setElementsControlPosition');
598+
spyOn(component, 'setOpacity');
599+
spyOn(component, <any>'observeContentResize');
600+
spyOn(component.openPopover, 'emit');
601+
602+
component['showPopover']();
603+
604+
expect(component['setElementsControlPosition']).toHaveBeenCalled();
605+
expect(component.setPopoverPosition).toHaveBeenCalled();
606+
expect(component.setOpacity).toHaveBeenCalledWith(1);
607+
expect(component.openPopover.emit).toHaveBeenCalled();
608+
expect(component['observeContentResize']).toHaveBeenCalled();
609+
});
610+
525611
it(`ngAfterViewInit: should call 'setElementsControlPosition'`, () => {
526612
spyOn(component, <any>'setElementsControlPosition');
527613

projects/ui/src/lib/components/po-popover/po-popover.component.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
104104
close(): void {
105105
this.isHidden = true;
106106
this.disconnectResizeObserver();
107+
this.widthPopover = undefined;
107108
this.closePopover.emit();
108109

109110
if (this.trigger === 'function' && this.clickoutListener) {
@@ -124,25 +125,23 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
124125
this.addScrollEventListener();
125126
this.setOpacity(0);
126127
this.isHidden = false;
127-
setTimeout(() => {
128-
this.setElementsControlPosition();
129-
this.setPopoverPosition();
130-
this.setOpacity(1);
131-
this.openPopover.emit();
132-
this.observeContentResize();
133-
if (this.cornerAligned && !this.width) {
134-
const el = this.popoverElement.nativeElement;
135128

136-
el.style.width = 'auto';
137-
const width = el.scrollWidth;
138-
this.widthPopover = width;
139-
140-
requestAnimationFrame(() => {
141-
this.setPopoverPosition();
142-
});
143-
}
129+
if (this.cornerAligned && !this.width && !this.widthPopover) {
130+
const el = this.popoverElement.nativeElement;
131+
el.style.visibility = 'hidden';
132+
el.style.left = '-9999px';
133+
el.style.width = '';
134+
this.setOpacity(0);
144135
this.cd.detectChanges();
145-
});
136+
137+
requestAnimationFrame(() => {
138+
this.widthPopover = el.getBoundingClientRect().width;
139+
el.style.visibility = '';
140+
el.style.left = '';
141+
this.cd.detectChanges();
142+
});
143+
}
144+
this.showPopover();
146145

147146
if (this.trigger === 'function') {
148147
this.clickoutListener = this.renderer.listen('document', 'click', (event: MouseEvent) => {
@@ -153,6 +152,17 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
153152
this.cd.detectChanges();
154153
}
155154

155+
private showPopover(): void {
156+
requestAnimationFrame(() => {
157+
this.setElementsControlPosition();
158+
this.setPopoverPosition();
159+
this.setOpacity(1);
160+
this.openPopover.emit();
161+
this.observeContentResize();
162+
this.cd.detectChanges();
163+
});
164+
}
165+
156166
public ensurePopoverPosition(): void {
157167
setTimeout(() => {
158168
this.setElementsControlPosition();

0 commit comments

Comments
 (0)