Skip to content

Commit 35a53e8

Browse files
authored
Merge branch '19.2.x' into mkirova/fix-15768-19.2.x
2 parents 59df19b + ba08fdc commit 35a53e8

37 files changed

+428
-179
lines changed

.github/workflows/nodejs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
strategy:
1818
matrix:
19-
node-version: [20.x, 22.17.1]
19+
node-version: [20.x, 22.x]
2020

2121
steps:
2222
- name: Checkout
@@ -51,7 +51,7 @@ jobs:
5151
npm run test:schematics
5252
npm run test:i18n
5353
env:
54-
NODE_OPTIONS: --max_old_space_size=4096
54+
NODE_OPTIONS: --max_old_space_size=4096 ${{ matrix.node-version == '22.x' && '--no-experimental-strip-types' || '' }}
5555
TZ: America/New_York
5656
- name: Build i18n & validate output
5757
run: |

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,9 @@
12531253
%grid-display-container-tr {
12541254
width: 100%;
12551255
overflow: visible;
1256+
flex: 1;
1257+
// needed to override the min-width of the column headers
1258+
min-width: 0;
12561259
}
12571260

12581261
%grid-mrl-block {
@@ -1450,7 +1453,7 @@
14501453
}
14511454

14521455
padding-block: 0;
1453-
flex: 1 0 auto;
1456+
flex: 0 0 auto;
14541457
background: inherit;
14551458
z-index: 4;
14561459
cursor: move;

projects/igniteui-angular/src/lib/data-operations/sorting-strategy.spec.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,46 @@ describe('Unit testing SortingStrategy', () => {
2424
strategy: DefaultSortingStrategy.instance()
2525
}]);
2626
expect(dataGenerator.getValuesForColumn(res, 'number'))
27-
.toEqual([4, 2, 0, 3, 1]);
27+
.toEqual([4, 2, 0, 3, 1]);
2828
});
2929
it('tests `compareObjects`', () => {
3030
const strategy = DefaultSortingStrategy.instance();
3131
expect(strategy.compareValues(1, 0) === 1 &&
32-
strategy.compareValues(true, false) === 1 &&
33-
strategy.compareValues('bc', 'adfc') === 1)
32+
strategy.compareValues(true, false) === 1 &&
33+
strategy.compareValues('bc', 'adfc') === 1)
3434
.toBeTruthy('compare first argument greater than second');
3535
expect(strategy.compareValues(1, 2) === -1 &&
36-
strategy.compareValues('a', 'b') === -1 &&
37-
strategy.compareValues(false, true) === -1)
36+
strategy.compareValues('a', 'b') === -1 &&
37+
strategy.compareValues(false, true) === -1)
3838
.toBeTruthy('compare 0, 1');
3939
expect(strategy.compareValues(0, 0) === 0 &&
40-
strategy.compareValues(true, true) === 0 &&
41-
strategy.compareValues('test', 'test') === 0
42-
)
40+
strategy.compareValues(true, true) === 0 &&
41+
strategy.compareValues('test', 'test') === 0
42+
)
4343
.toBeTruthy('Comare equal variables');
4444
});
4545
it('tests default settings', () => {
4646
(data[4] as { string: string }).string = 'ROW';
4747
const res = sorting.sort(data, [{
48-
dir: SortingDirection.Asc,
49-
fieldName: 'string',
50-
ignoreCase: true,
51-
strategy: DefaultSortingStrategy.instance()
52-
}]);
48+
dir: SortingDirection.Asc,
49+
fieldName: 'string',
50+
ignoreCase: true,
51+
strategy: DefaultSortingStrategy.instance()
52+
}]);
5353
expect(dataGenerator.getValuesForColumn(res, 'number'))
54-
.toEqual([4, 0, 1, 2, 3]);
54+
.toEqual([4, 0, 1, 2, 3]);
55+
});
56+
57+
it('should not sort when sorting direction is None', () => {
58+
const unsortedData = [{ number: 3 }, { number: 1 }, { number: 4 }, { number: 0 }, { number: 2 }];
59+
const res = sorting.sort(unsortedData, [{
60+
dir: SortingDirection.None,
61+
fieldName: 'number',
62+
ignoreCase: false,
63+
strategy: DefaultSortingStrategy.instance()
64+
}]);
65+
expect(res.map(d => d.number))
66+
.toEqual([3, 1, 4, 0, 2]);
5567
});
5668

5769
});

projects/igniteui-angular/src/lib/directives/focus-trap/focus-trap.directive.spec.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { IgxFocusTrapDirective } from './focus-trap.directive';
55

