Skip to content

Commit e222444

Browse files
committed
Merge remote-tracking branch 'origin/master' into copilot/increase-code-coverage-tests
2 parents 40f6848 + 5dad161 commit e222444

12 files changed

Lines changed: 333 additions & 184 deletions

File tree

package-lock.json

Lines changed: 166 additions & 162 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@
306306
%filtering-row-input-overrides {
307307
igx-input-group {
308308
width: 100%;
309-
max-width: rem(200px);
309+
max-width: rem(240px);
310310
min-width: rem(140px);
311311

312312
@if $variant != 'fluent' {
@@ -2482,6 +2482,16 @@
24822482
margin: rem(4px);
24832483
}
24842484
}
2485+
2486+
.igx-grid__filtering-row-percent-hint {
2487+
display: inline-block;
2488+
max-width: rem(56px);
2489+
overflow: hidden;
2490+
text-overflow: ellipsis;
2491+
white-space: nowrap;
2492+
vertical-align: middle;
2493+
flex-shrink: 1;
2494+
}
24852495
}
24862496

24872497
%igx-grid__filtering-dropdown-items {

projects/igniteui-angular/directives/src/directives/tooltip/tooltip-target.directive.ts

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
Directive, OnInit, OnDestroy, Output, ElementRef, ViewContainerRef,
2+
Directive, OnInit, OnDestroy, Output, ViewContainerRef,
33
Input, EventEmitter, booleanAttribute, TemplateRef, ComponentRef, Renderer2,
44
EnvironmentInjector,
55
createComponent,
@@ -380,6 +380,7 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
380380
private _positionSettings: PositionSettings = TooltipPositionSettings;
381381
private _showTriggers = new Set(['pointerenter']);
382382
private _hideTriggers = new Set(['pointerleave', 'click']);
383+
private _pendingShowTrigger: string | null = null;
383384

384385
private _abortController = new AbortController();
385386

@@ -400,15 +401,20 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
400401
/**
401402
* @hidden
402403
*/
403-
public onShow(): void {
404-
this._checksBeforeShowing(() => this._showOnInteraction());
404+
public onShow(event?: Event): void {
405+
this._checksBeforeShowing(() => this._showOnInteraction(event));
405406
}
406407

407408
/**
408409
* @hidden
409410
*/
410-
public onHide(): void {
411-
if (this.tooltipDisabled || this.target.collapsed) {
411+
public onHide(event?: Event): void {
412+
if (this.target.collapsed) {
413+
this._cancelPendingShow(event);
414+
return;
415+
}
416+
417+
if (this.tooltipDisabled) {
412418
return;
413419
}
414420

@@ -538,7 +544,7 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
538544
}, withDelay ? this.hideDelay : 0);
539545
}
540546

541-
private _showTooltip(withDelay: boolean, withEvents: boolean): void {
547+
private _showTooltip(withDelay: boolean, withEvents: boolean, triggerEvent?: Event): void {
542548
if (!this.target.collapsed && !this._isForceClosed) {
543549
return;
544550
}
@@ -555,17 +561,19 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
555561
}
556562

557563
this._evaluateStickyState();
564+
this._pendingShowTrigger = triggerEvent?.type ?? null;
558565

559566
this.target.timeoutId = setTimeout(() => {
560567
// Call open() of IgxTooltipDirective
568+
this._pendingShowTrigger = null;
561569
this.target.open(this._mergedOverlaySettings);
562570
}, withDelay ? this.showDelay : 0);
563571
}
564572

565573

566-
private _showOnInteraction(): void {
574+
private _showOnInteraction(triggerEvent?: Event): void {
567575
this._stopTimeoutAndAnimation();
568-
this._showTooltip(true, true);
576+
this._showTooltip(true, true, triggerEvent);
569577
}
570578

571579
private _hideOnInteraction(): void {
@@ -594,6 +602,26 @@ export class IgxTooltipTargetDirective extends IgxToggleActionDirective implemen
594602
this.target.stopAnimations();
595603
}
596604

605+
/**
606+
* Used when a hide trigger occurs before the tooltip opens.
607+
* Clears the pending timeout and resets the tracked show trigger
608+
* so the tooltip does not open after the user has already left the target.
609+
*/
610+
private _cancelPendingShow(event?: Event): void {
611+
if (!this.target.timeoutId) {
612+
return;
613+
}
614+
615+
// Keep same-event show/hide trigger combinations acting as toggle behavior.
616+
if (event?.type && event.type === this._pendingShowTrigger) {
617+
return;
618+
}
619+
620+
clearTimeout(this.target.timeoutId);
621+
this.target.timeoutId = null;
622+
this._pendingShowTrigger = null;
623+
}
624+
597625
/**
598626
* Used when a single tooltip is used for multiple targets.
599627
*/

projects/igniteui-angular/directives/src/directives/tooltip/tooltip.directive.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,19 @@ describe('IgxTooltip', () => {
519519
flush();
520520
verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false);
521521
}));
522+
523+
it('should not open when pointer leaves before the show delay elapses', fakeAsync(() => {
524+
tooltipTarget.showDelay = 500;
525+
fix.detectChanges();
526+
527+
hoverElement(button);
528+
tick(300);
529+
verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false);
530+
531+
unhoverElement(button);
532+
tick(300);
533+
verifyTooltipVisibility(tooltipNativeElement, tooltipTarget, false);
534+
}));
522535
});
523536
});
524537

