Skip to content

refactor(material/tree): docs updates and rename variables #28238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/cdk/a11y/key-manager/noop-tree-key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ import {
/**
* @docs-private
*
* Opt-out of Tree of key manager behavior.
*
* When provided, Tree has same focus management behavior as before TreeKeyManager was introduced.
* - Tree does not respond to keyboard interaction
* - Tree node allows tabindex to be set by Input binding
* - Tree node allows tabindex to be set by attribute binding
*
* @deprecated NoopTreeKeyManager deprecated. Use TreeKeyManager or inject a
* TreeKeyManagerStrategy instead. To be removed in a future version.
*
Expand Down Expand Up @@ -62,6 +69,13 @@ export class NoopTreeKeyManager<T extends TreeKeyManagerItem> implements TreeKey
/**
* @docs-private
*
* Opt-out of Tree of key manager behavior.
*
* When provided, Tree has same focus management behavior as before TreeKeyManager was introduced.
* - Tree does not respond to keyboard interaction
* - Tree node allows tabindex to be set by Input binding
* - Tree node allows tabindex to be set by attribute binding
*
* @deprecated NoopTreeKeyManager deprecated. Use TreeKeyManager or inject a
* TreeKeyManagerStrategy instead. To be removed in a future version.
*
Expand All @@ -76,6 +90,13 @@ export function NOOP_TREE_KEY_MANAGER_FACTORY<
/**
* @docs-private
*
* Opt-out of Tree of key manager behavior.
*
* When provided, Tree has same focus management behavior as before TreeKeyManager was introduced.
* - Tree does not respond to keyboard interaction
* - Tree node allows tabindex to be set by Input binding
* - Tree node allows tabindex to be set by attribute binding
*
* @deprecated NoopTreeKeyManager deprecated. Use TreeKeyManager or inject a
* TreeKeyManagerStrategy instead. To be removed in a future version.
*
Expand Down
11 changes: 5 additions & 6 deletions src/cdk/a11y/key-manager/tree-key-manager-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,20 @@ export interface TreeKeyManagerItem {
export interface TreeKeyManagerOptions<T extends TreeKeyManagerItem> {
/**
* If true, then the key manager will call `activate` in addition to calling `focus` when a
* particular item is focused. By default, this is false.
* particular item is focused.
*/
activationFollowsFocus?: boolean;
shouldActivationFollowFocus?: boolean;

/**
* The direction in which the tree items are laid out horizontally. This influences which key
* will be interpreted as expand or collapse. Defaults to 'ltr'.
* will be interpreted as expand or collapse.
*/
horizontalOrientation?: 'rtl' | 'ltr';

/**
* Sets the predicate function that determines which items should be skipped by the tree key
* manager. By default, disabled items are skipped.
* If provided, navigation "skips" over items that pass the given predicate.
*
* If the item is to be skipped, this function should return false.
* If the item is to be skipped, predicate function should return false.
*/
skipPredicate?: (item: T) => boolean;

