From fcdb126f2fcccf696e199e617c5df3f696e79c4b Mon Sep 17 00:00:00 2001 From: Elizabeth Mitchell Date: Wed, 14 Jun 2023 14:41:30 -0700 Subject: [PATCH] fix(chips): add aria grid/listbox models to chip set PiperOrigin-RevId: 540384126 --- chips/demo/stories.ts | 22 ++++++++++++++------- chips/lib/_chip-set.scss | 6 ++++++ chips/lib/_shared.scss | 4 ++++ chips/lib/chip-set.ts | 28 +++++++++++++++++++++++++-- chips/lib/chip.ts | 34 ++++++++++++++++++++++++++------- chips/lib/filter-chip.ts | 16 +++++++++++++--- chips/lib/input-chip.ts | 7 +++++-- chips/lib/multi-action-chip.ts | 35 +++++++++++++++++++++++++++++----- chips/lib/trailing-icons.ts | 9 ++++++++- 9 files changed, 134 insertions(+), 27 deletions(-) diff --git a/chips/demo/stories.ts b/chips/demo/stories.ts index 37e4502ad4..b9252f88d0 100644 --- a/chips/demo/stories.ts +++ b/chips/demo/stories.ts @@ -50,7 +50,8 @@ const standard: MaterialStoryInit = { render({label, elevated, disabled, scrolling}) { const classes = {scrolling}; return html` - + = { render({label, elevated, disabled, scrolling}) { const classes = {scrolling}; return html` - + = { render({label, elevated, disabled, scrolling, singleSelect}) { const classes = {scrolling}; return html` - + = { render({label, disabled, scrolling}) { const classes = {scrolling}; return html` - + = { render({label, disabled, scrolling}) { const classes = {scrolling}; return html` - + = { render({label, elevated, disabled, scrolling}) { const classes = {scrolling}; return html` - + = { render({label, elevated, disabled, scrolling}) { const classes = {scrolling}; return html` - + child instanceof Chip); } + @property() type: ChipSetType = ''; @property({type: Boolean, attribute: 'single-select'}) singleSelect = false; @queryAssignedElements({flatten: true}) @@ -49,7 +62,18 @@ export class ChipSet extends LitElement { } protected override render() { - return html``; + const {ariaLabel} = this as ARIAMixinStrict; + const isFilter = this.type === 'filter'; + const role = isFilter ? 'listbox' : 'grid'; + const multiselectable = isFilter ? !this.singleSelect : nothing; + return html` +
+ +
+ `; } private handleKeyDown(event: KeyboardEvent) { diff --git a/chips/lib/chip.ts b/chips/lib/chip.ts index f55520b835..bd36427642 100644 --- a/chips/lib/chip.ts +++ b/chips/lib/chip.ts @@ -7,8 +7,8 @@ import '../../focus/focus-ring.js'; import '../../ripple/ripple.js'; -import {html, LitElement, TemplateResult} from 'lit'; -import {property} from 'lit/decorators.js'; +import {html, LitElement, nothing, TemplateResult} from 'lit'; +import {property, state} from 'lit/decorators.js'; import {classMap} from 'lit/directives/class-map.js'; import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js'; @@ -43,14 +43,21 @@ export abstract class Chip extends LitElement { return this.disabled; } + /** + * The aria role of the container. Defaults to `row` for grid chip sets. + * Listbox chip sets should remove this since they do not contain cells. + */ + @state() protected containerRole?: 'row' = 'row'; + protected override render() { return html` -
+
${this.renderOutline()} - ${this.renderAction()} + ${this.renderActions()}
`; } @@ -61,9 +68,24 @@ export abstract class Chip extends LitElement { }; } + protected renderActions() { + return this.renderActionCell(this.renderAction()); + } + + protected renderActionCell(content: TemplateResult| + typeof nothing): TemplateResult|typeof nothing { + if (content === nothing) { + return content; + } + + return html`
${content}
`; + } + + protected abstract renderAction(): TemplateResult; + protected renderContent() { return html` - + ${this.label} @@ -71,8 +93,6 @@ export abstract class Chip extends LitElement { `; } - protected abstract renderAction(): TemplateResult; - protected renderOutline() { return html``; } diff --git a/chips/lib/filter-chip.ts b/chips/lib/filter-chip.ts index 75745dd1a4..f759cb8b37 100644 --- a/chips/lib/filter-chip.ts +++ b/chips/lib/filter-chip.ts @@ -6,7 +6,7 @@ import '../../elevation/elevation.js'; -import {html, nothing, PropertyValues, svg} from 'lit'; +import {html, nothing, PropertyValues, svg, TemplateResult} from 'lit'; import {property, query} from 'lit/decorators.js'; import {ARIAMixinStrict} from '../../internal/aria/aria.js'; @@ -32,6 +32,9 @@ export class FilterChip extends MultiActionChip { constructor() { super(); + // Remove the `row` role from the container, since filter chips do not use a + // `grid` navigation model. + this.containerRole = undefined; this.addEventListener('click', () => { if (this.disabled) { return; @@ -56,7 +59,13 @@ export class FilterChip extends MultiActionChip { }; } - protected override renderPrimaryAction() { + protected override renderActionCell(content: TemplateResult|typeof nothing) { + // Filter chips use a `listbox`/`option` model, and do not need `gridcell` + // wrappers around their actions. + return content; + } + + protected override renderAction() { const {ariaLabel} = this as ARIAMixinStrict; return html`