Skip to content

Commit

Permalink
A11y revamp: Pharos buttons (non-breaking change) (#628)
Browse files Browse the repository at this point in the history
* docs: add @sirrah-tam as a contributor

* feat(button): add a11y naming convention for aria

* feat(button): add aria-description support

* chore: add changset

* Update packages/pharos/src/components/button/pharos-button.ts

Co-authored-by: Dane Hillard <github@danehillard.com>

* Update packages/pharos/src/components/button/pharos-button.ts

Co-authored-by: Dane Hillard <github@danehillard.com>

* feat(button): move property deprecated flag

* fix(button): remove ts-ignore after lit upgrade

* feat(button): add a11y state typing

* fix: add TODO for future reference

Co-authored-by: Dane Hillard <github@danehillard.com>

* fix(a11y attributes): update AriaHiddenState name

---------

Co-authored-by: Dane Hillard <github@danehillard.com>
  • Loading branch information
sirrah-tam and daneah committed Dec 8, 2023
1 parent 3ad3fd6 commit 9ef1e18
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/large-frogs-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ithaka/pharos': minor
---

Update PharosButton to use a11y naming convention and include wider ARIA support
68 changes: 60 additions & 8 deletions packages/pharos/src/components/button/pharos-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +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;

const TYPES = ['button', 'submit', 'reset'] as ButtonType[];

const VARIANTS = ['primary', 'secondary', 'subtle', 'overlay'] as ButtonVariant[];
Expand Down Expand Up @@ -112,12 +109,41 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
public large = false;

/**
* @deprecated
* Indicates the aria label to apply to the button.
* @attr label
*/
@property({ type: String, reflect: true })
public label?: string;

/**
* Indicates the aria label to apply to the button.
* @attr a11y-label
*/
@property({ type: String, reflect: true, attribute: 'a11y-label' })
public a11yLabel?: string;

/**
* Indicates the aria description to apply to the button.
* @attr a11y-description
*/
@property({ type: String, reflect: true, attribute: 'a11y-description' })
public a11yDescription?: string;

/**
* Indicates the aria expanded state to apply to the button.
* @attr a11y-expanded
*/
@property({ type: String, reflect: true, attribute: 'a11y-expanded' })
public a11yExpanded: AriaExpandedState = undefined;

/**
* Indicates the aria expanded state to apply to the button.
* @attr a11y-haspopup
*/
@property({ type: String, reflect: true, attribute: 'a11y-haspopup' })
public a11yHaspopup: AriaPopupState = undefined;

/**
* Indicates the button's width should match its container.
* @attr full-width
Expand All @@ -140,11 +166,19 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
public value?: string;

/**
* @deprecated
* Indicates this button is a toggle button and whether it is pressed or not.
* @attr value
*/
@property({ type: String, reflect: true })
public pressed: PressedState = undefined;
public pressed: AriaPressedState = 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: AriaPressedState = undefined;

@query('#button-element')
private _button!: HTMLButtonElement | HTMLAnchorElement;
Expand Down Expand Up @@ -178,6 +212,14 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
`${this.variant} is not a valid variant. Valid variants are: ${VARIANTS.join(', ')}`
);
}

if (this.label) {
console.warn("The 'label' attribute is deprecated. Use 'a11y-label' instead.");
}

if (this.pressed) {
console.warn("The 'pressed' attribute is deprecated. Use 'a11y-pressed' instead.");
}
}

override connectedCallback(): void {
Expand Down Expand Up @@ -243,6 +285,10 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
}

protected override render(): TemplateResult {
// TODO: 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`
<a
Expand All @@ -254,8 +300,11 @@ 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-pressed=${ifDefined(this.pressed)}
aria-label=${ifDefined(a11yLabel)}
aria-description=${ifDefined(this.a11yDescription)}
aria-pressed=${ifDefined(a11yPressed)}
aria-expanded=${ifDefined(this.a11yExpanded)}
aria-haspopup=${ifDefined(this.a11yHaspopup)}
@keyup=${this._handleKeyup}
>
${this.buttonContent}
Expand All @@ -269,8 +318,11 @@ export class PharosButton extends ScopedRegistryMixin(FocusMixin(AnchorElement))
?autofocus=${this.autofocus}
?disabled=${this.disabled}
type="${ifDefined(this.type)}"
aria-label=${ifDefined(this.label)}
aria-pressed=${ifDefined(this.pressed)}
aria-label=${ifDefined(a11yLabel)}
aria-description=${ifDefined(this.a11yDescription)}
aria-pressed=${ifDefined(a11yPressed)}
aria-expanded=${ifDefined(this.a11yExpanded)}
aria-haspopup=${ifDefined(this.a11yHaspopup)}
>
${this.buttonContent}
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +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 } from '../button/pharos-button';
export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState };
import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button';
export type { LinkTarget, ButtonType, IconName, ButtonVariant };

/**
* Pharos sidenav button component.
Expand Down
4 changes: 2 additions & 2 deletions packages/pharos/src/components/toast/pharos-toast-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +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 } from '../button/pharos-button';
import type { ButtonType, IconName, ButtonVariant } from '../button/pharos-button';

export type { LinkTarget, ButtonType, IconName, ButtonVariant, PressedState };
export type { LinkTarget, ButtonType, IconName, ButtonVariant };

/**
* Pharos toast button component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +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,
} from '../button/pharos-button';
export type { ButtonType, LinkTarget, IconName, ButtonVariant, PressedState };
import type { ButtonType, LinkTarget, IconName, ButtonVariant } from '../button/pharos-button';
export type { ButtonType, LinkTarget, IconName, ButtonVariant };

/**
* Pharos toggle button component.
Expand Down
17 changes: 17 additions & 0 deletions packages/pharos/src/typings/a11y-attributes.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export {};

declare global {
type AriaHiddenState = '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;
}

0 comments on commit 9ef1e18

Please sign in to comment.