From 1db7550f6fb60003caf21043b5613150320c37c6 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Tue, 22 Aug 2023 17:03:57 -0400 Subject: [PATCH 01/13] feat(button): add ability to pass down ARIA attributes --- .../src/components/button/pharos-button.ts | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index dedef5bf6..0028ee4d0 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -20,6 +20,18 @@ export type ButtonVariant = 'primary' | 'secondary' | 'subtle' | 'overlay'; // undefined means no state has been expressed at all and won't render; 'undefined' is an explicit state export type PressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined; +export type ExpandedState = 'false' | 'true' | 'undefined' | undefined; + +export type HasPopupState = + | 'false' + | 'true' + | 'menu' + | 'listbox' + | 'tree' + | 'grid' + | 'dialog' + | undefined; + const TYPES = ['button', 'submit', 'reset'] as ButtonType[]; const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[]; @@ -113,10 +125,17 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) /** * Indicates the aria label to apply to the button. - * @attr label + * @attr a11y-label */ - @property({ type: String, reflect: true }) - public label?: string; + @property({ type: String, reflect: true, attribute: 'a11y-label' }) + public a11yLabel?: string; + + /** + * Indicates the aria expanded state to apply to the button. + * @attr a11y-expanded + */ + @property({ type: String, reflect: true, attribute: 'a11y-expanded' }) + public a11yExpanded: ExpandedState = undefined; /** * Indicates the button's width should match its container. @@ -254,8 +273,9 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ping=${ifDefined(this.ping)} rel=${ifDefined(this.rel)} target=${ifDefined(this.target)} - aria-label=${ifDefined(this.label)} + aria-label=${ifDefined(this.a11yLabel)} aria-pressed=${ifDefined(this.pressed)} + aria-expanded=${ifDefined(this.a11yExpanded)} @keyup=${this._handleKeyup} > ${this.buttonContent} @@ -269,8 +289,9 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ?autofocus=${this.autofocus} ?disabled=${this.disabled} type="${ifDefined(this.type)}" - aria-label=${ifDefined(this.label)} + aria-label=${ifDefined(this.a11yLabel)} aria-pressed=${ifDefined(this.pressed)} + aria-expanded=${ifDefined(this.a11yExpanded)} > ${this.buttonContent} From 0bf72180c9607e2b0c252f14c479e4d5c82b3172 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Tue, 22 Aug 2023 17:08:08 -0400 Subject: [PATCH 02/13] feat(button): add reference to new button types Including the ExpandedState type reference for other components that consume the button. These threw errors when initially compiling so there may be other such commponents that eventually need a similar update. --- .../src/components/sidenav/pharos-sidenav-button.ts | 12 +++++++++--- .../src/components/toast/pharos-toast-button.ts | 10 ++++++++-- .../toggle-button-group/pharos-toggle-button.ts | 3 ++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts index 6dcab2e42..df4421a05 100644 --- a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts +++ b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts @@ -4,8 +4,14 @@ import { PharosButton } from '../button/pharos-button'; import type { PharosSidenav } from './pharos-sidenav'; import type { LinkTarget } from '../base/anchor-element'; -import type { ButtonType, IconName, ButtonVariant, PressedState } from '../button/pharos-button'; -export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState }; +import type { + ButtonType, + IconName, + ButtonVariant, + PressedState, + ExpandedState, +} from '../button/pharos-button'; +export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState, ExpandedState }; /** * Pharos sidenav button component. @@ -18,7 +24,7 @@ export class PharosSidenavButton extends PharosButton { super(); this.icon = 'menu'; this.variant = 'subtle'; - this.label = 'Open menu'; + this.a11yLabel = 'Open menu'; } public static override get styles(): CSSResultArray { diff --git a/packages/pharos/src/components/toast/pharos-toast-button.ts b/packages/pharos/src/components/toast/pharos-toast-button.ts index 7cdb2eab4..0fad3b046 100644 --- a/packages/pharos/src/components/toast/pharos-toast-button.ts +++ b/packages/pharos/src/components/toast/pharos-toast-button.ts @@ -3,9 +3,15 @@ import { toastButtonStyles } from './pharos-toast-button.css'; import { PharosButton } from '../button/pharos-button'; import type { LinkTarget } from '../base/anchor-element'; -import type { ButtonType, IconName, ButtonVariant, PressedState } from '../button/pharos-button'; +import type { + ButtonType, + IconName, + ButtonVariant, + PressedState, + ExpandedState, +} from '../button/pharos-button'; -export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState }; +export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState, ExpandedState }; /** * Pharos toast button component. diff --git a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts index 1952fc9ab..8f1276814 100644 --- a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts +++ b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts @@ -9,8 +9,9 @@ import type { IconName, ButtonVariant, PressedState, + ExpandedState, } from '../button/pharos-button'; -export type { ButtonType, LinkTarget, IconName, ButtonVariant, PressedState }; +export type { ButtonType, LinkTarget, IconName, ButtonVariant, PressedState, ExpandedState }; /** * Pharos toggle button component. From 0a26b517afeb2ad3fc997e38bd41b655c7714cf8 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Tue, 22 Aug 2023 17:11:57 -0400 Subject: [PATCH 03/13] feat(button): attempt at updating storybook example --- .../src/components/button/pharos-button.wc.stories.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.wc.stories.jsx b/packages/pharos/src/components/button/pharos-button.wc.stories.jsx index e24462954..e8af3159d 100644 --- a/packages/pharos/src/components/button/pharos-button.wc.stories.jsx +++ b/packages/pharos/src/components/button/pharos-button.wc.stories.jsx @@ -30,7 +30,8 @@ export const Base = { ?full-width=${ifDefined(args.fullWidth)} href=${ifDefined(args.href)} hreflang=${ifDefined(args.hreflang)} - label=${ifDefined(args.label)} + a11y-label=${ifDefined(args.a11yLabel)} + a11y-expanded=${ifDefined(args.a11yExpanded)} ?large=${ifDefined(args.large)} ?on-background=${ifDefined(args.onBackground)} ping=${ifDefined(args.ping)} @@ -220,7 +221,7 @@ export const IconOnly = { ...Base.args, text: undefined, icon: 'download', - label: 'download', + a11yLabel: 'download', }, }; From 93dcef25ebbe14478029975c671d40cac403af16 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Wed, 23 Aug 2023 10:34:16 -0400 Subject: [PATCH 04/13] feat(button): remove test code for popupstate --- packages/pharos/src/components/button/pharos-button.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index 0028ee4d0..9df00757b 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -22,16 +22,6 @@ export type PressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined; export type ExpandedState = 'false' | 'true' | 'undefined' | undefined; -export type HasPopupState = - | 'false' - | 'true' - | 'menu' - | 'listbox' - | 'tree' - | 'grid' - | 'dialog' - | undefined; - const TYPES = ['button', 'submit', 'reset'] as ButtonType[]; const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[]; From f85d9c66a14f6d14efa5cff983f438f8e42addeb Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Thu, 24 Aug 2023 11:18:52 -0400 Subject: [PATCH 05/13] feat(button): add aria-haspopup --- .../src/components/button/pharos-button.ts | 22 ++++++++++++++++++- .../sidenav/pharos-sidenav-button.ts | 11 +++++++++- .../components/toast/pharos-toast-button.ts | 11 +++++++++- .../pharos-toggle-button.ts | 11 +++++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index 9df00757b..3bb0edb6a 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -22,6 +22,16 @@ export type PressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined; export type ExpandedState = 'false' | 'true' | 'undefined' | undefined; +export type PopupState = + | 'false' + | 'true' + | 'menu' + | 'tree' + | 'grid' + | 'listbox' + | 'dialog' + | undefined; + const TYPES = ['button', 'submit', 'reset'] as ButtonType[]; const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[]; @@ -65,7 +75,6 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) * Indicates the variant of button. * @attr variant */ - @property({ type: String, reflect: true }) public variant: ButtonVariant = 'primary'; /** @@ -127,6 +136,13 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) @property({ type: String, reflect: true, attribute: 'a11y-expanded' }) public a11yExpanded: ExpandedState = undefined; + /** + * Indicates the aria expanded state to apply to the button. + * @attr a11y-haspopup + */ + @property({ type: String, reflect: true, attribute: 'a11y-haspopup' }) + public a11yHaspopup: PopupState = undefined; + /** * Indicates the button's width should match its container. * @attr full-width @@ -254,6 +270,7 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) protected override render(): TemplateResult { return this.href ? html` + ${this.buttonContent} ` : html` + diff --git a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts index df4421a05..e722944d4 100644 --- a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts +++ b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts @@ -10,8 +10,17 @@ import type { ButtonVariant, PressedState, ExpandedState, + PopupState, } from '../button/pharos-button'; -export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState, ExpandedState }; +export type { + LinkTarget, + ButtonType, + IconName, + ButtonVariant, + PressedState, + ExpandedState, + PopupState, +}; /** * Pharos sidenav button component. diff --git a/packages/pharos/src/components/toast/pharos-toast-button.ts b/packages/pharos/src/components/toast/pharos-toast-button.ts index 0fad3b046..ff6cc8c6a 100644 --- a/packages/pharos/src/components/toast/pharos-toast-button.ts +++ b/packages/pharos/src/components/toast/pharos-toast-button.ts @@ -9,9 +9,18 @@ import type { ButtonVariant, PressedState, ExpandedState, + PopupState, } from '../button/pharos-button'; -export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState, ExpandedState }; +export type { + LinkTarget, + ButtonType, + IconName, + ButtonVariant, + PressedState, + ExpandedState, + PopupState, +}; /** * Pharos toast button component. diff --git a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts index 8f1276814..ae245d61e 100644 --- a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts +++ b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts @@ -10,8 +10,17 @@ import type { ButtonVariant, PressedState, ExpandedState, + PopupState, } from '../button/pharos-button'; -export type { ButtonType, LinkTarget, IconName, ButtonVariant, PressedState, ExpandedState }; +export type { + ButtonType, + LinkTarget, + IconName, + ButtonVariant, + PressedState, + ExpandedState, + PopupState, +}; /** * Pharos toggle button component. From f51bee5929cf338463cd30e4930cb30b4d31036c Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Thu, 24 Aug 2023 13:00:14 -0400 Subject: [PATCH 06/13] chore(changeset): add changeset --- .changeset/mighty-planes-poke.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/mighty-planes-poke.md diff --git a/.changeset/mighty-planes-poke.md b/.changeset/mighty-planes-poke.md new file mode 100644 index 000000000..c9cba6b0a --- /dev/null +++ b/.changeset/mighty-planes-poke.md @@ -0,0 +1,7 @@ +--- +'@ithaka/pharos': major +--- + +Add additional ARIA attributes for Pharos button +and use a new naming convention for these specific +pharos attributes. From 67338285243660b4cb23a712d43b8363a813a357 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Fri, 25 Aug 2023 15:34:28 -0400 Subject: [PATCH 07/13] feat(button): update label attr to a11y-label --- .../src/components/alert/pharos-alert.ts | 2 +- .../button/PharosButton.react.stories.jsx | 2 +- .../components/button/pharos-button.test.ts | 2 +- .../components/combobox/pharos-combobox.ts | 4 +-- .../image-card/pharos-image-card.ts | 2 +- .../PharosInputGroup.react.stories.jsx | 16 ++++++------ .../input-group/pharos-input-group.test.ts | 4 +-- .../pharos-input-group.wc.stories.jsx | 26 +++++++++---------- .../src/components/modal/pharos-modal.ts | 2 +- .../sidenav/PharosSidenav.react.stories.jsx | 2 +- .../components/sidenav/pharos-sidenav.test.ts | 2 +- .../src/components/sidenav/pharos-sidenav.ts | 2 +- .../sidenav/pharos-sidenav.wc.stories.jsx | 2 +- .../components/toast/pharos-toast-button.ts | 2 +- .../CollectionCarousel.tsx | 4 +-- .../react/item-carousel/ItemCarousel.tsx | 4 +-- .../react/item-detail.pages.stories.tsx | 10 +++---- .../collection-carousel.ts | 4 +-- .../wc/item-carousel/item-carousel.ts | 4 +-- .../wc/item-detail.pages.stories.ts | 10 +++---- .../pages/reports/react/CreateReportModal.tsx | 4 +-- .../pages/reports/wc/create-report-modal.ts | 4 +-- .../pharos/src/pages/shared/react/Header.tsx | 2 +- .../src/pages/shared/react/HeaderRevised.tsx | 2 +- .../src/pages/shared/wc/header-revised.ts | 2 +- packages/pharos/src/pages/shared/wc/header.ts | 2 +- 26 files changed, 61 insertions(+), 61 deletions(-) diff --git a/packages/pharos/src/components/alert/pharos-alert.ts b/packages/pharos/src/components/alert/pharos-alert.ts index 4fcdf4c97..bba1c0173 100644 --- a/packages/pharos/src/components/alert/pharos-alert.ts +++ b/packages/pharos/src/components/alert/pharos-alert.ts @@ -114,7 +114,7 @@ export class PharosAlert extends ScopedRegistryMixin(FocusMixin(PharosElement)) variant="subtle" icon="close" icon-condensed - label="Close alert" + a11y-label="Close alert" class="alert__button" @click=${this.close} >` diff --git a/packages/pharos/src/components/button/PharosButton.react.stories.jsx b/packages/pharos/src/components/button/PharosButton.react.stories.jsx index 0ab3e58ec..d257d130f 100644 --- a/packages/pharos/src/components/button/PharosButton.react.stories.jsx +++ b/packages/pharos/src/components/button/PharosButton.react.stories.jsx @@ -45,7 +45,7 @@ export const Base = { fullWidth={args.fullWidth} href={args.href} hreflang={args.hreflang} - label={args.label} + a11yLabel={args.a11yLabel} large={args.large} onBackground={args.onBackground} ping={args.ping} diff --git a/packages/pharos/src/components/button/pharos-button.test.ts b/packages/pharos/src/components/button/pharos-button.test.ts index d2cd6b986..f10806bc0 100644 --- a/packages/pharos/src/components/button/pharos-button.test.ts +++ b/packages/pharos/src/components/button/pharos-button.test.ts @@ -26,7 +26,7 @@ describe('pharos-button', () => { it('is accessible as an icon button', async () => { component.icon = 'download'; - component.label = 'download'; + component.a11yLabel = 'download'; await component.updateComplete; await expect(component).to.be.accessible(); }); diff --git a/packages/pharos/src/components/combobox/pharos-combobox.ts b/packages/pharos/src/components/combobox/pharos-combobox.ts index df5936c53..99a3966df 100644 --- a/packages/pharos/src/components/combobox/pharos-combobox.ts +++ b/packages/pharos/src/components/combobox/pharos-combobox.ts @@ -258,7 +258,7 @@ export class PharosCombobox extends ScopedRegistryMixin(FormMixin(FormElement)) variant="subtle" icon="close" ?disabled=${this.disabled} - label="Clear option" + a11y-label="Clear option" @click=${this._handleClearClick} @mousedown=${this._handleClearClick} > @@ -277,7 +277,7 @@ export class PharosCombobox extends ScopedRegistryMixin(FormMixin(FormElement)) type="button" variant="subtle" class="search__button" - label="Search" + a11y-label="Search" ?disabled=${this.disabled} @click=${this.onChange} > diff --git a/packages/pharos/src/components/image-card/pharos-image-card.ts b/packages/pharos/src/components/image-card/pharos-image-card.ts index 9fd51f370..28d28e8ae 100644 --- a/packages/pharos/src/components/image-card/pharos-image-card.ts +++ b/packages/pharos/src/components/image-card/pharos-image-card.ts @@ -367,7 +367,7 @@ export class PharosImageCard extends ScopedRegistryMixin(FocusMixin(PharosElemen icon="ellipses-vertical" variant="subtle" icon-condensed - label="More actions" + a11y-label="More actions" @click=${this._handleClick} >` : html``; diff --git a/packages/pharos/src/components/input-group/PharosInputGroup.react.stories.jsx b/packages/pharos/src/components/input-group/PharosInputGroup.react.stories.jsx index d2a2a4274..6fd9bfdd1 100644 --- a/packages/pharos/src/components/input-group/PharosInputGroup.react.stories.jsx +++ b/packages/pharos/src/components/input-group/PharosInputGroup.react.stories.jsx @@ -38,7 +38,7 @@ export const Base = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -60,7 +60,7 @@ export const Prominent = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -82,7 +82,7 @@ export const Validity = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -91,7 +91,7 @@ export const Validity = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -117,13 +117,13 @@ export const Composition = { name="close-button" icon="close" variant="subtle" - label="close" + a11y-label="close" > @@ -137,7 +137,7 @@ export const Composition = { name="search-with-select-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -146,7 +146,7 @@ export const Composition = { slot="prepend" icon="book" variant="subtle" - label="book" + a11y-label="book" > Prepend diff --git a/packages/pharos/src/components/input-group/pharos-input-group.test.ts b/packages/pharos/src/components/input-group/pharos-input-group.test.ts index d80b5ed2c..c0a3d4b9e 100644 --- a/packages/pharos/src/components/input-group/pharos-input-group.test.ts +++ b/packages/pharos/src/components/input-group/pharos-input-group.test.ts @@ -10,7 +10,7 @@ describe('pharos-input-group', () => { component = await fixture(html` Search - + `); }); @@ -38,7 +38,7 @@ describe('pharos-input-group', () => { slot="prepend" icon="search" variant="subtle" - label="search" + a11y-label="search" > ` diff --git a/packages/pharos/src/components/input-group/pharos-input-group.wc.stories.jsx b/packages/pharos/src/components/input-group/pharos-input-group.wc.stories.jsx index 66c04e14f..a020ad680 100644 --- a/packages/pharos/src/components/input-group/pharos-input-group.wc.stories.jsx +++ b/packages/pharos/src/components/input-group/pharos-input-group.wc.stories.jsx @@ -21,7 +21,7 @@ export const Base = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -38,7 +38,7 @@ export const Prominent = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -47,7 +47,7 @@ export const Prominent = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -56,7 +56,7 @@ export const Prominent = { slot="prepend" icon="book" variant="subtle" - label="book" + a11y-label="book" > prominent Prepend @@ -66,20 +66,20 @@ export const Prominent = { slot="prepend" icon="book" variant="subtle" - label="book" + a11y-label="book" > Multiple buttons @@ -96,7 +96,7 @@ export const Validity = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -105,7 +105,7 @@ export const Validity = { name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -126,13 +126,13 @@ export const Composition = { name="close-button" icon="close" variant="subtle" - label="close" + a11y-label="close" > @@ -146,7 +146,7 @@ export const Composition = { name="search-with-select-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > @@ -155,7 +155,7 @@ export const Composition = { slot="prepend" icon="book" variant="subtle" - label="book" + a11y-label="book" > Prepend diff --git a/packages/pharos/src/components/modal/pharos-modal.ts b/packages/pharos/src/components/modal/pharos-modal.ts index f5e67da19..ca9a406b5 100644 --- a/packages/pharos/src/components/modal/pharos-modal.ts +++ b/packages/pharos/src/components/modal/pharos-modal.ts @@ -275,7 +275,7 @@ export class PharosModal extends ScopedRegistryMixin(PharosElement) { type="button" variant="subtle" icon="close" - label="Close modal" + a11y-label="Close modal" > diff --git a/packages/pharos/src/pages/shared/react/HeaderRevised.tsx b/packages/pharos/src/pages/shared/react/HeaderRevised.tsx index cabaa23d8..9013b776c 100644 --- a/packages/pharos/src/pages/shared/react/HeaderRevised.tsx +++ b/packages/pharos/src/pages/shared/react/HeaderRevised.tsx @@ -58,7 +58,7 @@ export const HeaderRevised: FC
= ({ showSearch = false }) => ( name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > diff --git a/packages/pharos/src/pages/shared/wc/header-revised.ts b/packages/pharos/src/pages/shared/wc/header-revised.ts index 0ac6424d3..b43dee81b 100644 --- a/packages/pharos/src/pages/shared/wc/header-revised.ts +++ b/packages/pharos/src/pages/shared/wc/header-revised.ts @@ -50,7 +50,7 @@ export const HeaderRevised = (showSearch = false): TemplateResult => html` name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > diff --git a/packages/pharos/src/pages/shared/wc/header.ts b/packages/pharos/src/pages/shared/wc/header.ts index 6beb12730..24e6585bc 100644 --- a/packages/pharos/src/pages/shared/wc/header.ts +++ b/packages/pharos/src/pages/shared/wc/header.ts @@ -79,7 +79,7 @@ export const Header = (): TemplateResult => html` name="search-button" icon="search" variant="subtle" - label="search" + a11y-label="search" > From 7b22e074d9b2207af3fdd27b0760451b49bbeca0 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Wed, 30 Aug 2023 15:03:54 -0400 Subject: [PATCH 08/13] feat(button): replace property for ButtonVariant --- packages/pharos/src/components/button/pharos-button.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index 3bb0edb6a..d25a7a872 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -75,6 +75,7 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) * Indicates the variant of button. * @attr variant */ + @property({ type: String, reflect: true }) public variant: ButtonVariant = 'primary'; /** From e5eb07e135bcab15a4a05c9ece720b011d7abb69 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Mon, 18 Sep 2023 12:27:03 -0400 Subject: [PATCH 09/13] feat(button): allow backwards compatibility Gives warning if using deprecated attributes, updating aria-pressed --- .../src/components/button/pharos-button.ts | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index d25a7a872..a9fd10dc4 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -123,6 +123,13 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) @property({ type: Boolean, reflect: true }) public large = false; + /** + * Indicates the aria label to apply to the button. DEPRECRATED + * @attr label + */ + @property({ type: String, reflect: true }) + public label?: string; + /** * Indicates the aria label to apply to the button. * @attr a11y-label @@ -166,12 +173,19 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) public value?: string; /** - * Indicates this button is a toggle button and whether it is pressed or not. + * Indicates this button is a toggle button and whether it is pressed or not. DEPRECATED * @attr value */ @property({ type: String, reflect: true }) public pressed: PressedState = undefined; + /** + * Indicates this button is a toggle button and whether it is pressed or not. + * @attr value + */ + @property({ type: String, reflect: true, attribute: 'a11y-pressed' }) + public a11yPressed: PressedState = undefined; + @query('#button-element') private _button!: HTMLButtonElement | HTMLAnchorElement; @@ -204,6 +218,16 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) `${this.variant} is not a valid variant. Valid variants are: ${VARIANTS.join(', ')}` ); } + + // Warn consumers that the label attribute is being deprecated + if (this.label) { + console.warn("The 'label' attribute is deprecated. Use 'a11y-label' instead."); + } + + // Warn consumers that the pressed attribute is being deprecated + if (this.pressed) { + console.warn("The 'pressed' attribute is deprecated. Use 'a11y-pressed' instead."); + } } override connectedCallback(): void { @@ -269,6 +293,10 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) } protected override render(): TemplateResult { + // Remove in future release once sufficient time elapsed to update naming convention + const a11yLabel = this.a11yLabel ?? this.label; + const a11yPressed = this.a11yPressed ?? this.pressed; + return this.href ? html` @@ -281,8 +309,8 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ping=${ifDefined(this.ping)} rel=${ifDefined(this.rel)} target=${ifDefined(this.target)} - aria-label=${ifDefined(this.a11yLabel)} - aria-pressed=${ifDefined(this.pressed)} + aria-label=${ifDefined(a11yLabel)} + aria-pressed=${ifDefined(a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} aria-haspopup=${ifDefined(this.a11yHaspopup)} @keyup=${this._handleKeyup} @@ -299,8 +327,8 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ?autofocus=${this.autofocus} ?disabled=${this.disabled} type="${ifDefined(this.type)}" - aria-label=${ifDefined(this.a11yLabel)} - aria-pressed=${ifDefined(this.pressed)} + aria-label=${ifDefined(a11yLabel)} + aria-pressed=${ifDefined(a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} aria-haspopup=${ifDefined(this.a11yHaspopup)} > From 4770316923652f9e23b3caf24da8c0ad47ad350e Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Mon, 18 Sep 2023 12:28:20 -0400 Subject: [PATCH 10/13] feat(button): update storybook aria-pressed --- .../pharos/src/components/button/pharos-button.wc.stories.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pharos/src/components/button/pharos-button.wc.stories.jsx b/packages/pharos/src/components/button/pharos-button.wc.stories.jsx index e8af3159d..59b552204 100644 --- a/packages/pharos/src/components/button/pharos-button.wc.stories.jsx +++ b/packages/pharos/src/components/button/pharos-button.wc.stories.jsx @@ -32,10 +32,10 @@ export const Base = { hreflang=${ifDefined(args.hreflang)} a11y-label=${ifDefined(args.a11yLabel)} a11y-expanded=${ifDefined(args.a11yExpanded)} + a11y-pressed=${ifDefined(args.a11yPressed)} ?large=${ifDefined(args.large)} ?on-background=${ifDefined(args.onBackground)} ping=${ifDefined(args.ping)} - pressed=${ifDefined(args.pressed)} target=${ifDefined(args.target)} type=${ifDefined(args.type)} variant=${ifDefined(args.variant)} From bafe3dab9c1b5674af3d98b5eb19b3ef298c5bbd Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Mon, 2 Oct 2023 13:21:51 -0400 Subject: [PATCH 11/13] feat(button): remove fallback from major release --- .../src/components/button/pharos-button.ts | 50 ++++--------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index a9fd10dc4..91e0c43d2 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -123,13 +123,6 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) @property({ type: Boolean, reflect: true }) public large = false; - /** - * Indicates the aria label to apply to the button. DEPRECRATED - * @attr label - */ - @property({ type: String, reflect: true }) - public label?: string; - /** * Indicates the aria label to apply to the button. * @attr a11y-label @@ -137,6 +130,13 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) @property({ type: String, reflect: true, attribute: 'a11y-label' }) public a11yLabel?: string; + /** + * Indicates this button is a toggle button and whether it is pressed or not. + * @attr value + */ + @property({ type: String, reflect: true, attribute: 'a11y-pressed' }) + public a11yPressed: PressedState = undefined; + /** * Indicates the aria expanded state to apply to the button. * @attr a11y-expanded @@ -172,20 +172,6 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) @property({ type: String, reflect: true }) public value?: string; - /** - * Indicates this button is a toggle button and whether it is pressed or not. DEPRECATED - * @attr value - */ - @property({ type: String, reflect: true }) - public pressed: PressedState = undefined; - - /** - * Indicates this button is a toggle button and whether it is pressed or not. - * @attr value - */ - @property({ type: String, reflect: true, attribute: 'a11y-pressed' }) - public a11yPressed: PressedState = undefined; - @query('#button-element') private _button!: HTMLButtonElement | HTMLAnchorElement; @@ -218,16 +204,6 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) `${this.variant} is not a valid variant. Valid variants are: ${VARIANTS.join(', ')}` ); } - - // Warn consumers that the label attribute is being deprecated - if (this.label) { - console.warn("The 'label' attribute is deprecated. Use 'a11y-label' instead."); - } - - // Warn consumers that the pressed attribute is being deprecated - if (this.pressed) { - console.warn("The 'pressed' attribute is deprecated. Use 'a11y-pressed' instead."); - } } override connectedCallback(): void { @@ -293,10 +269,6 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) } protected override render(): TemplateResult { - // Remove in future release once sufficient time elapsed to update naming convention - const a11yLabel = this.a11yLabel ?? this.label; - const a11yPressed = this.a11yPressed ?? this.pressed; - return this.href ? html` @@ -309,8 +281,8 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ping=${ifDefined(this.ping)} rel=${ifDefined(this.rel)} target=${ifDefined(this.target)} - aria-label=${ifDefined(a11yLabel)} - aria-pressed=${ifDefined(a11yPressed)} + aria-label=${ifDefined(this.a11yLabel)} + aria-pressed=${ifDefined(this.a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} aria-haspopup=${ifDefined(this.a11yHaspopup)} @keyup=${this._handleKeyup} @@ -327,8 +299,8 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) ?autofocus=${this.autofocus} ?disabled=${this.disabled} type="${ifDefined(this.type)}" - aria-label=${ifDefined(a11yLabel)} - aria-pressed=${ifDefined(a11yPressed)} + aria-label=${ifDefined(this.a11yLabel)} + aria-pressed=${ifDefined(this.a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} aria-haspopup=${ifDefined(this.a11yHaspopup)} > From 72a1b0197e5a22c7e267c6b88b9d1ce563c4b3f7 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Tue, 5 Dec 2023 10:13:09 -0500 Subject: [PATCH 12/13] feat(button): add a11y attributes typing --- .../src/components/button/pharos-button.ts | 30 ++++++++----------- .../sidenav/pharos-sidenav-button.ts | 19 ++---------- .../components/toast/pharos-toast-button.ts | 19 ++---------- .../pharos-toggle-button.ts | 20 ++----------- .../pharos/src/typings/a11y-attributes.d.ts | 17 +++++++++++ 5 files changed, 35 insertions(+), 70 deletions(-) create mode 100644 packages/pharos/src/typings/a11y-attributes.d.ts diff --git a/packages/pharos/src/components/button/pharos-button.ts b/packages/pharos/src/components/button/pharos-button.ts index 91e0c43d2..7549b466f 100644 --- a/packages/pharos/src/components/button/pharos-button.ts +++ b/packages/pharos/src/components/button/pharos-button.ts @@ -17,21 +17,6 @@ export type ButtonType = 'button' | 'submit' | 'reset'; export type ButtonVariant = 'primary' | 'secondary' | 'subtle' | 'overlay'; -// undefined means no state has been expressed at all and won't render; 'undefined' is an explicit state -export type PressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined; - -export type ExpandedState = 'false' | 'true' | 'undefined' | undefined; - -export type PopupState = - | 'false' - | 'true' - | 'menu' - | 'tree' - | 'grid' - | 'listbox' - | 'dialog' - | undefined; - const TYPES = ['button', 'submit', 'reset'] as ButtonType[]; const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[]; @@ -135,21 +120,28 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) * @attr value */ @property({ type: String, reflect: true, attribute: 'a11y-pressed' }) - public a11yPressed: PressedState = undefined; + public a11yPressed: AriaPressedState = undefined; /** * Indicates the aria expanded state to apply to the button. * @attr a11y-expanded */ @property({ type: String, reflect: true, attribute: 'a11y-expanded' }) - public a11yExpanded: ExpandedState = undefined; + public a11yExpanded: AriaExpandedState = undefined; + + /** + * Indicates the aria expanded state to apply to the button. + * @attr a11y-disabled + */ + @property({ type: String, reflect: true, attribute: 'a11y-disabled' }) + public a11yDisabled: AriaDisabledState = undefined; /** * Indicates the aria expanded state to apply to the button. * @attr a11y-haspopup */ @property({ type: String, reflect: true, attribute: 'a11y-haspopup' }) - public a11yHaspopup: PopupState = undefined; + public a11yHaspopup: AriaPopupState = undefined; /** * Indicates the button's width should match its container. @@ -284,6 +276,7 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) aria-label=${ifDefined(this.a11yLabel)} aria-pressed=${ifDefined(this.a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} + aria-disabled=${ifDefined(this.a11yDisabled)} aria-haspopup=${ifDefined(this.a11yHaspopup)} @keyup=${this._handleKeyup} > @@ -302,6 +295,7 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement)) aria-label=${ifDefined(this.a11yLabel)} aria-pressed=${ifDefined(this.a11yPressed)} aria-expanded=${ifDefined(this.a11yExpanded)} + aria-disabled=${ifDefined(this.a11yDisabled)} aria-haspopup=${ifDefined(this.a11yHaspopup)} > ${this.buttonContent} diff --git a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts index e722944d4..0dd634378 100644 --- a/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts +++ b/packages/pharos/src/components/sidenav/pharos-sidenav-button.ts @@ -4,23 +4,8 @@ import { PharosButton } from '../button/pharos-button'; import type { PharosSidenav } from './pharos-sidenav'; import type { LinkTarget } from '../base/anchor-element'; -import type { - ButtonType, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -} from '../button/pharos-button'; -export type { - LinkTarget, - ButtonType, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -}; +import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button'; +export type { LinkTarget, ButtonType, IconName, ButtonVariant }; /** * Pharos sidenav button component. diff --git a/packages/pharos/src/components/toast/pharos-toast-button.ts b/packages/pharos/src/components/toast/pharos-toast-button.ts index 81b887e6b..4b42df8d8 100644 --- a/packages/pharos/src/components/toast/pharos-toast-button.ts +++ b/packages/pharos/src/components/toast/pharos-toast-button.ts @@ -3,24 +3,9 @@ import { toastButtonStyles } from './pharos-toast-button.css'; import { PharosButton } from '../button/pharos-button'; import type { LinkTarget } from '../base/anchor-element'; -import type { - ButtonType, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -} from '../button/pharos-button'; +import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button'; -export type { - LinkTarget, - ButtonType, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -}; +export type { LinkTarget, ButtonType, IconName, ButtonVariant }; /** * Pharos toast button component. diff --git a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts index ae245d61e..004cba931 100644 --- a/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts +++ b/packages/pharos/src/components/toggle-button-group/pharos-toggle-button.ts @@ -3,24 +3,8 @@ import type { CSSResultArray, PropertyValues } from 'lit'; import { toggleButtonStyles } from './pharos-toggle-button.css'; import { PharosButton } from '../button/pharos-button'; -import type { - ButtonType, - LinkTarget, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -} from '../button/pharos-button'; -export type { - ButtonType, - LinkTarget, - IconName, - ButtonVariant, - PressedState, - ExpandedState, - PopupState, -}; +import type { ButtonType, LinkTarget, IconName, ButtonVariant } from '../button/pharos-button'; +export type { ButtonType, LinkTarget, IconName, ButtonVariant }; /** * Pharos toggle button component. diff --git a/packages/pharos/src/typings/a11y-attributes.d.ts b/packages/pharos/src/typings/a11y-attributes.d.ts new file mode 100644 index 000000000..b1736aee3 --- /dev/null +++ b/packages/pharos/src/typings/a11y-attributes.d.ts @@ -0,0 +1,17 @@ +export {}; + +declare global { + type AriaHiddenValues = 'false' | 'true' | 'undefined' | undefined; + type AriaPressedState = 'false' | 'true' | 'mixed' | 'undefined' | undefined; + type AriaExpandedState = 'false' | 'true' | 'undefined' | undefined; + type AriaDisabledState = 'false' | 'true' | undefined; + type AriaPopupState = + | 'false' + | 'true' + | 'menu' + | 'tree' + | 'grid' + | 'listbox' + | 'dialog' + | undefined; +} From 5aa5f15b4b7cd376fa25785f2ae82e9be34a0e15 Mon Sep 17 00:00:00 2001 From: Mat Harris Date: Tue, 5 Dec 2023 10:20:32 -0500 Subject: [PATCH 13/13] test(button): add tests for new aria attributes --- .../components/button/pharos-button.test.ts | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/pharos/src/components/button/pharos-button.test.ts b/packages/pharos/src/components/button/pharos-button.test.ts index f10806bc0..8af5284d3 100644 --- a/packages/pharos/src/components/button/pharos-button.test.ts +++ b/packages/pharos/src/components/button/pharos-button.test.ts @@ -24,10 +24,14 @@ describe('pharos-button', () => { await expect(component).to.be.accessible(); }); - it('is accessible as an icon button', async () => { - component.icon = 'download'; - component.a11yLabel = 'download'; + it('is renders aria-label on button and is accessible', async () => { + const label = 'download'; + component.icon = label; + component.a11yLabel = label; await component.updateComplete; + await expect( + component.renderRoot.querySelector('button')?.getAttribute('aria-label') + ).to.equal(label); await expect(component).to.be.accessible(); }); @@ -37,6 +41,33 @@ describe('pharos-button', () => { await expect(component).to.be.accessible(); }); + it('is accessible when using aria-disabled', async () => { + component.a11yDisabled = 'true'; + await component.updateComplete; + await expect( + component.renderRoot.querySelector('button')?.getAttribute('aria-disabled') + ).to.equal('true'); + await expect(component).to.be.accessible(); + }); + + it('is accessible when using aria-expanded', async () => { + component.a11yExpanded = 'true'; + await component.updateComplete; + await expect( + component.renderRoot.querySelector('button')?.getAttribute('aria-expanded') + ).to.equal('true'); + await expect(component).to.be.accessible(); + }); + + it('is accessible when using aria-haspopup', async () => { + component.a11yHaspopup = 'menu'; + await component.updateComplete; + await expect( + component.renderRoot.querySelector('button')?.getAttribute('aria-haspopup') + ).to.equal('menu'); + await expect(component).to.be.accessible(); + }); + it('is accessible as the secondary variant', async () => { component.variant = 'secondary'; await component.updateComplete;