66
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
77
import { UIInteractions } from '../../test-utils/ui-interactions.spec';
8+
import { IgxTimePickerComponent } from '../../time-picker/time-picker.component';
89

910
describe('igxFocusTrap', () => {
1011
beforeEach(waitForAsync(() => {
@@ -161,6 +162,39 @@ describe('igxFocusTrap', () => {
161162
fix.detectChanges();
162163
expect(document.activeElement).toEqual(button.nativeElement);
163164
}));
165+
166+
it('should focus only visible focusable elements on Tab key pressed', () => {
167+
const fix = TestBed.createComponent(TrapFocusTestComponent);
168+
fix.detectChanges();
169+
170+
fix.componentInstance.showTimePicker = true;
171+
fix.detectChanges();
172+
173+
const focusTrap = fix.debugElement.query(By.directive(IgxFocusTrapDirective));
174+
const buttons = fix.debugElement.queryAll(By.css('button'));
175+
const inputs = fix.debugElement.queryAll(By.css('input'));
176+
const timePickerInput = fix.debugElement.query(By.css('.igx-input-group__input'));
177+
178+
UIInteractions.triggerEventHandlerKeyDown('Tab', focusTrap);
179+
fix.detectChanges();
180+
expect(document.activeElement).toEqual(inputs[0].nativeElement);
181+
182+
UIInteractions.triggerEventHandlerKeyDown('Tab', focusTrap);
183+
fix.detectChanges();
184+
expect(document.activeElement).toEqual(inputs[1].nativeElement);
185+
186+
UIInteractions.triggerEventHandlerKeyDown('Tab', focusTrap);
187+
fix.detectChanges();
188+
expect(document.activeElement).toEqual(timePickerInput.nativeElement);
189+
190+
UIInteractions.triggerEventHandlerKeyDown('Tab', focusTrap);
191+
fix.detectChanges();
192+
expect(document.activeElement).toEqual(buttons[buttons.length - 1].nativeElement);
193+
194+
UIInteractions.triggerEventHandlerKeyDown('Tab', focusTrap);
195+
fix.detectChanges();
196+
expect(document.activeElement).toEqual(inputs[0].nativeElement);
197+
});
164198
});
165199

166200

@@ -177,14 +211,19 @@ describe('igxFocusTrap', () => {
177211
<input type="password" placeholder="Enter Password" name="psw">
178212
}
179213
<br>
214+
@if (showTimePicker) {
215+
<igx-time-picker> </igx-time-picker>
216+
}
217+
<br>
180218
@if (showButton) {
181219
<button>SIGN IN</button>
182220
}
183221
</div>`,
184-
imports: [IgxFocusTrapDirective]
222+
imports: [IgxFocusTrapDirective, IgxTimePickerComponent]
185223
})
186224
class TrapFocusTestComponent {
187225
public showInput = true;
188226
public showButton = true;
189227
public focusTrap = true;
228+
public showTimePicker = false;
190229
}

projects/igniteui-angular/src/lib/directives/focus-trap/focus-trap.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class IgxFocusTrapDirective implements AfterViewInit, OnDestroy {
8080
private getFocusableElements(element: Element) {
8181
return Array.from(element.querySelectorAll(
8282
'a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'
83-
)).filter(el => !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden'));
83+
)).filter(el => !el.hasAttribute('disabled') && !el.closest('[aria-hidden="true"]'));
8484
}
8585

8686
private getFocusedElement(): HTMLElement | null {

projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,22 @@ describe('IgxInput', () => {
908908

909909
expect(formControl.touched).toBe(true);
910910
}));
911+
912+
it('should update validity when control is marked as touched', fakeAsync(() => {
913+
const fixture = TestBed.createComponent(ReactiveFormComponent);
914+
fixture.detectChanges();
915+
916+
const component = fixture.componentInstance;
917+
const igxInput = component.strIgxInput;
918+
919+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
920+
921+
component.markAllAsTouched();
922+
tick();
923+
fixture.detectChanges();
924+
925+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
926+
}));
911927
});
912928

913929
@Component({
@@ -1201,6 +1217,12 @@ class ReactiveFormComponent {
12011217
this.textareaControl.markAsTouched();
12021218
this.textareaControl.updateValueAndValidity();
12031219
}
1220+
1221+
public markAllAsTouched() {
1222+
if (!this.form.valid) {
1223+
this.form.markAllAsTouched();
1224+
}
1225+
}
12041226
}
12051227

12061228
@Component({

projects/igniteui-angular/src/lib/directives/input/input.directive.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import {
1616
import {
1717
AbstractControl,
1818
NgControl,
19-
NgModel
19+
NgModel,
20+
TouchedChangeEvent
2021
} from '@angular/forms';
21-
import { Subscription } from 'rxjs';
22+
import { filter, Subscription } from 'rxjs';
2223
import { IgxInputGroupBase } from '../../input-group/input-group.common';
2324

2425
const nativeValidationAttributes = [
@@ -100,6 +101,7 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
100101
private _valid = IgxInputState.INITIAL;
101102
private _statusChanges$: Subscription;
102103
private _valueChanges$: Subscription;
104+
private _touchedChanges$: Subscription;
103105
private _fileNames: string;
104106
private _disabled = false;
105107

@@ -313,6 +315,14 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
313315
this._valueChanges$ = this.ngControl.valueChanges.subscribe(
314316
this.onValueChanged.bind(this)
315317
);
318+
319+
if (this.ngControl.control) {
320+
this._touchedChanges$ = this.ngControl.control.events
321+
.pipe(filter(e => e instanceof TouchedChangeEvent))
322+
.subscribe(
323+
this.updateValidityState.bind(this)
324+
);
325+
}
316326
}
317327

318328
this.cdr.detectChanges();
@@ -326,6 +336,10 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
326336
if (this._valueChanges$) {
327337
this._valueChanges$.unsubscribe();
328338
}
339+
340+
if (this._touchedChanges$) {
341+
this._touchedChanges$.unsubscribe();
342+
}
329343
}
330344
/**
331345
* Sets a focus on the igxInput.

projects/igniteui-angular/src/lib/grids/columns/column.component.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,13 +1597,6 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy
15971597
return !this.grid.isPinningToStart && pinnedCols[0] === this;
15981598
}
15991599

1600-
/** @hidden @internal **/
1601-
public get rightPinnedOffset(): string {
1602-
return this.pinned && !this.grid.isPinningToStart ?
1603-
- this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' :
1604-
null;
1605-
}
1606-
16071600
/** @hidden @internal **/
16081601
public get gridRowSpan(): number {
16091602
return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;

projects/igniteui-angular/src/lib/grids/common/strategy.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { IGroupingState } from '../../data-operations/groupby-state.interface';
55
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
66
import { IGroupByResult } from '../../data-operations/grouping-result.interface';
77
import { getHierarchy, isHierarchyMatch } from '../../data-operations/operations';
8-
import { DefaultSortingStrategy, ISortingExpression } from '../../data-operations/sorting-strategy';
8+
import { DefaultSortingStrategy, ISortingExpression, SortingDirection } from '../../data-operations/sorting-strategy';
99
import { GridType } from './grid.interface';
1010

1111
const DATE_TYPE = 'date';
@@ -229,7 +229,11 @@ export class IgxSorting implements IGridSortingStrategy {
229229
const isDate = column?.dataType === DATE_TYPE || column?.dataType === DATE_TIME_TYPE;
230230
const isTime = column?.dataType === TIME_TYPE || column?.dataType === DATE_TIME_TYPE;
231231
const isString = column?.dataType === STRING_TYPE;
232-
data = expr.strategy.sort(data, expr.fieldName, expr.dir, expr.ignoreCase, this.getFieldValue, isDate, isTime, grid);
232+
if (expr.dir === SortingDirection.None) {
233+
data = this.sortDataRecursive(data, expressions, expressionIndex + 1, grid);
234+
} else {
235+
data = expr.strategy.sort(data, expr.fieldName, expr.dir, expr.ignoreCase, this.getFieldValue, isDate, isTime, grid);
236+
}
233237
if (expressionIndex === exprsLen - 1) {
234238
return data;
235239
}

projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-conditional-filter.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
[igxDropDownItemNavigation]="subMenu"
88
role="menuitem"
99
aria-haspopup="true"
10-
[attr.aria-controls]="this.subMenu?.listId"
11-
[attr.aria-activedescendant]="!this.subMenu?.collapsed ? this.subMenu?.focusedItem?.id : null">
10+
[attr.aria-controls]="subMenu?.listId"
11+
[attr.aria-activedescendant]="!subMenu?.collapsed ? subMenu?.focusedItem?.id : null">
1212
<span class="igx-excel-filter__filter-number">
1313
{{ subMenuText }}
1414
@if (filterNumber > 0) { ({{filterNumber}}) }

0 commit comments

Comments
 (0)