Skip to content

Commit b608e1f

Browse files
BobobUnicornzarend
authored andcommitted
feat(material/tree): revamp tree data model, accessibility and documentation
Iterate on Tree component to improve its data model, accessibility and documentation. Introduce levelAcessor and childrenAccessor as an alternative to TreeController. Given a data node, childrenAccessor determines the children of that node. Given a data node, levelAccessor determines level of the node. One of levelAccessor or childrenAccessor must be specified, not both. Implement keyboard navigation in Tree component to align with [WAI ARIA Tree View Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/). Make changes directly to Cdk tree API, which also apply to Mat tree APIs. See “Breaking Change” and “Deprecated” sections below for specifics on adopting changes. Accessibility improvements * Implement keyboard navigation for CdkTree and MatTree * Implement keyboard usability for CdkTreeNodeToggle. * Improve ARIA semantics for CdkTree, CdkTreeNode, Tree and TreeNode components * Make accessibility fixes to tree and cdk-tree examples * Add accessibility instructions to documentation Documentation updates * Add API and usage examples for TreeKeyManager * Update @angular/cdk/tree and @angular/material/tree to be more consistent * Update examples to use levelAccessor and childrenAccessor * Add example for (activation) on MatTreeNode and CdkTreeNode BREAKING CHANGE: Tree component uses a levelAcessor or childrenAccessor as alternative to a controller. - CdkTree requires either a levelAccessor or childrenAccessor as Input. Cannot specify both. - CdkTree optionally takes a expansionKey as Input. expansionKey is a function that returns key of a given node. CdkTree uses key to determine expanded state. - Add isExpanded, toggle, expand and collapse methods to CdkTree - Add toggleDescendants, expandDescendants, and collapseDescendants methods to CdkTree - Add expandAll and collapseAll methods to CdkTree BREAKING CHANGE: By default, tree nodes cannot be expanded and collapsed. Use isExpanded function to specify nodes that can be expanded and collapsed. - Add isExpandable and isExpanded Inputs to CdkTreeNode to specify if argument tree node can be expanded or collapsed. - Add isExpandable function to NestedTreeControlOptions to determine if argument tree node can be expanded or collapsed. BREAKING CHANGE: Add methods and Outputs to CdkTreeNode to manage the activated, expanded and collapsed state. - Add activate, expand and collapse methods to CdkTreeNode - Add activation Output to CdkTreeNode - Add expandedChange Output to CdkTreeNode BREAKING CHANGE: Use isDisabled to set the disabled state of tree nodes. - Add isDisabled Input to CdkTreeNode. By default, nodes are not disabled. BREAKING CHANGE: MatTree and CdkTree components responds to keyboard navigation. - CdkTree and MatTree respond to arrow keys, page up, page down, etc.; Keyboard commands align with [WAI ARIA Tree View Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/). - Add TreeKeyManager class - CdkTree consumes TreeKeyManager - Can no longer set the tabindex on MatTreeNode. MatTreeNode ignores the passed value of tabindex. MatTreeNode always has a tabindex attribute of “-1”. BREAKING CHANGE: CdkTreeNodeToggle directive and component respond to keyboard navigation. - CdkTreeNodeToggle toggles expanded state on Enter or Space keypress DEPRECATED: Tree controllers deprecated. Use one of levelAccessor or childrenAccessor instead. To be removed in a future version. * BaseTreeControl deprecated * TreeControl deprecated * FlatTreeControl deprecated * NestedTreeControl deprecated * treeControl Input on CdkTree deprecated in favor of using one of levelAccessor childrenAccessor Inputs. DEPRECATED: Setting tabindex of tree nodes deprecated. * `@Input tabIndex` on `MatTreeNode` deprecated. MatTreeNode ignores Input tabIndex and manages its own focus behavior. * `@Input defaultTabIndex` on `MatTreeNode` deprecated. MatTreeNode ignores Input defaultTabIndex and manages its own focus behavior. * `@Input tabIndex` on `MatNestedTreeNode` deprecated. MatTreeNode ignores Input defaultTabIndex and manages its own focus behavior. DEPRECATED: disabled Input renamed to isDiabled. disabled to be deleted in a future version. * disabled Input deprecated and alias to isDisabled * disabled Input deprecated and alias to isDiabled
1 parent 47ac55f commit b608e1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+6160
-418
lines changed

src/cdk/a11y/a11y.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Navigation through options can be made to wrap via the `withWrap` method
2727
this.keyManager = new FocusKeyManager(...).withWrap();
2828
```
2929

30-
#### Types of key managers
30+
#### Types of list key managers
3131

3232
There are two varieties of `ListKeyManager`, `FocusKeyManager` and `ActiveDescendantKeyManager`.
3333

@@ -55,6 +55,64 @@ interface Highlightable extends ListKeyManagerOption {
5555

5656
Each item must also have an ID bound to the listbox's or menu's `aria-activedescendant`.
5757

58+
### TreeKeyManager
59+
60+
`TreeKeyManager` manages the active option in a tree view. This is intended to be used with
61+
components that correspond to a `role="tree"` pattern.
62+
63+
#### Basic usage
64+
65+
Any component that uses a `TreeKeyManager` will generally do three things:
66+
* Create a `@ViewChildren` query for the tree items being managed.
67+
* Initialize the `TreeKeyManager`, passing in the options.
68+
* Forward keyboard events from the managed component to the `TreeKeyManager` via `onKeydown`.
69+
70+
Each tree item should implement the `TreeKeyManagerItem` interface:
71+
```ts
72+
interface TreeKeyManagerItem {
73+
/** Whether the item is disabled. */
74+
isDisabled?: (() => boolean) | boolean;
75+
76+
/** The user-facing label for this item. */
77+
getLabel?(): string;
78+
79+
/** Perform the main action (i.e. selection) for this item. */
80+
activate(): void;
81+
82+
/** Retrieves the parent for this item. This is `null` if there is no parent. */
83+
getParent(): TreeKeyManagerItem | null;
84+
85+
/** Retrieves the children for this item. */
86+
getChildren(): TreeKeyManagerItem[] | Observable<TreeKeyManagerItem[]>;
87+
88+
/** Determines if the item is currently expanded. */
89+
isExpanded: (() => boolean) | boolean;
90+
91+
/** Collapses the item, hiding its children. */
92+
collapse(): void;
93+
94+
/** Expands the item, showing its children. */
95+
expand(): void;
96+
97+
/**
98+
* Focuses the item. This should provide some indication to the user that this item is focused.
99+
*/
100+
focus(): void;
101+
}
102+
```
103+
104+
#### Focus management
105+
106+
The `TreeKeyManager` will handle focusing the appropriate item on keyboard interactions. However,
107+
the component should call `onInitialFocus` when the component is focused for the first time (i.e.
108+
when there is no active item).
109+
110+
`tabindex` should also be set by the component when the active item changes. This can be listened to
111+
via the `change` property on the `TreeKeyManager`. In particular, the tree should only have a
112+
`tabindex` set if there is no active item, and should not have a `tabindex` set if there is an
113+
active item. Only the HTML node corresponding to the active item should have a `tabindex` set to
114+
`0`, with all other items set to `-1`.
115+
58116

59117
### FocusTrap
60118

0 commit comments

Comments
 (0)