projects/igniteui-angular/grids/core/src/filtering/base/grid-filtering-row.component.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
(keyup)="onInputKeyUp()"/>
3939
@if (value || value === 0) {
4040
<igx-suffix>
41+
@if (column.dataType === 'percent') {
42+
<span class="igx-grid__filtering-row-percent-hint">{{ value | percent:column.pipeArgs.digitsInfo:filteringService.grid.locale }}</span>
43+
}
4144
<igx-icon
4245
(keydown)="onCommitKeyDown($event)"
4346
(click)="onCommitClick()"

projects/igniteui-angular/grids/core/src/filtering/base/grid-filtering-row.component.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ import { IBaseChipEventArgs, IgxChipComponent, IgxChipsAreaComponent } from 'ign
2626
import { IgxIconComponent } from 'igniteui-angular/icon';
2727
import { IgxInputDirective, IgxInputGroupComponent, IgxPrefixDirective, IgxSuffixDirective } from 'igniteui-angular/input-group';
2828
import { IgxDatePickerComponent } from 'igniteui-angular/date-picker';
29-
import { AbsoluteScrollStrategy, ColumnType, ConnectedPositioningStrategy, DataUtil, FilteringLogic, GridColumnDataType, HorizontalAlignment, IFilteringExpression, IFilteringOperation, IgxPickerClearComponent, IgxPickerToggleComponent, isEqual, OverlaySettings, PlatformUtil, ɵSize, VerticalAlignment } from 'igniteui-angular/core';
29+
import { AbsoluteScrollStrategy, ColumnType, ConnectedPositioningStrategy, DataUtil, FilteringLogic, GridColumnDataType, HorizontalAlignment, IFilteringExpression, IFilteringOperation, IgxPercentFormatterPipe, IgxPickerClearComponent, IgxPickerToggleComponent, isEqual, OverlaySettings, PlatformUtil, ɵSize, VerticalAlignment } from 'igniteui-angular/core';
3030
import { IgxTimePickerComponent } from 'igniteui-angular/time-picker';
3131
import { IgxButtonDirective, IgxDateTimeEditorDirective, IgxIconButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives';
3232

33+
/**
34+
* Default debounce time (ms) for filtering row inputs.
35+
* @hidden
36+
*/
37+
export const INPUT_DEBOUNCE_TIME_DEFAULT = 350;
38+
3339
/**
3440
* Injection token for setting the debounce time used in filtering row inputs.
3541
* @hidden
3642
*/
3743
export const INPUT_DEBOUNCE_TIME = /*@__PURE__*/new InjectionToken<number>('INPUT_DEBOUNCE_TIME', {
38-
factory: () => 350
44+
factory: () => INPUT_DEBOUNCE_TIME_DEFAULT
3945
});
4046

4147
/**
@@ -65,7 +71,8 @@ export const INPUT_DEBOUNCE_TIME = /*@__PURE__*/new InjectionToken<number>('INPU
6571
IgxButtonDirective,
6672
NgClass,
6773
IgxRippleDirective,
68-
IgxIconButtonDirective
74+
IgxIconButtonDirective,
75+
IgxPercentFormatterPipe
6976
]
7077
})
7178
export class IgxGridFilteringRowComponent implements OnInit, AfterViewInit, OnDestroy {
@@ -280,6 +287,7 @@ export class IgxGridFilteringRowComponent implements OnInit, AfterViewInit, OnDe
280287
return 'text';
281288
case GridColumnDataType.Number:
282289
case GridColumnDataType.Currency:
290+
case GridColumnDataType.Percent:
283291
return 'number';
284292
}
285293
}

projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-default-expression.component.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
[(ngModel)]="expressionUI.expression.searchVal"
3434
(blur)="updateSearchValueOnBlur($event)"
3535
/>
36+
@if (column.dataType === 'percent' && (expressionUI.expression.searchVal || expressionUI.expression.searchVal === 0)) {
37+
<igx-suffix>
38+
<span class="igx-grid__filtering-row-percent-hint">{{ expressionUI.expression.searchVal | percent:column.pipeArgs.digitsInfo:grid.locale }}</span>
39+
</igx-suffix>
40+
}
3641
</igx-input-group>
3742

3843
@if (!isSingle) {

projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-default-expression.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Component, AfterViewInit, Input, Output, EventEmitter, ChangeDetectorRef, ViewChild, inject } from '@angular/core';
22
import { FormsModule } from '@angular/forms';
33
import { ExpressionUI } from './common';
4-
import { AbsoluteScrollStrategy, ColumnType, ConnectedPositioningStrategy, DataUtil, FilteringLogic, GridColumnDataType, IBaseEventArgs, IFilteringOperation, IgxOverlayOutletDirective, OverlaySettings, PlatformUtil } from 'igniteui-angular/core';
4+
import { AbsoluteScrollStrategy, ColumnType, ConnectedPositioningStrategy, DataUtil, FilteringLogic, GridColumnDataType, IBaseEventArgs, IFilteringOperation, IgxOverlayOutletDirective, IgxPercentFormatterPipe, OverlaySettings, PlatformUtil } from 'igniteui-angular/core';
55
import { IgxSelectComponent, IgxSelectItemComponent } from 'igniteui-angular/select';
6-
import { IgxInputDirective, IgxInputGroupComponent, IgxPrefixDirective } from 'igniteui-angular/input-group';
6+
import { IgxInputDirective, IgxInputGroupComponent, IgxPrefixDirective, IgxSuffixDirective } from 'igniteui-angular/input-group';
77
import { IgxIconComponent } from 'igniteui-angular/icon';
88
import { IgxButtonDirective, IgxIconButtonDirective } from 'igniteui-angular/directives';
99
import { IgxButtonGroupComponent } from 'igniteui-angular/button-group';
@@ -22,7 +22,7 @@ export interface ILogicOperatorChangedArgs extends IBaseEventArgs {
2222
@Component({
2323
selector: 'igx-excel-style-default-expression',
2424
templateUrl: './excel-style-default-expression.component.html',
25-
imports: [FormsModule, IgxSelectComponent, IgxPrefixDirective, IgxIconComponent, IgxSelectItemComponent, IgxInputGroupComponent, IgxInputDirective, IgxButtonDirective, IgxButtonGroupComponent, IgxOverlayOutletDirective, IgxIconButtonDirective]
25+
imports: [FormsModule, IgxSelectComponent, IgxPrefixDirective, IgxIconComponent, IgxSelectItemComponent, IgxInputGroupComponent, IgxInputDirective, IgxSuffixDirective, IgxButtonDirective, IgxButtonGroupComponent, IgxOverlayOutletDirective, IgxIconButtonDirective, IgxPercentFormatterPipe]
2626
})
2727
export class IgxExcelStyleDefaultExpressionComponent implements AfterViewInit {
2828
public cdr = inject(ChangeDetectorRef);

projects/igniteui-angular/grids/grid/src/column.spec.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
2121
import { UIInteractions, wait } from '../../../test-utils/ui-interactions.spec';
2222
import { GridFunctions, GridSummaryFunctions } from '../../../test-utils/grid-functions.spec';
23-
import { IgxCellFooterTemplateDirective, IgxCellHeaderTemplateDirective, IgxCellTemplateDirective, IgxColumnComponent, IgxSummaryTemplateDirective } from 'igniteui-angular/grids/core';
23+
import { IgxCellFooterTemplateDirective, IgxCellHeaderTemplateDirective, IgxCellTemplateDirective, IgxColumnComponent, INPUT_DEBOUNCE_TIME_DEFAULT, IgxSummaryTemplateDirective } from 'igniteui-angular/grids/core';
2424
import { IgxGridRowComponent } from './grid-row.component';
2525
import { GridColumnDataType, IgxStringFilteringOperand, SortingDirection } from 'igniteui-angular/core';
2626
import { IgxButtonDirective, IgxDateTimeEditorDirective } from 'igniteui-angular/directives';
@@ -838,6 +838,77 @@ describe('IgxGrid - Column properties #grid', () => {
838838
expect((checkBoxes[3].querySelector('.igx-checkbox__label') as HTMLElement).innerText).toEqual('002.700%');
839839
}));
840840

841+
it('should show percent suffix in filter row when filtering a percent column', fakeAsync(() => {
842+
const fix = TestBed.createComponent(IgxGridPercentColumnComponent);
843+
fix.detectChanges();
844+
845+
const grid = fix.componentInstance.grid;
846+
const discountColumn = grid.getColumnByName('Discount');
847+
grid.allowFiltering = true;
848+
fix.detectChanges();
849+
850+
GridFunctions.clickFilterCellChip(fix, discountColumn.field);
851+
tick(100);
852+
fix.detectChanges();
853+
854+
const filterUIRow = fix.debugElement.query(By.css('igx-grid-filtering-row'));
855+
const input = filterUIRow.query(By.directive(IgxInputDirective));
856+
857+
// Suffix should not be visible before entering a value
858+
let percentLabel = filterUIRow.query(By.css('.igx-grid__filtering-row-percent-hint'));
859+
expect(percentLabel).toBeNull();
860+
861+
// Enter a value to trigger the suffix; wait for the filter row input debounce
862+
GridFunctions.typeValueInFilterRowInput(0.03, fix, input);
863+
tick(INPUT_DEBOUNCE_TIME_DEFAULT);
864+
fix.detectChanges();
865+
866+
percentLabel = filterUIRow.query(By.css('.igx-grid__filtering-row-percent-hint'));
867+
expect(percentLabel).not.toBeNull();
868+
expect(percentLabel.nativeElement.textContent.trim()).toEqual('3%');
869+
}));
870+
871+
it('should show percent suffix in ESF custom dialog when filtering a percent column', fakeAsync(() => {
872+
const fix = TestBed.createComponent(IgxGridPercentColumnComponent);
873+
tick();
874+
fix.detectChanges();
875+
876+
const grid = fix.componentInstance.grid;
877+
const discountColumn = grid.getColumnByName('Discount');
878+
grid.allowFiltering = true;
879+
grid.filterMode = 'excelStyleFilter';
880+
fix.detectChanges();
881+
882+
GridFunctions.clickExcelFilterIcon(fix, discountColumn.field);
883+
tick(100);
884+
fix.detectChanges();
885+
886+
GridFunctions.clickExcelFilterCascadeButton(fix);
887+
tick(100);
888+
fix.detectChanges();
889+
890+
// Open custom filter dialog by selecting first operator (Equals)
891+
GridFunctions.clickOperatorFromCascadeMenu(fix, 0);
892+
tick(200);
893+
fix.detectChanges();
894+
895+
const exprComponents = GridFunctions.getExcelCustomFilteringDefaultExpressions(fix);
896+
expect(exprComponents.length).toBeGreaterThan(0);
897+
898+
// Percent label should not be visible before entering a value
899+
let percentLabel = exprComponents[0].querySelector('.igx-grid__filtering-row-percent-hint');
900+
expect(percentLabel).toBeNull();
901+
902+
// Enter a value to trigger the suffix
903+
GridFunctions.setInputValueESF(fix, 0, 0.05);
904+
tick(100);
905+
fix.detectChanges();
906+
907+
percentLabel = exprComponents[0].querySelector('.igx-grid__filtering-row-percent-hint');
908+
expect(percentLabel).not.toBeNull();
909+
expect(percentLabel.textContent.trim()).toEqual('5%');
910+
}));
911+
841912
});
842913

843914
describe('Date, DateTime and Time column tests', () => {

projects/igniteui-angular/grids/grid/src/grid-filtering-ui.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => {
19771977
}));
19781978

19791979
it('should scroll correct chip in view when one is deleted', async () => {
1980-
grid.width = '800px';
1980+
grid.width = '840px';
19811981
fix.detectChanges();
19821982
await wait(DEBOUNCE_TIME);
19831983

0 commit comments

Comments
 (0)