Skip to content
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

feat(tree): improve screen reader support #102

Merged
merged 35 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
409b40a
feat(list): improve screen reader
Jidapa-Pai Nov 23, 2021
7c0b5d5
feat(list): add aria-multiselectable for screen reader
Jidapa-Pai Nov 24, 2021
42642d2
test(list): improve key control cases
Jidapa-Pai Nov 24, 2021
41def04
test(tree): update snapshots for tree
Jidapa-Pai Nov 24, 2021
e503ca1
Merge branch 'develop' into accessibility/list
Jidapa-Pai Nov 24, 2021
679a550
feat(tree): add roles to tree and treee-item and add aria-expanded
phetw Nov 25, 2021
a40080a
Merge remote-tracking branch 'origin/accessibility/list' into accessi…
phetw Nov 29, 2021
035d4c4
fix: add more generic type to default role for extendibility
phetw Nov 30, 2021
61be64b
Merge branch 'develop' into accessibility/list
wsuwt Nov 30, 2021
3dcb321
Merge remote-tracking branch 'origin/accessibility/list' into accessi…
phetw Nov 30, 2021
6cdc4aa
refactor: use setAttribute instead of overriding AOM properties
phetw Dec 1, 2021
7898ed6
refactor: aria expanded and selected logics
phetw Dec 2, 2021
c55afab
Merge remote-tracking branch 'origin/develop' into accessibility/tree
phetw Dec 2, 2021
ea704b2
feat: add aria level and setsize support
phetw Dec 7, 2021
6f1d279
feat: remove asterick key support
phetw Dec 7, 2021
86b5838
feat: used aria-checked for multiple mode to indicate indeterminate s…
phetw Dec 7, 2021
00e7114
Merge branch 'develop' into accessibility/tree
wsuwt Dec 7, 2021
51d2a37
chore: update lock file
phetw Dec 8, 2021
cca053f
refactor: simplify aria setting logics
phetw Dec 8, 2021
6f39f73
feat: add generic type to treeitem defaulRole
phetw Dec 8, 2021
6aec07c
fix: handles multiple mode changes
phetw Dec 9, 2021
f4721e6
test(tree): update snapshots
Jidapa-Pai Dec 9, 2021
3aa7cac
Merge branch 'accessibility/tree' of github.com:Refinitiv/refinitiv-u…
Jidapa-Pai Dec 9, 2021
9844d88
refactor: reflect aria-selected according to selected state
phetw Dec 13, 2021
44ca8d9
Merge branch 'develop' into accessibility/tree
wsuwt Dec 14, 2021
18c8bf8
Merge branch 'develop' into accessibility/tree
wsuwt Dec 15, 2021
5531634
Merge branch 'develop' into accessibility/tree
wsuwt Dec 15, 2021
9d0b2be
Merge branch 'develop' into accessibility/tree
wsuwt Dec 15, 2021
5cab00f
refactor: move most of the aria setting logics to tree-item element
phetw Dec 16, 2021
05b2760
Merge branch 'develop' into accessibility/tree
wsuwt Dec 16, 2021
c911c82
Merge branch 'develop' into accessibility/tree
wsuwt Dec 21, 2021
6e9cb09
Merge branch 'develop' into accessibility/tree
wsuwt Dec 24, 2021
a59379d
Merge branch 'develop' into accessibility/tree
wsuwt Jan 5, 2022
f1a86e1
refactor: remove aria-setsize as it's no longer needed
phetw Jan 5, 2022
2468ab3
Merge branch 'develop' into accessibility/tree
wsuwt Jan 12, 2022
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
6 changes: 6 additions & 0 deletions packages/elements/src/list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ export class List<T extends DataItem = ItemData> extends ControlElement {
@property({ type: Boolean })
public stateless = false;

/**
* Aria indicating that list supports multiple selection
*/
@property({ type: String, reflect: true, attribute: 'aria-multiselectable' })
public ariaMultiselectable = 'false';

/**
* Allow multiple selections
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/elements/src/tree/__snapshots__/Tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
```html
<ef-tree
aria-multiselectable="false"
role="listbox"
role="tree"
>
</ef-tree>

Expand Down
118 changes: 94 additions & 24 deletions packages/elements/src/tree/elements/tree-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export class TreeItem<T extends TreeDataItem = TreeDataItem> extends ControlElem
return VERSION;
}

protected readonly defaultRole: string | null = 'treeitem';

/**
* Checked state of the item
*/
Expand Down Expand Up @@ -61,7 +63,7 @@ export class TreeItem<T extends TreeDataItem = TreeDataItem> extends ControlElem
/**
* Depth of the item
*/
@property({ reflect: true, type: Number })
@property({ type: Number, reflect: true })
public depth = 0;

/**
Expand Down Expand Up @@ -103,10 +105,7 @@ export class TreeItem<T extends TreeDataItem = TreeDataItem> extends ControlElem
*/
protected get toggleTemplate (): TemplateResult {
return html`
<div
expand-toggle
part="toggle"
style="pointer-events:all;visibility:${this.parent ? 'visible' : 'hidden'}">
<div expand-toggle part="toggle" style="pointer-events:all;visibility:${this.parent ? 'visible' : 'hidden'}">
<ef-icon part="toggle-icon${this.expanded ? ' toggle-icon-expanded' : ''}" icon="right"></ef-icon>
</div>
`;
Expand All @@ -119,23 +118,25 @@ export class TreeItem<T extends TreeDataItem = TreeDataItem> extends ControlElem
if (!this.multiple) {
return emptyTemplate;
}

return html`
<ef-checkbox
part="checkbox"
tabindex="-1"
.disabled="${this.disabled}"
.readonly="${this.readonly}"
.indeterminate="${this.indeterminate}"
.checked="${this.checked}"
style="pointer-events:none"></ef-checkbox>
part="checkbox"
tabindex="-1"
.disabled="${this.disabled}"
.readonly="${this.readonly}"
.indeterminate="${this.indeterminate}"
.checked="${this.checked}"
style="pointer-events:none">
</ef-checkbox>
`;
}

/**
* Template for rendering the icon
*/
protected get iconTemplate (): TemplateResult {
if(typeof this.icon === 'undefined') {
if (typeof this.icon === 'undefined') {
return emptyTemplate;
}

Expand All @@ -156,24 +157,93 @@ export class TreeItem<T extends TreeDataItem = TreeDataItem> extends ControlElem
return this.checkedState === CheckedState.INDETERMINATE;
}

/**
* Handles aria-checked and aria-selected when mode changes
* aria-checked is used for multiple mode due to tri-state support
* @returns {void}
**/
private multipleChanged (): void {
this.removeAttribute(this.multiple ? 'aria-selected' : 'aria-checked');
this.checkedChanged();
}

/**
* Handles selected and aria attribute changes
* @returns {void}
*/
private checkedChanged (): void {
switch (this.checkedState) {
case CheckedState.CHECKED:
this.setAttribute('selected', '');
this.setAttribute(this.multiple ? 'aria-checked' : 'aria-selected', 'true');
break;
case CheckedState.INDETERMINATE:
this.setAttribute('selected', 'indeterminate');
this.setAttribute('aria-checked', 'mixed');
break;
default:
this.removeAttribute('selected');

// In single mode, only children nodes are selectable
if (this.parent && !this.multiple) {
this.removeAttribute('aria-selected');
}
else {
this.setAttribute(this.multiple ? 'aria-checked' : 'aria-selected', 'false');
}

break;
}
}

/**
* Handles aria-expanded when expanded state changes
* @returns {void}
*/
private expandedChanged () :void {
if (this.parent) {
this.setAttribute('aria-expanded', this.expanded ? 'true' : 'false');
}
}

/**
* Called after the component is first rendered
* @param changedProperties Properties which have changed
* @returns {void}
*/
protected firstUpdated (changedProperties: PropertyValues): void {
super.firstUpdated(changedProperties);
this.setAttribute('aria-level', String(this.depth + 1));
}

/**
* Invoked whenever the element is updated
* @param changedProperties Map of changed properties with old values
* @returns {void}
*/
protected update (changedProperties: PropertyValues): void {
super.update(changedProperties);

if (changedProperties.has('checkedState')) {
switch (this.checkedState) {
case CheckedState.CHECKED:
this.setAttribute('selected', '');
break;
case CheckedState.INDETERMINATE:
this.setAttribute('selected', 'indeterminate');
break;
default:
this.removeAttribute('selected');
}
this.checkedChanged();
}

if (changedProperties.has('multiple') && changedProperties.get('multiple') !== undefined) {
this.multipleChanged();
}

if (changedProperties.has('expanded')) {
this.expandedChanged();
}
}

/**
* A `TemplateResult` that will be used
* to render the updated internal template.
* @returns Render template
*/
protected render (): TemplateResult {
return html `
return html`
${this.indentTemplate}
${this.toggleTemplate}
${this.checkboxTemplate}
Expand Down
2 changes: 2 additions & 0 deletions packages/elements/src/tree/elements/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export class Tree<T extends TreeDataItem = TreeDataItem> extends List<T> {
return VERSION;
}

protected readonly defaultRole: string | null = 'tree';

/**
* Tree manager used for manipulation
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/elements/src/tree/helpers/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type RendererScope = {

export class TreeRenderer extends Renderer {
constructor (scope?: unknown) {

let manager: TreeManager<TreeDataItem>;
let currentMode: TreeManagerMode;
let currentComposer: CollectionComposer<TreeDataItem>;
Expand All @@ -36,6 +37,7 @@ export class TreeRenderer extends Renderer {
el.disabled = composer.getItemPropertyValue(item, 'disabled') === true;
el.readonly = composer.getItemPropertyValue(item, 'readonly') === true;
el.highlighted = composer.getItemPropertyValue(item, 'highlighted') === true;

return el;
});
}
Expand Down
1 change: 0 additions & 1 deletion packages/elements/src/tree/managers/tree-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,5 +439,4 @@ export class TreeManager<T extends TreeDataItem> {
public uncheckAllItems (): void {
this.editableItems.forEach(item => this.uncheckItem(item));
}

}