Expand Down
29 changes: 20 additions & 9 deletions src/cdk/a11y/key-manager/tree-key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ function coerceObservable<T>(data: T | Observable<T>): Observable<T> {
export class TreeKeyManager<T extends TreeKeyManagerItem> implements TreeKeyManagerStrategy<T> {
private _activeItemIndex = -1;
private _activeItem: T | null = null;
private _activationFollowsFocus = false;
private _horizontal: 'ltr' | 'rtl' = 'ltr';
private _shouldActivationFollowFocus = false;
private _horizontalOrientation: 'ltr' | 'rtl' = 'ltr';

// Keep tree items focusable when disabled. Align with
// https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#focusabilityofdisabledcontrols.
Expand Down Expand Up @@ -85,6 +85,14 @@ export class TreeKeyManager<T extends TreeKeyManagerItem> implements TreeKeyMana
this._hasInitialFocused = true;
}

/**
*
* @param items List of TreeKeyManager options. Can be synchronous or asynchronous.
* @param config Optional configuration options. By default, use 'ltr' horizontal orientation. By
* default, do not skip any nodes. By default, key manager only calls `focus` method when items
* are focused and does not call `activate`. If `typeaheadDefaultInterval` is `true`, use a
* default interval of 200ms.
*/
constructor(items: Observable<T[]> | QueryList<T> | T[], config: TreeKeyManagerOptions<T>) {
// We allow for the items to be an array or Observable because, in some cases, the consumer may
// not have access to a QueryList of the items they want to manage (e.g. when the
Expand All @@ -109,11 +117,11 @@ export class TreeKeyManager<T extends TreeKeyManagerItem> implements TreeKeyMana
this._initialFocus();
}

if (typeof config.activationFollowsFocus === 'boolean') {
this._activationFollowsFocus = config.activationFollowsFocus;
if (typeof config.shouldActivationFollowFocus === 'boolean') {
this._shouldActivationFollowFocus = config.shouldActivationFollowFocus;
}
if (config.horizontalOrientation) {
this._horizontal = config.horizontalOrientation;
this._horizontalOrientation = config.horizontalOrientation;
}
if (config.skipPredicate) {
this._skipPredicateFn = config.skipPredicate;
Expand Down Expand Up @@ -157,11 +165,15 @@ export class TreeKeyManager<T extends TreeKeyManagerItem> implements TreeKeyMana
break;

case RIGHT_ARROW:
this._horizontal === 'rtl' ? this._collapseCurrentItem() : this._expandCurrentItem();
this._horizontalOrientation === 'rtl'
? this._collapseCurrentItem()
: this._expandCurrentItem();
break;

case LEFT_ARROW:
this._horizontal === 'rtl' ? this._expandCurrentItem() : this._collapseCurrentItem();
this._horizontalOrientation === 'rtl'
? this._expandCurrentItem()
: this._collapseCurrentItem();
break;

case HOME:
Expand Down Expand Up @@ -264,11 +276,10 @@ export class TreeKeyManager<T extends TreeKeyManagerItem> implements TreeKeyMana
previousActiveItem?.unfocus();

if (options.emitChangeEvent) {
// Emit to `change` stream as required by TreeKeyManagerStrategy interface.
this.change.next(this._activeItem);
}

if (this._activationFollowsFocus) {
if (this._shouldActivationFollowFocus) {
this._activateCurrentItem();
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/cdk/tree/toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ import {CdkTree, CdkTreeNode} from './tree';

/**
* Node toggle to expand and collapse the node.
*
* CdkTreeNodeToggle is intended only to be used on native button elements, elements with button role,
* or elements with treeitem role.
*/
@Directive({
selector: '[cdkTreeNodeToggle]',
Expand Down
46 changes: 22 additions & 24 deletions src/cdk/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,14 @@ export class CdkTree<T, K = T>
private _parents: Map<K, T | null> = new Map<K, T | null>();

/**
* The internal node groupings for each node; we use this to determine where
* a particular node is within each group. This allows us to compute the
* correct aria attribute values.
* Nodes grouped into each set, which is a list of nodes displayed together in the DOM.
*
* The structure of this is that:
* - the outer index is the level
* - the inner index is the parent node for this particular group. If there is no parent node, we
* use `null`.
* Lookup key is the parent of a set. Root nodes have key of null.
*
* Values is a 'set' of tree nodes. Each tree node maps to a treeitem element. Sets are in the
* order that it is rendered. Each set maps directly to aria-posinset and aria-setsize attributes.
*/
private _groups: Map<K | null, T[]> = new Map<K | null, T[]>();
private _ariaSets: Map<K | null, T[]> = new Map<K | null, T[]>();

/**
* Provides a stream containing the latest data array to render. Influenced by the tree's
Expand Down Expand Up @@ -500,10 +498,10 @@ export class CdkTree<T, K = T>
this.insertNode(data[currentIndex!], currentIndex!, viewContainer, parentData);
} else if (currentIndex == null) {
viewContainer.remove(adjustedPreviousIndex!);
const group = this._getNodeGroup(item.item);
const set = this._getAriaSet(item.item);
const key = this._getExpansionKey(item.item);
group.splice(
group.findIndex(groupItem => this._getExpansionKey(groupItem) === key),
set.splice(
set.findIndex(groupItem => this._getExpansionKey(groupItem) === key),
1,
);
} else {
Expand Down Expand Up @@ -784,8 +782,8 @@ export class CdkTree<T, K = T>
* This is intended to be used for `aria-setsize`.
*/
_getSetSize(dataNode: T) {
const group = this._getNodeGroup(dataNode);
return group.length;
const set = this._getAriaSet(dataNode);
return set.length;
}

/**
Expand All @@ -794,9 +792,9 @@ export class CdkTree<T, K = T>
* This is intended to be used for `aria-posinset`.
*/
_getPositionInSet(dataNode: T) {
const group = this._getNodeGroup(dataNode);
const set = this._getAriaSet(dataNode);
const key = this._getExpansionKey(dataNode);
return group.findIndex(node => this._getExpansionKey(node) === key) + 1;
return set.findIndex(node => this._getExpansionKey(node) === key) + 1;
}

/** Given a CdkTreeNode, gets the node that renders that node's parent's data. */
Expand Down Expand Up @@ -902,12 +900,12 @@ export class CdkTree<T, K = T>
return this.expansionKey?.(dataNode) ?? (dataNode as unknown as K);
}

private _getNodeGroup(node: T) {
private _getAriaSet(node: T) {
const key = this._getExpansionKey(node);
const parent = this._parents.get(key);
const parentKey = parent ? this._getExpansionKey(parent) : null;
const group = this._groups.get(parentKey);
return group ?? [node];
const set = this._ariaSets.get(parentKey);
return set ?? [node];
}

/**
Expand Down Expand Up @@ -963,7 +961,7 @@ export class CdkTree<T, K = T>
children.pipe(
take(1),
tap(childNodes => {
this._groups.set(parentKey, [...(childNodes ?? [])]);
this._ariaSets.set(parentKey, [...(childNodes ?? [])]);
for (const child of childNodes ?? []) {
const childKey = this._getExpansionKey(child);
this._parents.set(childKey, node);
Expand Down Expand Up @@ -1006,7 +1004,7 @@ export class CdkTree<T, K = T>
// nested.
if (this.childrenAccessor && nodeType === 'flat') {
// This flattens children into a single array.
this._groups.set(null, [...nodes]);
this._ariaSets.set(null, [...nodes]);
return this._flattenNestedNodesWithExpansion(nodes).pipe(
map(flattenedNodes => ({
renderNodes: flattenedNodes,
Expand Down Expand Up @@ -1039,7 +1037,7 @@ export class CdkTree<T, K = T>
} else {
// For nested nodes, we still need to perform the node flattening in order
// to maintain our caches for various tree operations.
this._groups.set(null, [...nodes]);
this._ariaSets.set(null, [...nodes]);
return this._flattenNestedNodesWithExpansion(nodes).pipe(
map(flattenedNodes => ({
renderNodes: nodes,
Expand All @@ -1065,7 +1063,7 @@ export class CdkTree<T, K = T>
}

this._parents.clear();
this._groups.clear();
this._ariaSets.clear();

for (let index = 0; index < flattenedNodes.length; index++) {
const dataNode = flattenedNodes[index];
Expand All @@ -1075,9 +1073,9 @@ export class CdkTree<T, K = T>
this._parents.set(key, parent);
const parentKey = parent ? this._getExpansionKey(parent) : null;

const group = this._groups.get(parentKey) ?? [];
const group = this._ariaSets.get(parentKey) ?? [];
group.splice(index, 0, dataNode);
this._groups.set(parentKey, group);
this._ariaSets.set(parentKey, group);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tools/public_api_guard/cdk/a11y.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,8 @@ export interface TreeKeyManagerItem {

// @public
export interface TreeKeyManagerOptions<T extends TreeKeyManagerItem> {
activationFollowsFocus?: boolean;
horizontalOrientation?: 'rtl' | 'ltr';
shouldActivationFollowFocus?: boolean;
skipPredicate?: (item: T) => boolean;
trackBy?: (treeItem: T) => unknown;
typeAheadDebounceInterval?: true | number;
Expand Down