Skip to content

Commit c0a0ed3

Browse files
authored
Merge branch 'master' into rivanova/fix-16458-master
2 parents a1a58a7 + 1281679 commit c0a0ed3

27 files changed

Lines changed: 416 additions & 183 deletions

.github/workflows/npm-publish.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
name: Npm.js deploy
22
permissions:
3+
id-token: write
34
contents: read
45

56
on:
@@ -10,12 +11,16 @@ jobs:
1011
build:
1112
runs-on: ubuntu-latest
1213
steps:
13-
- uses: actions/checkout@v3
14-
- uses: actions/setup-node@v3
14+
- uses: actions/checkout@v4
15+
- uses: actions/setup-node@v4
1516
with:
1617
node-version: 22
1718
cache: 'npm'
1819
registry-url: 'https://registry.npmjs.org'
20+
21+
- name: Update NPM
22+
run: npm install -g npm@latest
23+
1924
- run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
2025
- run: echo ${VERSION}
2126

@@ -60,11 +65,7 @@ jobs:
6065
- name: Publish igniteui-angular
6166
run: npm publish --tag ${NPM_TAG}
6267
working-directory: dist/igniteui-angular
63-
env:
64-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
6568

6669
- name: Publish igniteui-angular-i18n
6770
run: npm publish --tag ${NPM_TAG}
6871
working-directory: dist/igniteui-angular-i18n
69-
env:
70-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

CHANGELOG.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22

33
All notable changes for each version of this project will be documented in this file.
44

5-
## 21.2.0
6-
7-
### Breaking Changes
8-
9-
- `igxForOf`, `igxGrid`, `igxTreeGrid`, `igxHierarchicalGrid`, `igxPivotGrid`
10-
- original `data` array mutations (like adding/removing/moving records in the original array) are no longer detected automatically. Components need an array ref change for the change to be detected.
11-
125
## 21.1.0
136

