Skip to content

Commit f144b03

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 647a21e commit f144b03

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
@@ -112,6 +112,7 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
112112
close(): void {
113113
this.isHidden = true;
114114
this.disconnectResizeObserver();
115+
this.widthPopover = undefined;
115116
this.closePopover.emit();
116117

117118
if (this.trigger === 'function' && this.clickoutListener) {
@@ -132,25 +133,23 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
132133
this.addScrollEventListener();
133134
this.setOpacity(0);
134135
this.isHidden = false;
135-
setTimeout(() => {
136-
this.setElementsControlPosition();
137-
this.setPopoverPosition();
138-
this.setOpacity(1);
139-
this.openPopover.emit();
140-
this.observeContentResize();
141-
if (this.cornerAligned && !this.width) {
142-
const el = this.popoverElement.nativeElement;
143136

144-
el.style.width = 'auto';
145-
const width = el.scrollWidth;
146-
this.widthPopover = width;
147-
148-
requestAnimationFrame(() => {
149-
this.setPopoverPosition();
150-
});
151-
}
137+
if (this.cornerAligned && !this.width && !this.widthPopover) {
138+
const el = this.popoverElement.nativeElement;
139+
el.style.visibility = 'hidden';
140+
el.style.left = '-9999px';
141+
el.style.width = '';
142+
this.setOpacity(0);
152143
this.cd.detectChanges();
153-
});
144+
145+
requestAnimationFrame(() => {
146+
this.widthPopover = el.getBoundingClientRect().width;
147+
el.style.visibility = '';
148+
el.style.left = '';
149+
this.cd.detectChanges();
150+
});
151+
}
152+
this.showPopover();
154153

155154
if (this.trigger === 'function') {
156155
this.clickoutListener = this.renderer.listen('document', 'click', (event: MouseEvent) => {
@@ -161,6 +160,17 @@ export class PoPopoverComponent extends PoPopoverBaseComponent implements AfterV
161160
this.cd.detectChanges();
162161
}
163162

163+
private showPopover(): void {
164+
requestAnimationFrame(() => {
165+
this.setElementsControlPosition();
166+
this.setPopoverPosition();
167+
this.setOpacity(1);
168+
this.openPopover.emit();
169+
this.observeContentResize();
170+
this.cd.detectChanges();
171+
});
172+
}
173+
164174
public ensurePopoverPosition(): void {
165175
setTimeout(() => {
166176
this.setElementsControlPosition();

0 commit comments

Comments
 (0)