Skip to content

Commit

Permalink
feat(tree-view): enable "type ahead"/letter key navigation by default
Browse files Browse the repository at this point in the history
All tree views should implement letter key navigation. It's not optional.

See VPAT-604 and https://www.w3.org/WAI/ARIA/apg/example-index/treeview/treeview-1/treeview-1a.html.

BREAKING CHANGE:
- The `ClrForTypeAhead` directive and the `ClrForTypeAheadModule` have been removed.
- If you are importing the `ClrForTypeAheadModule`, you can just remove it.
- If you are using the `ClrForTypeAhead` directive class, you will need to adjust your code.
- The `clrForTypeAhead` input will still work on `clr-tree-node` elements.
- If your tree nodes have non-visible text (e.g. screen reader text), you will likely need to set the `clrForTypeAhead` input to just the visible text for the letter key navigation to work properly.
  • Loading branch information
kevinbuhmann committed Dec 19, 2022
1 parent 3346573 commit 46e663c
Show file tree
Hide file tree
Showing 17 changed files with 80 additions and 1,538 deletions.
126 changes: 50 additions & 76 deletions projects/angular/clarity.api.md

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions projects/angular/src/clr-angular.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { ClrSpinnerModule } from './progress/spinner/spinner.module';
import { ClrTimelineModule } from './timeline/timeline.module';
import { ClrConditionalModule } from './utils/conditional/conditional.module';
import { ClrFocusOnViewInitModule } from './utils/focus/focus-on-view-init/focus-on-view-init.module';
import { ClrForTypeAheadModule } from './utils/for-type-ahead/for-type-ahead.module';
import { ClrLoadingModule } from './utils/loading/loading.module';
import { ClrPopoverModuleNext } from './utils/popover/popover.module';
import { ClrWizardModule } from './wizard/wizard.module';
Expand All @@ -37,7 +36,6 @@ import '@cds/core/icon/register';
ClrLoadingModule,
ClrConditionalModule,
ClrFocusOnViewInitModule,
ClrForTypeAheadModule,
ClrButtonModule,
ClrFormsModule,
ClrLayoutModule,
Expand Down
4 changes: 2 additions & 2 deletions projects/angular/src/data/tree-view/tree-node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,21 @@ export default function (): void {
this.parent = new ClrTreeNode(
platformID,
undefined,
undefined,
this.featureService,
this.expandService,
stringsService,
this.focusManagerService,
{ nativeElement: document.createElement('div') },
null
);
this.node = new ClrTreeNode(
platformID,
this.parent,
undefined,
this.featureService,
this.expandService,
stringsService,
this.focusManagerService,
{ nativeElement: document.createElement('div') },
null
);
});
Expand Down
33 changes: 20 additions & 13 deletions projects/angular/src/data/tree-view/tree-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
Output,
PLATFORM_ID,
QueryList,
Self,
SkipSelf,
ViewChild,
} from '@angular/core';
Expand All @@ -31,7 +30,6 @@ import { debounceTime, filter } from 'rxjs/operators';
import { IfExpandService } from '../../utils/conditional/if-expanded.service';
import { KeyCodes } from '../../utils/enums/key-codes.enum';
import { isKeyEitherLetterOrNumber, keyValidator, preventArrowKeyScroll } from '../../utils/focus/key-focus/util';
import { ForTypeAheadProvider } from '../../utils/for-type-ahead/for-type-ahead.service';
import { ClrCommonStringsService } from '../../utils/i18n/common-strings.service';
import { uniqueIdFactory } from '../../utils/id-generator/id-generator.service';
import { LoadingListener } from '../../utils/loading/loading-listener';
Expand Down Expand Up @@ -79,11 +77,11 @@ export class ClrTreeNode<T> implements OnInit, AfterContentInit, OnDestroy {
@Optional()
@SkipSelf()
parent: ClrTreeNode<T>,
@Optional() @Self() private forTypeAheadProvider: ForTypeAheadProvider,
public featuresService: TreeFeaturesService<T>,
public expandService: IfExpandService,
public commonStrings: ClrCommonStringsService,
private focusManager: TreeFocusManagerService<T>,
private elementRef: ElementRef<HTMLElement>,
injector: Injector
) {
if (this.featuresService.recursion) {
Expand Down Expand Up @@ -166,6 +164,11 @@ export class ClrTreeNode<T> implements OnInit, AfterContentInit, OnDestroy {
this.expandService.expanded = value;
}

@Input('clrForTypeAhead')
set clrForTypeAhead(value: string) {
this._model.textContent = trimAndLowerCase(value || this.elementRef.nativeElement.textContent);
}

@Output('clrExpandedChange') expandedChange = new EventEmitter<boolean>();

private subscriptions: Subscription[] = [];
Expand Down Expand Up @@ -204,17 +207,17 @@ export class ClrTreeNode<T> implements OnInit, AfterContentInit, OnDestroy {
}

ngAfterContentInit() {
if (this.forTypeAheadProvider) {
this._model.textContent = this.forTypeAheadProvider.textContent;

this.subscriptions.push(
this.typeAheadKeyEvent.pipe(debounceTime(TREE_TYPE_AHEAD_TIMEOUT)).subscribe((bufferedKeys: string) => {
this.focusManager.focusNodeStartsWith(bufferedKeys, this._model);
// reset once bufferedKeys are used
this.typeAheadKeyBuffer = '';
})
);
if (!this._model.textContent) {
this._model.textContent = trimAndLowerCase(this.elementRef.nativeElement.textContent);
}

this.subscriptions.push(
this.typeAheadKeyEvent.pipe(debounceTime(TREE_TYPE_AHEAD_TIMEOUT)).subscribe((bufferedKeys: string) => {
this.focusManager.focusNodeStartsWith(bufferedKeys, this._model);
// reset once bufferedKeys are used
this.typeAheadKeyBuffer = '';
})
);
}

ngOnDestroy() {
Expand Down Expand Up @@ -351,3 +354,7 @@ export class ClrTreeNode<T> implements OnInit, AfterContentInit, OnDestroy {
}
}
}

function trimAndLowerCase(value: string) {
return value.toLocaleLowerCase().trim();
}
17 changes: 8 additions & 9 deletions projects/angular/src/data/tree-view/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

import { ClrForTypeAheadModule } from '../../utils/for-type-ahead/for-type-ahead.module';
import { spec, TestContext } from '../../utils/testing/helpers.spec';
import { RecursiveChildren } from './recursive-children';
import { ClrTree } from './tree';
Expand All @@ -35,18 +34,18 @@ class TestComponent {
@Component({
template: `
<clr-tree>
<clr-tree-node clrForTypeAhead [clrExpanded]="true">
<clr-tree-node [clrExpanded]="true">
California
<clr-tree-node clrForTypeAhead>San Francisco</clr-tree-node>
<clr-tree-node clrForTypeAhead>Los Angeles</clr-tree-node>
<clr-tree-node>San Francisco</clr-tree-node>
<clr-tree-node>Los Angeles</clr-tree-node>
</clr-tree-node>
<clr-tree-node clrForTypeAhead [clrExpanded]="true">
<clr-tree-node [clrExpanded]="true">
Washington
<clr-tree-node clrForTypeAhead>Seattle</clr-tree-node>
<clr-tree-node>Seattle</clr-tree-node>
</clr-tree-node>
<clr-tree-node clrForTypeAhead [clrExpanded]="false">
<clr-tree-node [clrExpanded]="false">
Vermont
<clr-tree-node clrForTypeAhead>Burlington</clr-tree-node>
<clr-tree-node>Burlington</clr-tree-node>
</clr-tree-node>
</clr-tree>
`,
Expand Down Expand Up @@ -122,7 +121,7 @@ export default function (): void {
let forTypeAheadDirectiveDEs: DebugElement[];
let forTypeAheadDirectives: ClrTreeNode<any>[];

spec(ClrTree, TreeTypeAhead, ClrTreeViewModule, { imports: [NoopAnimationsModule, ClrForTypeAheadModule] });
spec(ClrTree, TreeTypeAhead, ClrTreeViewModule, { imports: [NoopAnimationsModule] });

beforeEach(function (this: Context) {
forTypeAheadDirectiveDEs = this.fixture.debugElement.queryAll(By.directive(ClrTreeNode));
Expand Down
16 changes: 0 additions & 16 deletions projects/angular/src/utils/for-type-ahead/for-type-ahead.module.ts

This file was deleted.

This file was deleted.

61 changes: 0 additions & 61 deletions projects/angular/src/utils/for-type-ahead/for-type-ahead.spec.ts

This file was deleted.

50 changes: 0 additions & 50 deletions projects/angular/src/utils/for-type-ahead/for-type-ahead.ts

This file was deleted.

8 changes: 0 additions & 8 deletions projects/angular/src/utils/for-type-ahead/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion projects/angular/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ export * from './i18n/index';
export * from './popover/index';
export * from './focus/focus-on-view-init/index';
export * from './destroy';
export * from './for-type-ahead/index';
2 changes: 0 additions & 2 deletions projects/demo/src/app/tree-view/tree-view.demo.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { TreeNodeRoutingRevolverDemo } from './tree-node-routing/tree-node-routi
import { TreeNodeRoutingRubberSoulDemo } from './tree-node-routing/tree-node-routing-rubber-soul';
import { TreeViewDemo } from './tree-view.demo';
import { ROUTING } from './tree-view.demo.routing';
import { TypeAheadTreeViewDemo } from './type-ahead/tree-view-type-ahead';

@NgModule({
imports: [CommonModule, ClarityModule, ROUTING, UtilsDemoModule],
Expand All @@ -37,7 +36,6 @@ import { TypeAheadTreeViewDemo } from './type-ahead/tree-view-type-ahead';
TreeNodeRoutingRevolverDemo,
TreeNodeRoutingRubberSoulDemo,
PreSelectionDemo,
TypeAheadTreeViewDemo,
],
exports: [TreeViewDemo],
})
Expand Down
2 changes: 0 additions & 2 deletions projects/demo/src/app/tree-view/tree-view.demo.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { TreeNodeRoutingAbbeyRoadDemo } from './tree-node-routing/tree-node-rout
import { TreeNodeRoutingRevolverDemo } from './tree-node-routing/tree-node-routing-revolver';
import { TreeNodeRoutingRubberSoulDemo } from './tree-node-routing/tree-node-routing-rubber-soul';
import { TreeViewDemo } from './tree-view.demo';
import { TypeAheadTreeViewDemo } from './type-ahead/tree-view-type-ahead';

const ROUTES: Routes = [
{
Expand All @@ -41,7 +40,6 @@ const ROUTES: Routes = [
],
},
{ path: 'pre-selection', component: PreSelectionDemo },
{ path: 'type-ahead', component: TypeAheadTreeViewDemo },
],
},
];
Expand Down
1 change: 0 additions & 1 deletion projects/demo/src/app/tree-view/tree-view.demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { Component } from '@angular/core';
<li><a [routerLink]="['./nodes-with-icons']">Nodes with icons</a></li>
<li><a [routerLink]="['./routing']">Routing tree</a></li>
<li><a [routerLink]="['./pre-selection']">Pre-selection cases dump</a></li>
<li><a [routerLink]="['./type-ahead']">Type Ahead</a></li>
</ul>
<router-outlet></router-outlet>
`,
Expand Down
Loading

0 comments on commit 46e663c

Please sign in to comment.