147
### New Features
@@ -23,7 +16,16 @@ All notable changes for each version of this project will be documented in this
2316
<span #tooltipRef="tooltip" igxTooltip>Hello there, I am a tooltip!</span>
2417
```
2518

26-
# Localization(i18n)
19+
### General
20+
- `IgxCombo`, `IgxSimpleCombo`
21+
- Combo and Simple Combo now close the dropdown list and move the focus to the next focusable element on "Tab" press and clear the selection if the combo is collapsed on "Escape".
22+
23+
### Breaking Changes
24+
25+
- `igxForOf`, `igxGrid`, `igxTreeGrid`, `igxHierarchicalGrid`, `igxPivotGrid`
26+
- original `data` array mutations (like adding/removing/moving records in the original array) are no longer detected automatically. Components need an array ref change for the change to be detected.
27+
28+
### Localization(i18n)
2729

2830
- `IgxActionStrip`, `IgxBanner`, `IgxCalendar`, `IgxCarousel`, `IgxChip`, `IgxCombo`, `IgxDatePicker`, `IgxDateRangePicker`, `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`, `IgxPivotGrid`, `IgxInputs`, `IgxList`, `IgxPaginator`, `IgxQueryBuilder`, `IgxTimePicker`, `IgxTree`
2931
- New `Intl` implementation for all currently supported components that format and render data like dates and numbers.

projects/igniteui-angular/combo/src/combo/combo-dropdown.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
155155
/**
156156
* @hidden @internal
157157
*/
158-
public override onItemActionKey(key: DropDownActionKey) {
158+
public override onItemActionKey(key: DropDownActionKey, event?: KeyboardEvent) {
159159
switch (key) {
160160
case DropDownActionKey.ENTER:
161161
this.handleEnter();
@@ -164,8 +164,10 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
164164
this.handleSpace();
165165
break;
166166
case DropDownActionKey.ESCAPE:
167-
case DropDownActionKey.TAB:
168167
this.close();
168+
break;
169+
case DropDownActionKey.TAB:
170+
this.close(event);
169171
}
170172
}
171173

projects/igniteui-angular/combo/src/combo/combo.common.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,8 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
12211221
return;
12221222
}
12231223
this.searchValue = '';
1224-
if (!e.event) {
1224+
const isTab = (e.event as KeyboardEvent)?.key === 'Tab';
1225+
if (!e.event || isTab) {
12251226
this.comboInput?.nativeElement.focus();
12261227
} else {
12271228
this._onTouchedCallback();
@@ -1241,13 +1242,8 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
12411242
event.stopPropagation();
12421243
this.close();
12431244
}
1244-
}
1245-
1246-
/** @hidden @internal */
1247-
public handleToggleKeyDown(eventArgs: KeyboardEvent) {
1248-
if (eventArgs.key === 'Enter' || eventArgs.key === ' ') {
1249-
eventArgs.preventDefault();
1250-
this.toggle();
1245+
if (event.key === 'Tab') {
1246+
this.close();
12511247
}
12521248
}
12531249

projects/igniteui-angular/combo/src/combo/combo.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</ng-container>
2121
@if (displayValue) {
2222
<igx-suffix [attr.aria-label]="resourceStrings.igx_combo_clearItems_placeholder" class="igx-combo__clear-button"
23-
(click)="handleClearItems($event)" (keydown)="handleClearKeyDown($event)" [tabindex]="disabled ? -1 : 0" role="button">
23+
(click)="handleClearItems($event)">
2424
@if (clearIconTemplate) {
2525
<ng-container *ngTemplateOutlet="clearIconTemplate"></ng-container>
2626
}
@@ -29,7 +29,7 @@
2929
}
3030
</igx-suffix>
3131
}
32-
<igx-suffix class="igx-combo__toggle-button" (keydown)="handleToggleKeyDown($event)" [tabindex]="disabled ? -1 : 0" role="button">
32+
<igx-suffix class="igx-combo__toggle-button">
3333
@if (toggleIconTemplate) {
3434
<ng-container *ngTemplateOutlet="toggleIconTemplate; context: {$implicit: collapsed}"></ng-container>
3535
}

projects/igniteui-angular/combo/src/combo/combo.component.spec.ts

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,15 +1798,93 @@ describe('igxCombo', () => {
17981798
fixture.detectChanges();
17991799
expect(firstVisibleItem.classList.contains(CSS_CLASS_FOCUSED)).toBeTruthy();
18001800
}));
1801-
it('should close the dropdown list on pressing Tab key', fakeAsync(() => {
1801+
it('should close the dropdown list on pressing Tab key and focus the next focusable element', fakeAsync(() => {
18021802
combo.toggle();
18031803
fixture.detectChanges();
18041804

18051805
const dropdownContent = fixture.debugElement.query(By.css(`.${CSS_CLASS_CONTENT}`));
1806+
const dropdownList = fixture.debugElement.query(By.css(`.${CSS_CLASS_DROPDOWNLIST_SCROLL}`)).nativeElement;
1807+
UIInteractions.triggerEventHandlerKeyDown('Tab', dropdownContent);
1808+
tick();
1809+
fixture.detectChanges();
1810+
expect(combo.collapsed).toBeTruthy();
1811+
1812+
combo.toggle();
1813+
fixture.detectChanges();
1814+
expect(combo.collapsed).toBeFalsy();
1815+
1816+
let focusedItems = dropdownList.querySelectorAll(`.${CSS_CLASS_FOCUSED}`);
1817+
let selectedItems = dropdownList.querySelectorAll(`.${CSS_CLASS_SELECTED}`);
1818+
expect(focusedItems.length).toEqual(0);
1819+
expect(selectedItems.length).toEqual(0);
1820+
1821+
UIInteractions.triggerEventHandlerKeyDown('ArrowDown', dropdownContent);
1822+
fixture.detectChanges();
1823+
focusedItems = dropdownList.querySelectorAll(`.${CSS_CLASS_FOCUSED}`);
1824+
expect(focusedItems.length).toEqual(1);
1825+
18061826
UIInteractions.triggerEventHandlerKeyDown('Tab', dropdownContent);
18071827
tick();
18081828
fixture.detectChanges();
18091829
expect(combo.collapsed).toBeTruthy();
1830+
expect(document.activeElement).not.toEqual(combo.comboInput.nativeElement);
1831+
1832+
combo.toggle();
1833+
fixture.detectChanges();
1834+
expect(combo.collapsed).toBeFalsy();
1835+
1836+
UIInteractions.triggerEventHandlerKeyDown('ArrowDown', dropdownContent);
1837+
fixture.detectChanges();
1838+
focusedItems = dropdownList.querySelectorAll(`.${CSS_CLASS_FOCUSED}`);
1839+
expect(focusedItems.length).toEqual(1);
1840+
1841+
UIInteractions.triggerEventHandlerKeyDown('Space', dropdownContent);
1842+
fixture.detectChanges();
1843+
selectedItems = dropdownList.querySelectorAll(`.${CSS_CLASS_SELECTED}`);
1844+
expect(selectedItems.length).toEqual(1);
1845+
1846+
UIInteractions.triggerEventHandlerKeyDown('Tab', dropdownContent);
1847+
tick();
1848+
fixture.detectChanges();
1849+
expect(combo.collapsed).toBeTruthy();
1850+
expect(document.activeElement).not.toEqual(combo.comboInput.nativeElement);
1851+
}));
1852+
it('should clear the selection and preserve the focus when the combo is collapsed and Escape key is pressed', fakeAsync(() => {
1853+
combo.comboInput.nativeElement.focus();
1854+
fixture.detectChanges();
1855+
expect(document.activeElement).toEqual(combo.comboInput.nativeElement);
1856+
1857+
combo.select([combo.data[0][combo.valueKey]]);
1858+
expect(combo.selection.length).toEqual(1);
1859+
fixture.detectChanges();
1860+
1861+
combo.onEscape(UIInteractions.getKeyboardEvent('keydown', 'Escape'));
1862+
tick();
1863+
fixture.detectChanges();
1864+
expect(document.activeElement).toEqual(combo.comboInput.nativeElement);
1865+
expect(combo.selection.length).toEqual(0);
1866+
}));
1867+
it('should close the combo and preserve the focus when Escape key is pressed', fakeAsync(() => {
1868+
combo.comboInput.nativeElement.focus();
1869+
fixture.detectChanges();
1870+
expect(document.activeElement).toEqual(combo.comboInput.nativeElement);
1871+
1872+
combo.toggle();
1873+
fixture.detectChanges();
1874+
expect(combo.collapsed).toBeFalsy();
1875+
1876+
const dropdownContent = fixture.debugElement.query(By.css(`.${CSS_CLASS_CONTENT}`));
1877+
1878+
UIInteractions.triggerEventHandlerKeyDown('ArrowDown', dropdownContent);
1879+
fixture.detectChanges();
1880+
1881+
UIInteractions.triggerEventHandlerKeyDown('Escape', dropdownContent);
1882+
fixture.detectChanges();
1883+
expect(document.activeElement).toEqual(combo.comboInput.nativeElement);
1884+
1885+
tick();
1886+
fixture.detectChanges();
1887+
expect(combo.collapsed).toBeTruthy();
18101888
}));
18111889
});
18121890
describe('primitive data dropdown: ', () => {
@@ -2137,37 +2215,6 @@ describe('igxCombo', () => {
21372215
cancel: false
21382216
});
21392217
});
2140-
it('should toggle combo dropdown on Enter of the focused toggle icon', fakeAsync(() => {
2141-
spyOn(combo, 'toggle').and.callThrough();
2142-
const toggleBtn = fixture.debugElement.query(By.css(`.${CSS_CLASS_TOGGLEBUTTON}`));
2143-
2144-
UIInteractions.triggerEventHandlerKeyDown('Enter', toggleBtn);
2145-
tick();
2146-
fixture.detectChanges();
2147-
expect(combo.toggle).toHaveBeenCalledTimes(1);
2148-
expect(combo.collapsed).toEqual(false);
2149-
2150-
UIInteractions.triggerEventHandlerKeyDown('Enter', toggleBtn);
2151-
tick();
2152-
fixture.detectChanges();
2153-
expect(combo.toggle).toHaveBeenCalledTimes(2);
2154-
expect(combo.collapsed).toEqual(true);
2155-
}));
2156-
it('should clear the selection on Enter of the focused clear icon', () => {
2157-
const selectedItem_1 = combo.dropdown.items[1];
2158-
combo.toggle();
2159-
fixture.detectChanges();
2160-
simulateComboItemClick(1);
2161-
expect(combo.selection[0]).toEqual(selectedItem_1.value);
2162-
expect(combo.value[0]).toEqual(selectedItem_1.value[combo.valueKey]);
2163-
2164-
const clearBtn = fixture.debugElement.query(By.css(`.${CSS_CLASS_CLEARBUTTON}`));
2165-
UIInteractions.triggerEventHandlerKeyDown('Enter', clearBtn);
2166-
fixture.detectChanges();
2167-
expect(input.nativeElement.value).toEqual('');
2168-
expect(combo.selection.length).toEqual(0);
2169-
expect(combo.value.length).toEqual(0);
2170-
});
21712218
it('should not be able to select group header', () => {
21722219
spyOn(combo.selectionChanging, 'emit').and.callThrough();
21732220
combo.toggle();

projects/igniteui-angular/combo/src/combo/combo.component.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie
185185
this.open();
186186
}
187187

188+
@HostListener('keydown.Escape', ['$event'])
189+
public onEscape(event: Event) {
190+
if (this.collapsed) {
191+
this.deselectAllItems(true, event);
192+
}
193+
}
194+
188195
/** @hidden @internal */
189196
public get displaySearchInput(): boolean {
190197
return !this.disableFiltering || this.allowCustomValues;
@@ -253,7 +260,10 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie
253260
/**
254261
* @hidden @internal
255262
*/
256-
public clearInput(event: Event): void {
263+
public handleClearItems(event: Event): void {
264+
if (this.disabled) {
265+
return;
266+
}
257267
this.deselectAllItems(true, event);
258268
if (this.collapsed) {
259269
this.getEditElement().focus();
@@ -263,26 +273,6 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie
263273
event.stopPropagation();
264274
}
265275

266-
/**
267-
* @hidden @internal
268-
*/
269-
public handleClearItems(event: Event): void {
270-
if (this.disabled) {
271-
return;
272-
}
273-
this.clearInput(event);
274-
}
275-
276-
/**
277-
* @hidden @internal
278-
*/
279-
public handleClearKeyDown(eventArgs: KeyboardEvent) {
280-
if (eventArgs.key === 'Enter' || eventArgs.key === ' ') {
281-
eventArgs.preventDefault();
282-
this.clearInput(eventArgs);
283-
}
284-
}
285-
286276
/**
287277
* Select defined items
288278
*

projects/igniteui-angular/core/src/core/styles/components/button/_button-theme.scss

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,6 @@
6161
$variant
6262
);
6363

64-
$button-transition: color var(--_init-transition, #{$time}) ease-in-out,
65-
background-color var(--_init-transition, #{$time}) ease-in-out,
66-
border-color var(--_init-transition, #{$time}) ease-in-out,
67-
box-shadow var(--_init-transition, #{$time}) ease-in-out;
68-
6964
$button-disabled-shadow: none;
7065

7166
$button-floating-width: rem(56px);
@@ -287,6 +282,12 @@
287282
}
288283

289284
%igx-button-display {
285+
--_button-transition:
286+
color var(--_init-transition, #{$time}) ease-in-out,
287+
background-color var(--_init-transition, #{$time}) ease-in-out,
288+
border-color var(--_init-transition, #{$time}) ease-in-out,
289+
box-shadow var(--_init-transition, #{$time}) ease-in-out;
290+
290291
@include sizable();
291292

292293
position: relative;
@@ -312,7 +313,7 @@
312313
-webkit-tap-highlight-color: transparent;
313314
overflow: hidden;
314315
white-space: nowrap;
315-
transition: $button-transition;
316+
transition: var(--_button-transition);
316317
gap: pad-inline(
317318
map.get($items-gap, 'compact'),
318319
map.get($items-gap, 'cosy'),
@@ -330,7 +331,7 @@
330331
width: var(--igx-icon-size, #{$icon-in-button-size});
331332
height: var(--igx-icon-size, #{$icon-in-button-size});
332333
font-size: var(--igx-icon-size, #{$icon-in-button-size});
333-
transition: $button-transition;
334+
transition: var(--_button-transition);
334335
}
335336
}
336337

@@ -525,7 +526,7 @@
525526
color: var-get($outlined-theme, 'focus-visible-foreground');
526527
border-color: var-get($outlined-theme, 'focus-visible-border-color');
527528

528-
@if $variant == 'material' or $variant == 'bootstrap' {
529+
@if $variant == 'material' or $variant == 'bootstrap' {
529530
igx-icon {
530531
color: var-get($outlined-theme, 'icon-color-hover');
531532
}
@@ -701,7 +702,7 @@
701702
align-items: center;
702703
outline: none;
703704
cursor: pointer;
704-
transition: $button-transition;
705+
transition: var(--_button-transition);
705706
user-select: none;
706707
-webkit-tap-highlight-color: transparent;
707708
overflow: hidden;

0 commit comments

Comments
 (0)