From 27a71d0dbba5b3604afc351421f20efa8e8245f8 Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Wed, 13 Dec 2023 16:32:46 -0500 Subject: [PATCH 1/9] chore: refactor `setDefaultAria` to always set via `internals` ARIA properties; adjusted global theme colors to fix contrast issues --- .../pages/button-toggle/button-toggle.html | 2 +- .../button-toggle-group-constants.ts | 5 -- .../button-toggle-group-foundation.ts | 4 +- .../button-toggle-group.scss | 4 +- .../button-toggle-group.ts | 11 +-- src/lib/button-toggle/button-toggle.test.ts | 6 +- .../button-toggle/button-toggle-adapter.ts | 6 +- .../button-toggle/button-toggle-constants.ts | 5 -- .../button-toggle/button-toggle.ts | 9 +- src/lib/button/base/base-button-adapter.ts | 24 ++---- src/lib/button/base/base-button-constants.ts | 1 - src/lib/button/base/base-button-foundation.ts | 5 -- src/lib/button/base/base-button.ts | 9 +- .../circular-progress-adapter.ts | 20 ++--- .../circular-progress/circular-progress.scss | 25 +++--- .../circular-progress.test.ts | 10 +++ .../circular-progress/circular-progress.ts | 8 +- src/lib/constants.ts | 3 - .../mixins/internals/with-default-aria.ts | 35 +------- .../button-toggle-group/_tokens.scss | 4 +- .../button-toggle/button-toggle/_tokens.scss | 6 +- .../styles/tokens/theme/_token-utils.scss | 8 +- src/lib/core/utils/a11y-utils.ts | 84 +++---------------- src/lib/core/utils/feature-detection.ts | 4 +- .../linear-progress-adapter.ts | 20 ++--- src/lib/linear-progress/linear-progress.ts | 8 +- src/lib/radio/core/radio-group-manager.ts | 2 +- .../radio/radio-group/radio-group-adapter.ts | 4 +- .../radio-group/radio-group-constants.ts | 9 +- src/lib/radio/radio-group/radio-group.ts | 7 +- src/lib/radio/radio/radio-adapter.ts | 14 +--- src/lib/radio/radio/radio-constants.ts | 17 +--- src/lib/radio/radio/radio.ts | 11 +-- 33 files changed, 114 insertions(+), 276 deletions(-) diff --git a/src/dev/pages/button-toggle/button-toggle.html b/src/dev/pages/button-toggle/button-toggle.html index 83e3bacc0..cd3e02041 100644 --- a/src/dev/pages/button-toggle/button-toggle.html +++ b/src/dev/pages/button-toggle/button-toggle.html @@ -8,7 +8,7 @@ type: 'select', label: 'Theme', id: 'opt-theme', - defaultValue: 'primary', + defaultValue: 'tertiary', options: [ { label: 'Primary', value: 'primary' }, { label: 'Secondary', value: 'secondary' }, diff --git a/src/lib/button-toggle/button-toggle-group/button-toggle-group-constants.ts b/src/lib/button-toggle/button-toggle-group/button-toggle-group-constants.ts index 8f975d3cb..2fe3a5b88 100644 --- a/src/lib/button-toggle/button-toggle-group/button-toggle-group-constants.ts +++ b/src/lib/button-toggle/button-toggle-group/button-toggle-group-constants.ts @@ -1,6 +1,4 @@ import { COMPONENT_NAME_PREFIX, Theme } from '../../constants'; -import { supportsElementInternalsAria } from '../../core'; -import { ARIAAttribute } from '../../core/utils/a11y-utils'; const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}button-toggle-group`; @@ -18,8 +16,6 @@ const observedAttributes = { THEME: 'theme' }; -const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() ? [] : ['role', 'aria-label']; - const attributes = { ...observedAttributes }; @@ -40,7 +36,6 @@ const events = { export const BUTTON_TOGGLE_GROUP_CONSTANTS = { elementName, observedAttributes, - observedAriaAttributes, attributes, classes, selectors, diff --git a/src/lib/button-toggle/button-toggle-group/button-toggle-group-foundation.ts b/src/lib/button-toggle/button-toggle-group/button-toggle-group-foundation.ts index 0d55db642..6d25026dc 100644 --- a/src/lib/button-toggle/button-toggle-group/button-toggle-group-foundation.ts +++ b/src/lib/button-toggle/button-toggle-group/button-toggle-group-foundation.ts @@ -29,7 +29,7 @@ export class ButtonToggleGroupFoundation implements IButtonToggleGroupFoundation private _disabled = false; private _readonly = false; private _required = false; - private _theme: ButtonToggleGroupTheme = 'primary'; + private _theme: ButtonToggleGroupTheme = 'tertiary'; private _selectListener: (evt: CustomEvent) => void; private _slotListener: () => void; @@ -233,7 +233,7 @@ export class ButtonToggleGroupFoundation implements IButtonToggleGroupFoundation public set theme(value: ButtonToggleGroupTheme) { if (this._theme !== value) { this._theme = value; - this._adapter.toggleHostAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME, this._theme !== 'primary', this._theme); + this._adapter.toggleHostAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME, this._theme !== 'tertiary', this._theme); } } } diff --git a/src/lib/button-toggle/button-toggle-group/button-toggle-group.scss b/src/lib/button-toggle/button-toggle-group/button-toggle-group.scss index fa1f9fcff..30dc3f828 100644 --- a/src/lib/button-toggle/button-toggle-group/button-toggle-group.scss +++ b/src/lib/button-toggle/button-toggle-group/button-toggle-group.scss @@ -116,15 +116,15 @@ $_host-tokens: [display]; ::slotted(forge-button-toggle) { @include button-toggle.provide-theme(( selected-background: #{theme.variable(#{$theme}-container-low)}, - selected-color: #{theme.variable($theme)}, + selected-color: #{theme.variable(on-#{$theme}-container-low)}, focus-indicator-color: #{theme.variable($theme)} )); } } } +@include theme(primary); @include theme(secondary); -@include theme(tertiary); @include theme(success); @include theme(error); @include theme(warning); diff --git a/src/lib/button-toggle/button-toggle-group/button-toggle-group.ts b/src/lib/button-toggle/button-toggle-group/button-toggle-group.ts index b37efe659..f409d66aa 100644 --- a/src/lib/button-toggle/button-toggle-group/button-toggle-group.ts +++ b/src/lib/button-toggle/button-toggle-group/button-toggle-group.ts @@ -8,7 +8,7 @@ import { ButtonToggleComponent } from '../button-toggle/button-toggle'; import { ButtonToggleGroupAdapter } from './button-toggle-group-adapter'; import { ButtonToggleGroupTheme, BUTTON_TOGGLE_GROUP_CONSTANTS, IButtonToggleGroupChangeEventData } from './button-toggle-group-constants'; import { ButtonToggleGroupFoundation } from './button-toggle-group-foundation'; -import { getFormState, getFormValue, inputType, observedDefaultAriaAttributes, setDefaultAria } from '../../constants'; +import { getFormState, getFormValue, inputType, setDefaultAria } from '../../constants'; import { FormValue, FormRestoreState, FormRestoreReason } from '../../core/utils/form-utils'; import { IWithDefaultAria, WithDefaultAria } from '../../core/mixins/internals/with-default-aria'; @@ -100,14 +100,9 @@ const BaseButtonToggleGroupClass = WithLabelAwareness(WithFormAssociation(WithFo }) export class ButtonToggleGroupComponent extends BaseButtonToggleGroupClass implements IButtonToggleGroupComponent { public static get observedAttributes(): string[] { - return [ - ...Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAttributes), - ...Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAriaAttributes) - ]; + return Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAttributes); } - public readonly [observedDefaultAriaAttributes] = BUTTON_TOGGLE_GROUP_CONSTANTS.observedAriaAttributes; - private _foundation: ButtonToggleGroupFoundation; constructor() { @@ -118,7 +113,7 @@ export class ButtonToggleGroupComponent extends BaseButtonToggleGroupClass imple } public connectedCallback(): void { - this[setDefaultAria]({ role: 'group' }); + this[setDefaultAria]({ role: 'group' }, { setAttribute: !this.hasAttribute('role') }); this._foundation.initialize(); } diff --git a/src/lib/button-toggle/button-toggle.test.ts b/src/lib/button-toggle/button-toggle.test.ts index e2abbde60..983cdc09a 100644 --- a/src/lib/button-toggle/button-toggle.test.ts +++ b/src/lib/button-toggle/button-toggle.test.ts @@ -23,12 +23,12 @@ describe('Button Toggle', () => { expect(harness.buttonToggles.every(toggle => toggle.getAttribute('aria-pressed') === 'false')).to.be.true; }); - ['primary', 'secondary', 'danger', 'success', 'warning', 'info'].forEach((theme: ButtonToggleGroupTheme) => { + ['primary', 'secondary', 'tertiary', 'danger', 'success', 'warning', 'info'].forEach((theme: ButtonToggleGroupTheme) => { it(`should be accessible with selected values for theme ${theme}`, async () => { const harness = await createFixture({ theme, value: 'two' }); - // Primary is the default - if (theme !== 'primary') { + // tertiary is the default + if (theme !== 'tertiary') { expect(harness.element.getAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME)).to.equal(theme); } diff --git a/src/lib/button-toggle/button-toggle/button-toggle-adapter.ts b/src/lib/button-toggle/button-toggle/button-toggle-adapter.ts index 0be26ab4d..49391ceab 100644 --- a/src/lib/button-toggle/button-toggle/button-toggle-adapter.ts +++ b/src/lib/button-toggle/button-toggle/button-toggle-adapter.ts @@ -25,8 +25,8 @@ export class ButtonToggleAdapter extends BaseAdapter imp } public initialize(): void { + this._component[setDefaultAria]({ role: 'button' }, { setAttribute: !this._component.hasAttribute('role') }); this._component[setDefaultAria]({ - role: 'button', ariaPressed: `${!!this._component.selected}`, ariaDisabled: `${!!this._component.disabled}` }); @@ -34,11 +34,11 @@ export class ButtonToggleAdapter extends BaseAdapter imp } public setSelected(value: boolean): void { - this._component[setDefaultAria]({ ariaPressed: `${!!value}` }, { overwrite: true }); + this._component[setDefaultAria]({ ariaPressed: `${!!value}` }); } public setDisabled(value: boolean): void { - this._component[setDefaultAria]({ ariaDisabled: `${!!value}` }, { overwrite: true }); + this._component[setDefaultAria]({ ariaDisabled: `${!!value}` }); this._component[isFocusable] = !value; this._stateLayerElement.disabled = value; } diff --git a/src/lib/button-toggle/button-toggle/button-toggle-constants.ts b/src/lib/button-toggle/button-toggle/button-toggle-constants.ts index dd8c22238..bfb04f183 100644 --- a/src/lib/button-toggle/button-toggle/button-toggle-constants.ts +++ b/src/lib/button-toggle/button-toggle/button-toggle-constants.ts @@ -1,6 +1,4 @@ import { COMPONENT_NAME_PREFIX } from '../../constants'; -import { supportsElementInternalsAria } from '../../core'; -import { ARIAAttribute } from '../../core/utils/a11y-utils'; const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}button-toggle`; @@ -12,8 +10,6 @@ const observedAttributes = { TABINDEX: 'tabindex' // Need this to support the focusable mixin }; -const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() ? [] : ['role', 'aria-pressed', 'aria-disabled']; - const attributes = { ...observedAttributes }; @@ -25,7 +21,6 @@ const events = { export const BUTTON_TOGGLE_CONSTANTS = { elementName, observedAttributes, - observedAriaAttributes, attributes, events }; diff --git a/src/lib/button-toggle/button-toggle/button-toggle.ts b/src/lib/button-toggle/button-toggle/button-toggle.ts index 500d39308..726ae4d8d 100644 --- a/src/lib/button-toggle/button-toggle/button-toggle.ts +++ b/src/lib/button-toggle/button-toggle/button-toggle.ts @@ -1,5 +1,5 @@ import { attachShadowTemplate, coerceBoolean, CustomElement, FoundationProperty } from '@tylertech/forge-core'; -import { ExperimentalFocusOptions, observedDefaultAriaAttributes } from '../../constants'; +import { ExperimentalFocusOptions } from '../../constants'; import { IWithFocusable, WithFocusable } from '../../core/mixins/focus/with-focusable'; import { IWithElementInternals, WithElementInternals } from '../../core/mixins/internals/with-element-internals'; import { FocusIndicatorComponent } from '../../focus-indicator'; @@ -95,14 +95,9 @@ const BaseButtonToggleClass = WithDefaultAria(WithElementInternals(WithFocusable }) export class ButtonToggleComponent extends BaseButtonToggleClass implements IButtonToggleComponent { public static get observedAttributes(): string[] { - return [ - ...Object.values(BUTTON_TOGGLE_CONSTANTS.observedAttributes), - ...Object.values(BUTTON_TOGGLE_CONSTANTS.observedAriaAttributes) - ]; + return Object.values(BUTTON_TOGGLE_CONSTANTS.observedAttributes); } - public readonly [observedDefaultAriaAttributes] = BUTTON_TOGGLE_CONSTANTS.observedAriaAttributes; - private _foundation: ButtonToggleFoundation; constructor() { diff --git a/src/lib/button/base/base-button-adapter.ts b/src/lib/button/base/base-button-adapter.ts index 2c5a1be59..730b917d1 100644 --- a/src/lib/button/base/base-button-adapter.ts +++ b/src/lib/button/base/base-button-adapter.ts @@ -6,7 +6,7 @@ import { IStateLayerComponent, STATE_LAYER_CONSTANTS } from '../../state-layer'; import { IBaseButton } from './base-button'; import { BASE_BUTTON_CONSTANTS } from './base-button-constants'; import { BUTTON_FORM_ATTRIBUTES, cloneAttributes } from '../../core/utils/reflect-utils'; -import { internals, isFocusable } from '../../constants'; +import { internals, isFocusable, setDefaultAria } from '../../constants'; import { supportsPopover } from '../../core/utils/feature-detection'; // TODO: remove this augmentation when the TypeScript version is upgraded for latest DOM typings @@ -34,7 +34,6 @@ export interface IBaseButtonAdapter extends IBaseAdapter { managePopover(): boolean; toggleDefaultPopoverIcon(value: boolean): void; animateStateLayer(): void; - proxyLabel(value: string | null): void; } export abstract class BaseButtonAdapter extends BaseAdapter implements IBaseButtonAdapter { @@ -44,8 +43,6 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme protected _stateLayerElement: IStateLayerComponent; protected _endSlotElement: HTMLSlotElement; - private _labelAwareText?: string; - constructor(component: IBaseButton) { super(component); this._rootElement = getShadowElement(this._component, BASE_BUTTON_CONSTANTS.selectors.ROOT) as HTMLButtonElement; @@ -101,7 +98,7 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme } this._component[isFocusable] = !value; - toggleAttribute(this._component, value, 'aria-disabled', 'true'); + this._component[setDefaultAria]({ ariaDisabled: value ? 'true' : null }); } public clickAnchor(): void { @@ -246,12 +243,6 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme this._stateLayerElement?.playAnimation(); } - public proxyLabel(value: string | null): void { - this._labelAwareText = value ?? undefined; - const hasAriaLabel = this._component.hasAttribute('aria-label') || !!this._labelAwareText; - toggleAttribute(this._component, hasAriaLabel, 'aria-label', this._component.getAttribute('aria-label') ?? this._labelAwareText); - } - private _locatePopoverTargetElement(): TempHTMLElementWithPopover | null { let popoverElement = (this._component as TempHTMLElementWithPopover).popoverTargetElement ?? null; @@ -270,14 +261,9 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme private _applyHostSemantics(): void { const role = this._component.getAttribute('role'); - - // Allow user provided roles to override our default role - if (!role || ['button', 'link'].includes(role)) { - // Set default role based on the existence of an anchor element - this._component.role = this._anchorElement ? 'link' : 'button'; - } - - this._component[isFocusable] = !!this._anchorElement || !this._component.disabled; + const overwrite = !role || ['button', 'link'].includes(role); + this._component[setDefaultAria]({ role: this._anchorElement ? 'link' : 'button' }, { setAttribute: overwrite }); + this._component[isFocusable] = !!this._anchorElement ?? !this._component.disabled; } /** diff --git a/src/lib/button/base/base-button-constants.ts b/src/lib/button/base/base-button-constants.ts index 3d2fdaee6..c1ac6e8b8 100644 --- a/src/lib/button/base/base-button-constants.ts +++ b/src/lib/button/base/base-button-constants.ts @@ -34,5 +34,4 @@ export const BASE_BUTTON_CONSTANTS = { export type ButtonType = 'button' | 'submit' | 'reset'; export type ButtonTarget = '_blank' | '_self' | '_parent' | '_top'; - export type ButtonClickOptions = { animateStateLayer?: boolean }; diff --git a/src/lib/button/base/base-button-foundation.ts b/src/lib/button/base/base-button-foundation.ts index c9fd86130..ecab8f769 100644 --- a/src/lib/button/base/base-button-foundation.ts +++ b/src/lib/button/base/base-button-foundation.ts @@ -15,7 +15,6 @@ export interface IBaseButtonFoundation extends ICustomElementFoundation { dense: boolean; click(options: ButtonClickOptions): void; focus(options?: ExperimentalFocusOptions): void; - proxyLabel(label: string | null): void; } export abstract class BaseButtonFoundation implements IBaseButtonFoundation { @@ -81,10 +80,6 @@ export abstract class BaseButtonFoundation impleme } } - public proxyLabel(label: string | null): void { - this._adapter.proxyLabel(label); - } - protected async _onClick(evt: MouseEvent): Promise { const isFormType = this._type === 'submit' || this._type === 'reset'; diff --git a/src/lib/button/base/base-button.ts b/src/lib/button/base/base-button.ts index aff892fce..68f0af1dd 100644 --- a/src/lib/button/base/base-button.ts +++ b/src/lib/button/base/base-button.ts @@ -3,14 +3,15 @@ import { tylIconArrowDropDown } from '@tylertech/tyler-icons/standard'; import { IconRegistry } from '../../icon/icon-registry'; import { WithFocusable, IWithFocusable } from '../../core/mixins/focus/with-focusable'; import { BaseComponent } from '../../core/base/base-component'; -import { ExperimentalFocusOptions, internals } from '../../constants'; +import { ExperimentalFocusOptions, internals, setDefaultAria } from '../../constants'; import { IBaseButtonAdapter } from './base-button-adapter'; import { BASE_BUTTON_CONSTANTS, ButtonType } from './base-button-constants'; import { BaseButtonFoundation } from './base-button-foundation'; import { WithLabelAwareness, IWithLabelAwareness } from '../../core/mixins/label/with-label-aware'; import { IWithElementInternals, WithElementInternals } from '../../core/mixins/internals/with-element-internals'; +import { IWithDefaultAria, WithDefaultAria } from '../../core/mixins/internals/with-default-aria'; -export interface IBaseButton extends IWithFocusable, IWithLabelAwareness, IWithElementInternals { +export interface IBaseButton extends IWithFocusable, IWithLabelAwareness, IWithElementInternals, IWithDefaultAria { type: ButtonType; disabled: boolean; popoverIcon: boolean; @@ -26,7 +27,7 @@ export interface IBaseButton extends IWithFocusable, IWithLabelAwareness, IWithE focus(options?: ExperimentalFocusOptions): void; } -const BaseButtonClass = WithElementInternals(WithLabelAwareness(WithFocusable(BaseComponent))); +const BaseButtonClass = WithDefaultAria(WithElementInternals(WithLabelAwareness(WithFocusable(BaseComponent)))); export abstract class BaseButton> extends BaseButtonClass implements IBaseButton { public static readonly formAssociated = true; @@ -81,7 +82,7 @@ export abstract class BaseButton { expect(determinateProgressElement.getAttribute('stroke-dashoffset')).to.equal('100'); }); + it('should remove aria-valuenow when indeterminate after determinate', async () => { + const el = await fixture(html``); + + expect(el.hasAttribute('aria-valuenow')).to.be.true; + + el.determinate = false; + + expect(el.hasAttribute('aria-valuenow')).to.be.false; + }); + it('should set progress', async () => { const el = await fixture(html``); diff --git a/src/lib/circular-progress/circular-progress.ts b/src/lib/circular-progress/circular-progress.ts index 6c471a74a..6a362be8a 100644 --- a/src/lib/circular-progress/circular-progress.ts +++ b/src/lib/circular-progress/circular-progress.ts @@ -3,12 +3,14 @@ import { CustomElement, attachShadowTemplate, FoundationProperty, coerceBoolean, import { CircularProgressAdapter } from './circular-progress-adapter'; import { CircularProgressFoundation } from './circular-progress-foundation'; import { CircularProgressTheme, CIRCULAR_PROGRESS_CONSTANTS } from './circular-progress-constants'; -import { BaseComponent, IBaseComponent } from '../core/base/base-component'; +import { BaseComponent } from '../core/base/base-component'; +import { IWithElementInternals, WithElementInternals } from '../core/mixins/internals/with-element-internals'; +import { IWithDefaultAria, WithDefaultAria } from '../core/mixins/internals/with-default-aria'; import template from './circular-progress.html'; import styles from './circular-progress.scss'; -export interface ICircularProgressComponent extends IBaseComponent { +export interface ICircularProgressComponent extends IWithElementInternals, IWithDefaultAria { determinate: boolean; progress: number; theme: CircularProgressTheme; @@ -58,7 +60,7 @@ declare global { @CustomElement({ name: CIRCULAR_PROGRESS_CONSTANTS.elementName }) -export class CircularProgressComponent extends BaseComponent implements ICircularProgressComponent { +export class CircularProgressComponent extends WithDefaultAria(WithElementInternals(BaseComponent)) implements ICircularProgressComponent { public static get observedAttributes(): string[] { return [ CIRCULAR_PROGRESS_CONSTANTS.attributes.DETERMINATE, diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 82bd261f9..0c1a48698 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -27,9 +27,6 @@ export const isFocusable = Symbol('isFocusable'); * supported or sprouts attributes if not. */ export const setDefaultAria = Symbol('setDefaultAria'); -/** A property symbol that is used to define default ARIA attributes that will be observed. */ -export const observedDefaultAriaAttributes = Symbol('observedDefaultAriaAttributes'); - export type Theme = 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error' | 'info'; export type Density = 'small' | 'medium' | 'large'; diff --git a/src/lib/core/mixins/internals/with-default-aria.ts b/src/lib/core/mixins/internals/with-default-aria.ts index b4c92c6be..675c3e41a 100644 --- a/src/lib/core/mixins/internals/with-default-aria.ts +++ b/src/lib/core/mixins/internals/with-default-aria.ts @@ -1,13 +1,5 @@ -import { internals, MixinBase, setDefaultAria, AbstractConstructor, observedDefaultAriaAttributes } from '../../../constants'; -import { - ARIAAttribute, - ariaAttributeToProperty, - ARIAMixinStrict, - DefaultAriaOptions, - restoreDefaultAria as restoreDefaultAriaUtil, - setDefaultAria as setDefaultAriaUtil -} from '../../utils/a11y-utils'; -import { supportsElementInternalsAria } from '../../utils/feature-detection'; +import { internals, MixinBase, setDefaultAria, AbstractConstructor } from '../../../constants'; +import { ARIAMixinStrict, setDefaultAria as setDefaultAriaUtil, DefaultAriaOptions } from '../../utils/a11y-utils'; import { IBaseComponent } from '../../base/base-component'; /** @@ -26,8 +18,6 @@ export interface IWithDefaultAria extends IBaseComponent { } export declare abstract class WithDefaultAriaContract { - public abstract readonly [observedDefaultAriaAttributes]: ARIAAttribute[]; - public attributeChangedCallback(name: string, oldValue: string, newValue: string): void; public [setDefaultAria](properties: Partial, options?: DefaultAriaOptions): void; } @@ -35,32 +25,11 @@ export declare abstract class WithDefaultAriaContract { * Mixes in Element Internals functionality into a base component. * * @param base The base component to mix into. - * @param observedAria An array of ARIA attributes to observe for changes. If an observed attribute - * is removed, the default ARIA will be restored. This is only used if Element Internals is not - * supported. * @returns The mixed-in base component. */ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function WithDefaultAria(base: TBase) { abstract class DefaultAria extends base implements IWithDefaultAria { - public abstract readonly [observedDefaultAriaAttributes]: ARIAAttribute[]; - - public override attributeChangedCallback(name: string, oldValue: string, newValue: string): void { - super.attributeChangedCallback?.(name, oldValue, newValue); - - // If Element Internals is supported our default ARIA is never set as an attribute, so - // there's nothing to do here. - if (!this[observedDefaultAriaAttributes] || supportsElementInternalsAria()) { - return; - } - - // If the observed attribute is removed, restore the default ARIA. - if (this[observedDefaultAriaAttributes].includes(name as ARIAAttribute) && !newValue) { - const ariaPropertyName = ariaAttributeToProperty(name as ARIAAttribute); - restoreDefaultAriaUtil(this, ariaPropertyName); - } - } - public [setDefaultAria](properties: Partial, options?: DefaultAriaOptions): void { setDefaultAriaUtil(this, this[internals], properties, options); } diff --git a/src/lib/core/styles/tokens/button-toggle/button-toggle-group/_tokens.scss b/src/lib/core/styles/tokens/button-toggle/button-toggle-group/_tokens.scss index ef3085be7..3cdfd7869 100644 --- a/src/lib/core/styles/tokens/button-toggle/button-toggle-group/_tokens.scss +++ b/src/lib/core/styles/tokens/button-toggle/button-toggle-group/_tokens.scss @@ -23,8 +23,8 @@ $tokens: ( // Outline outline-width: utils.module-val(button-toggle-group, outline-width, border.variable(thin)), outline-style: utils.module-val(button-toggle-group, outline-style, solid), - outline-color: utils.module-val(button-toggle-group, outline-color, theme.variable(outline-medium)), - outline-color-active: utils.module-val(button-toggle-group, outline-color-active, theme.variable(outline-high)), + outline-color: utils.module-val(button-toggle-group, outline-color, theme.variable(outline-low)), + outline-color-active: utils.module-val(button-toggle-group, outline-color-active, theme.variable(outline-medium)), // Shape shape: utils.module-val(button-toggle-group, shape, shape.variable(medium)), diff --git a/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss b/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss index f12caa7d7..efa35d890 100644 --- a/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss +++ b/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss @@ -26,7 +26,7 @@ $tokens: ( // Border border-width: utils.module-val(button-toggle, border-width, medium), border-style: utils.module-val(button-toggle, border-style, none), - border-color: utils.module-val(button-toggle, border-color, theme.variable(text-medium)), + border-color: utils.module-val(button-toggle, border-color, theme.variable(outline-medium)), // Shape shape: utils.module-val(button-toggle, shape, shape.variable(small)), @@ -36,8 +36,8 @@ $tokens: ( shape-end-end: utils.module-ref(button-toggle, shape-end-end, shape), // Selected - selected-background: utils.module-val(button-toggle, selected-background, theme.variable(primary-container-low)), - selected-color: utils.module-val(button-toggle, selected-color, theme.variable(primary)), + selected-background: utils.module-val(button-toggle, selected-background, theme.variable(tertiary-container-low)), + selected-color: utils.module-val(button-toggle, selected-color, theme.variable(on-tertiary-container-low)), selected-disabled-background: utils.module-val(button-toggle, selected-disabled-background, theme.variable(surface-container)), // Dense diff --git a/src/lib/core/styles/tokens/theme/_token-utils.scss b/src/lib/core/styles/tokens/theme/_token-utils.scss index 745852668..89be5ebd3 100644 --- a/src/lib/core/styles/tokens/theme/_token-utils.scss +++ b/src/lib/core/styles/tokens/theme/_token-utils.scss @@ -18,10 +18,10 @@ $surface-tone: color-utils.tone($surface); // The container colors are the provided color mixed with the surface color at lower emphasis levels - $container-minimum: theme-utils.hexify($color, $surface, color-emphasis.value(if($surface-tone == 'light', minimum, lowest))); - $container-low: theme-utils.hexify($color, $surface, color-emphasis.value(if($surface-tone == 'light', lower, low))); - $container: theme-utils.hexify($color, $surface, color-emphasis.value(if($surface-tone == 'light', low, medium-low))); - $container-high: theme-utils.hexify($color, $surface, color-emphasis.value(if($surface-tone == 'light', medium-low, medium))); + $container-minimum: theme-utils.hexify($color, $surface, color-emphasis.value(minimum)); + $container-low: theme-utils.hexify($color, $surface, color-emphasis.value(lower)); + $container: theme-utils.hexify($color, $surface, color-emphasis.value(low)); + $container-high: theme-utils.hexify($color, $surface, color-emphasis.value(medium-low)); // The on-color is the contrast color against the provided color $on-color: theme-utils.contrast($color); diff --git a/src/lib/core/utils/a11y-utils.ts b/src/lib/core/utils/a11y-utils.ts index 1de284cae..e066739c5 100644 --- a/src/lib/core/utils/a11y-utils.ts +++ b/src/lib/core/utils/a11y-utils.ts @@ -66,7 +66,7 @@ export const ARIA_PROPERTIES: ARIAProperty[] = [ /** * An object mapping all ARIA attributes to their corresponding properties. * - * This is required because the proeprty name cannot be reliably inferred from the attribute name. + * This is required because the property name cannot be reliably inferred from the attribute name. */ const ARIA_ATTRIBUTES_TO_PROPERTIES: Record = { 'aria-atomic': 'ariaAtomic', @@ -209,12 +209,9 @@ export function ariaAttributeToProperty(attribut return ARIA_ATTRIBUTES_TO_PROPERTIES[attribute] as ARIAProperty; } -// TODO: deprecate and remove `setupDefaultAria` and related functions when ARIA in -// ElementInternals is widely supported in all major browsers. - -export interface DefaultAriaOptions { - overwrite?: boolean; -} +export type DefaultAriaOptions = { + setAttribute?: boolean; +}; /** * Applies default ARIA to an element through ElementInternals if supported. Otherwise, ARIA @@ -252,75 +249,16 @@ export function setDefaultAria( element: HTMLElement, internals: ElementInternals, properties: Partial, - options?: DefaultAriaOptions + { setAttribute: overwrite }: DefaultAriaOptions = { setAttribute: true } ): void { - if (supportsElementInternalsAria()) { - Object.entries(properties).forEach(([key, value]) => { - internals[key as ARIAProperty] = value; - }); - return; - } - Object.entries(properties).forEach(([key, value]) => { - const ariaAttribute = ariaPropertyToAttribute(key as ARIAProperty); - - if (options?.overwrite || !element.hasAttribute(ariaAttribute)) { - toggleAttribute(element, value != null, ariaPropertyToAttribute(key as ARIAProperty), value?.toString()); + if (supportsElementInternalsAria()) { + internals[key as ARIAProperty] = value; } - if (value != null) { - storeDefaultAria(element, key as ARIAProperty, value); - } else { - removeDefaultAria(element, key as ARIAProperty); + + const attribute = ariaPropertyToAttribute(key as ARIAProperty); + if (overwrite || !element.hasAttribute(attribute)) { + toggleAttribute(element, value != null, attribute, value as string); } }); } - -/** - * Sets a `*Default` property on an element to backup the default value of an ARIA attribute. - * - * @param element The element to store the default ARIA value on. - * @param property The ARIA mixin property. - * @param value The default value to store. - */ -export function storeDefaultAria(element: HTMLElement, property: T, value: ARIAMixinStrict[T]): void { - element[getDefaultAriaPropertyName(property)] = value; -} - -/** - * Removes a `*Default` property from an element. - * - * @param element The element to remove the default ARIA value from. - * @param property The ARIA mixin property. - */ -export function removeDefaultAria(element: HTMLElement, property: T): void { - delete element[getDefaultAriaPropertyName(property)]; -} - -/** - * Gets a default ARIA value from an element's `*Default` property. - * - * @param element The element to retrieve the default ARIA value from. - * @param property An ARIA mixin property. - * @returns The value of the default ARIA attribute, or null if it does not exist. - */ -export function retrieveDefaultAria(element: HTMLElement, property: T): ARIAMixinStrict[T] | null { - const value = element[getDefaultAriaPropertyName(property)]; - return !!value ? value as ARIAMixinStrict[T] : null; -} - -/** - * Restores the given ARIA attribute of an element to its default value if it exists. - * - * @param element The element to restore the ARIA attribute on. - * @param property The ARIA mixin property. - */ -export function restoreDefaultAria(element: HTMLElement, property: T): void { - const defaultValue = retrieveDefaultAria(element, property); - if (defaultValue !== null) { - toggleAttribute(element, true, ariaPropertyToAttribute(property), defaultValue.toString()); - } -} - -function getDefaultAriaPropertyName(property: T): string { - return `_forge_${property}Default`; -} diff --git a/src/lib/core/utils/feature-detection.ts b/src/lib/core/utils/feature-detection.ts index dca97ddf5..6badeddc4 100644 --- a/src/lib/core/utils/feature-detection.ts +++ b/src/lib/core/utils/feature-detection.ts @@ -14,7 +14,5 @@ export function supportsPopover(): boolean { * @returns {boolean} */ export function supportsElementInternalsAria(): boolean { - // TODO: return whether the user agent actually supports this when tooling is able to detect it - // return ElementInternals.prototype.hasOwnProperty('role'); - return false; + return ElementInternals.prototype.hasOwnProperty('role'); } diff --git a/src/lib/linear-progress/linear-progress-adapter.ts b/src/lib/linear-progress/linear-progress-adapter.ts index 23cfafa8d..cce79315b 100644 --- a/src/lib/linear-progress/linear-progress-adapter.ts +++ b/src/lib/linear-progress/linear-progress-adapter.ts @@ -1,4 +1,5 @@ import { getShadowElement } from '@tylertech/forge-core'; +import { setDefaultAria } from '../constants'; import { BaseAdapter, IBaseAdapter } from '../core/base/base-adapter'; import { ILinearProgressComponent } from './linear-progress'; import { LINEAR_PROGRESS_CONSTANTS } from './linear-progress-constants'; @@ -23,20 +24,16 @@ export class LinearProgressAdapter extends BaseAdapter } public initialize(): void { - if (!this._component.hasAttribute('role')) { - this._component.setAttribute('role', 'progressbar'); - } - if (!this._component.hasAttribute('aria-valuemin')) { - this._component.setAttribute('aria-valuemin', '0'); - } - if (!this._component.hasAttribute('aria-valuemax')) { - this._component.setAttribute('aria-valuemax', '1'); - } + this._component[setDefaultAria]({ + role: 'progressbar', + ariaValueMin: '0', + ariaValueMax: '1' + }); } public setDeterminate(value: boolean): void { if (!value) { - this._component.removeAttribute('aria-valuenow'); + this._component[setDefaultAria]({ ariaValueNow: null }); this._progressElement.style.transform = ''; this._bufferElement.style.transform = ''; } @@ -44,7 +41,8 @@ export class LinearProgressAdapter extends BaseAdapter } public setProgress(value: number): void { - this._component.setAttribute('aria-valuenow', `${value}`); + // this._component.setAttribute('theme', 'test'); // TODO: figure this out + this._component[setDefaultAria]({ ariaValueNow: `${value}` }); this._progressElement.style.transform = `scaleX(${value * 100}%)`; } diff --git a/src/lib/linear-progress/linear-progress.ts b/src/lib/linear-progress/linear-progress.ts index 237eef778..bdbc99878 100644 --- a/src/lib/linear-progress/linear-progress.ts +++ b/src/lib/linear-progress/linear-progress.ts @@ -1,5 +1,7 @@ import { attachShadowTemplate, coerceBoolean, coerceNumber, CustomElement, FoundationProperty } from '@tylertech/forge-core'; -import { BaseComponent, IBaseComponent } from '../core/base/base-component'; +import { BaseComponent } from '../core/base/base-component'; +import { IWithDefaultAria, WithDefaultAria } from '../core/mixins/internals/with-default-aria'; +import { IWithElementInternals, WithElementInternals } from '../core/mixins/internals/with-element-internals'; import { LinearProgressAdapter } from './linear-progress-adapter'; import { LinearProgressTheme, LINEAR_PROGRESS_CONSTANTS } from './linear-progress-constants'; import { LinearProgressFoundation } from './linear-progress-foundation'; @@ -7,7 +9,7 @@ import { LinearProgressFoundation } from './linear-progress-foundation'; import template from './linear-progress.html'; import styles from './linear-progress.scss'; -export interface ILinearProgressComponent extends IBaseComponent { +export interface ILinearProgressComponent extends IWithElementInternals, IWithDefaultAria { determinate: boolean; progress: number; buffer: number; @@ -57,7 +59,7 @@ declare global { @CustomElement({ name: LINEAR_PROGRESS_CONSTANTS.elementName }) -export class LinearProgressComponent extends BaseComponent implements ILinearProgressComponent { +export class LinearProgressComponent extends WithElementInternals(WithDefaultAria(BaseComponent)) implements ILinearProgressComponent { public static get observedAttributes(): string[] { return [ LINEAR_PROGRESS_CONSTANTS.attributes.DETERMINATE, diff --git a/src/lib/radio/core/radio-group-manager.ts b/src/lib/radio/core/radio-group-manager.ts index 188f1ca7b..9d70ca3a0 100644 --- a/src/lib/radio/core/radio-group-manager.ts +++ b/src/lib/radio/core/radio-group-manager.ts @@ -59,7 +59,7 @@ export class RadioGroupManager { checked: radio.checked }); radio[internals].setValidity({ valueMissing: invalid }, validationMessage); - radio[setDefaultAria]({ 'ariaInvalid': invalid ? 'true' : 'false' }, { overwrite: true }); + radio[setDefaultAria]({ 'ariaInvalid': invalid ? 'true' : 'false' }); }); } diff --git a/src/lib/radio/radio-group/radio-group-adapter.ts b/src/lib/radio/radio-group/radio-group-adapter.ts index 5d718e50e..26c1c575c 100644 --- a/src/lib/radio/radio-group/radio-group-adapter.ts +++ b/src/lib/radio/radio-group/radio-group-adapter.ts @@ -20,9 +20,7 @@ export class RadioGroupAdapter extends BaseAdapter impleme } public setDisabled(value: boolean): void { - this._component[setDefaultAria]({ - ariaDisabled: value ? 'true' : null - }, { overwrite: true }); + this._component[setDefaultAria]({ ariaDisabled: value ? 'true' : null }); this._disableRadios(value); } diff --git a/src/lib/radio/radio-group/radio-group-constants.ts b/src/lib/radio/radio-group/radio-group-constants.ts index 349f9dbf0..f6ab62267 100644 --- a/src/lib/radio/radio-group/radio-group-constants.ts +++ b/src/lib/radio/radio-group/radio-group-constants.ts @@ -1,6 +1,4 @@ import { COMPONENT_NAME_PREFIX } from '../../constants'; -import { ARIAAttribute } from '../../core/utils/a11y-utils'; -import { supportsElementInternalsAria } from '../../core/utils/feature-detection'; const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}radio-group`; @@ -8,12 +6,7 @@ const attributes = { DISABLED: 'disabled' }; -const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() - ? [] - : ['role', 'aria-disabled', 'aria-label']; - export const RADIO_GROUP_CONSTANTS = { elementName, - attributes, - observedAriaAttributes + attributes }; diff --git a/src/lib/radio/radio-group/radio-group.ts b/src/lib/radio/radio-group/radio-group.ts index b1012196c..38cf2b0b9 100644 --- a/src/lib/radio/radio-group/radio-group.ts +++ b/src/lib/radio/radio-group/radio-group.ts @@ -1,5 +1,5 @@ import { CustomElement, FoundationProperty, attachShadowTemplate, coerceBoolean, toggleAttribute } from '@tylertech/forge-core'; -import { internals, observedDefaultAriaAttributes, setDefaultAria } from '../../constants'; +import { internals, setDefaultAria } from '../../constants'; import { BaseComponent } from '../../core/base/base-component'; import { IWithDefaultAria, WithDefaultAria } from '../../core/mixins/internals/with-default-aria'; import { IWithElementInternals, WithElementInternals } from '../../core/mixins/internals/with-element-internals'; @@ -41,8 +41,6 @@ const BaseRadioGroupClass = WithLabelAwareness(WithDefaultAria(WithElementIntern export class RadioGroupComponent extends BaseRadioGroupClass implements IRadioGroupComponent { public static readonly formAssociated = true; - public readonly [observedDefaultAriaAttributes] = RADIO_GROUP_CONSTANTS.observedAriaAttributes; - public get form(): HTMLFormElement | null { return this[internals].form; } @@ -80,13 +78,12 @@ export class RadioGroupComponent extends BaseRadioGroupClass implements IRadioGr this._foundation.initialize(); } - public override attributeChangedCallback(name: string, oldValue: string, newValue: string): void { + public attributeChangedCallback(name: string, oldValue: string, newValue: string): void { switch (name) { case RADIO_GROUP_CONSTANTS.attributes.DISABLED: this.disabled = coerceBoolean(newValue); break; } - super.attributeChangedCallback(name, oldValue, newValue); } public formDisabledCallback(isDisabled: boolean): void { diff --git a/src/lib/radio/radio/radio-adapter.ts b/src/lib/radio/radio/radio-adapter.ts index fe7847d9a..83282d118 100644 --- a/src/lib/radio/radio/radio-adapter.ts +++ b/src/lib/radio/radio/radio-adapter.ts @@ -32,9 +32,7 @@ export class RadioAdapter extends BaseAdapter implements IRadio } public setChecked(checked: boolean, value: string): void { - this._component[setDefaultAria]({ - ariaChecked: checked ? 'true' : 'false' - }, { overwrite: true }); + this._component[setDefaultAria]({ ariaChecked: checked ? 'true' : 'false' }); if (checked) { RadioGroupManager.setSelectedRadioInGroup(this._component); } @@ -60,9 +58,7 @@ export class RadioAdapter extends BaseAdapter implements IRadio return false; } - this._component[setDefaultAria]({ - ariaDisabled: value ? 'true' : 'false' - }, { overwrite: true }); + this._component[setDefaultAria]({ ariaDisabled: `${!!value}` }); this._component[isFocusable] = !value; return true; } @@ -70,14 +66,12 @@ export class RadioAdapter extends BaseAdapter implements IRadio public setRequired(value: boolean): void { this._component[setDefaultAria]({ ariaRequired: value ? 'true' : 'false' - }, { overwrite: true }); + }, { setAttribute: true }); RadioGroupManager.setRadioGroupValidity(this._component); } public setReadonly(value: boolean): void { - this._component[setDefaultAria]({ - ariaDisabled: value ? 'true' : 'false' - }, { overwrite: true }); + this._component[setDefaultAria]({ ariaDisabled: `${!!value}` }); } public disableStateLayer(value: boolean): void { diff --git a/src/lib/radio/radio/radio-constants.ts b/src/lib/radio/radio/radio-constants.ts index 67326316b..0736b2760 100644 --- a/src/lib/radio/radio/radio-constants.ts +++ b/src/lib/radio/radio/radio-constants.ts @@ -1,6 +1,4 @@ import { COMPONENT_NAME_PREFIX } from '../../constants'; -import { ARIAAttribute } from '../../core/utils/a11y-utils'; -import { supportsElementInternalsAria } from '../../core/utils/feature-detection'; const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}radio`; @@ -27,24 +25,11 @@ const events = { INPUT: 'input' }; -const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() - ? [] - : [ - 'role', - 'aria-checked', - 'aria-disabled', - 'aria-invalid', - 'aria-label', - 'aria-readonly', - 'aria-required' - ]; - export const RADIO_CONSTANTS = { elementName, attributes, selectors, - events, - observedAriaAttributes + events }; /** diff --git a/src/lib/radio/radio/radio.ts b/src/lib/radio/radio/radio.ts index 1f523caa7..fc10edaa8 100644 --- a/src/lib/radio/radio/radio.ts +++ b/src/lib/radio/radio/radio.ts @@ -1,5 +1,5 @@ import { CustomElement, FoundationProperty, attachShadowTemplate, coerceBoolean } from '@tylertech/forge-core'; -import { getFormState, getFormValue, inputType, internals, observedDefaultAriaAttributes, setDefaultAria } from '../../constants'; +import { getFormState, getFormValue, inputType, internals, setDefaultAria } from '../../constants'; import { BaseComponent } from '../../core/base/base-component'; import { IWithFocusable, WithFocusable } from '../../core/mixins/focus/with-focusable'; import { IWithElementInternals, WithElementInternals } from '../../core/mixins/internals/with-element-internals'; @@ -116,13 +116,10 @@ export class RadioComponent extends BaseRadioClass implements IRadioComponent { RADIO_CONSTANTS.attributes.REQUIRED, RADIO_CONSTANTS.attributes.READONLY, RADIO_CONSTANTS.attributes.LABEL_POSITION, - RADIO_CONSTANTS.attributes.TABINDEX, - ...RADIO_CONSTANTS.observedAriaAttributes + RADIO_CONSTANTS.attributes.TABINDEX ]; } - public readonly [observedDefaultAriaAttributes] = RADIO_CONSTANTS.observedAriaAttributes; - private _foundation: RadioFoundation; constructor() { @@ -195,9 +192,7 @@ export class RadioComponent extends BaseRadioClass implements IRadioComponent { } public labelChangedCallback(value: string | null): void { - this[setDefaultAria]({ - ariaLabel: value ?? undefined - }); + this[setDefaultAria]({ ariaLabel: value }); } @FoundationProperty() From 9b87fa4740e5b4bf69b06d380b2acb7bf7ec5b65 Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Wed, 13 Dec 2023 16:48:49 -0500 Subject: [PATCH 2/9] chore: cleanup --- src/lib/button/base/base-button-adapter.ts | 4 ++-- src/lib/core/utils/a11y-utils.ts | 4 ++-- src/lib/linear-progress/linear-progress-adapter.ts | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/button/base/base-button-adapter.ts b/src/lib/button/base/base-button-adapter.ts index 730b917d1..f3820e637 100644 --- a/src/lib/button/base/base-button-adapter.ts +++ b/src/lib/button/base/base-button-adapter.ts @@ -261,8 +261,8 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme private _applyHostSemantics(): void { const role = this._component.getAttribute('role'); - const overwrite = !role || ['button', 'link'].includes(role); - this._component[setDefaultAria]({ role: this._anchorElement ? 'link' : 'button' }, { setAttribute: overwrite }); + const setAttribute = !role || ['button', 'link'].includes(role); + this._component[setDefaultAria]({ role: this._anchorElement ? 'link' : 'button' }, { setAttribute }); this._component[isFocusable] = !!this._anchorElement ?? !this._component.disabled; } diff --git a/src/lib/core/utils/a11y-utils.ts b/src/lib/core/utils/a11y-utils.ts index e066739c5..f752c5b2a 100644 --- a/src/lib/core/utils/a11y-utils.ts +++ b/src/lib/core/utils/a11y-utils.ts @@ -249,7 +249,7 @@ export function setDefaultAria( element: HTMLElement, internals: ElementInternals, properties: Partial, - { setAttribute: overwrite }: DefaultAriaOptions = { setAttribute: true } + { setAttribute }: DefaultAriaOptions = { setAttribute: true } ): void { Object.entries(properties).forEach(([key, value]) => { if (supportsElementInternalsAria()) { @@ -257,7 +257,7 @@ export function setDefaultAria( } const attribute = ariaPropertyToAttribute(key as ARIAProperty); - if (overwrite || !element.hasAttribute(attribute)) { + if (setAttribute || !element.hasAttribute(attribute)) { toggleAttribute(element, value != null, attribute, value as string); } }); diff --git a/src/lib/linear-progress/linear-progress-adapter.ts b/src/lib/linear-progress/linear-progress-adapter.ts index cce79315b..a3726192c 100644 --- a/src/lib/linear-progress/linear-progress-adapter.ts +++ b/src/lib/linear-progress/linear-progress-adapter.ts @@ -41,7 +41,6 @@ export class LinearProgressAdapter extends BaseAdapter } public setProgress(value: number): void { - // this._component.setAttribute('theme', 'test'); // TODO: figure this out this._component[setDefaultAria]({ ariaValueNow: `${value}` }); this._progressElement.style.transform = `scaleX(${value * 100}%)`; } From 659d5938220db4d8a1808a747e7d86d877407e8a Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Wed, 13 Dec 2023 17:42:39 -0500 Subject: [PATCH 3/9] chore(linear-progress): fix timing bug when setting determinate state and progress together --- .../linear-progress/linear-progress-adapter.ts | 9 ++++++--- .../linear-progress/linear-progress-constants.ts | 9 +++++++-- .../linear-progress/linear-progress-foundation.ts | 3 ++- src/lib/linear-progress/linear-progress.ts | 15 +++++---------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/lib/linear-progress/linear-progress-adapter.ts b/src/lib/linear-progress/linear-progress-adapter.ts index a3726192c..aa2ebcd6a 100644 --- a/src/lib/linear-progress/linear-progress-adapter.ts +++ b/src/lib/linear-progress/linear-progress-adapter.ts @@ -27,13 +27,16 @@ export class LinearProgressAdapter extends BaseAdapter this._component[setDefaultAria]({ role: 'progressbar', ariaValueMin: '0', - ariaValueMax: '1' + ariaValueMax: '1', + ariaValueNow: this._component.determinate ? `${this._component.progress}` : null }); } public setDeterminate(value: boolean): void { - if (!value) { - this._component[setDefaultAria]({ ariaValueNow: null }); + this._component[setDefaultAria]({ ariaValueNow: value ? `${this._component.progress}` : null }); + if (value) { + this.setProgress(this._component.progress); + } else { this._progressElement.style.transform = ''; this._bufferElement.style.transform = ''; } diff --git a/src/lib/linear-progress/linear-progress-constants.ts b/src/lib/linear-progress/linear-progress-constants.ts index 5b8574e95..34303bb60 100644 --- a/src/lib/linear-progress/linear-progress-constants.ts +++ b/src/lib/linear-progress/linear-progress-constants.ts @@ -12,18 +12,23 @@ const selectors = { BUFFER: '.buffer-bar' }; -const attributes = { +const observedAttributes = { DETERMINATE: 'determinate', PROGRESS: 'progress', BUFFER: 'buffer', THEME: 'theme' }; +const attributes = { + ...observedAttributes +}; + export const LINEAR_PROGRESS_CONSTANTS = { elementName, classes, selectors, - attributes + attributes, + observedAttributes }; export type LinearProgressTheme = Theme; diff --git a/src/lib/linear-progress/linear-progress-foundation.ts b/src/lib/linear-progress/linear-progress-foundation.ts index 50f2aa0c4..8585ebeab 100644 --- a/src/lib/linear-progress/linear-progress-foundation.ts +++ b/src/lib/linear-progress/linear-progress-foundation.ts @@ -25,6 +25,7 @@ export class LinearProgressFoundation { return this._determinate; } public set determinate(value: boolean) { + value = Boolean(value); if (this._determinate !== value) { this._determinate = value; this._adapter.setBuffer(this._determinate ? this._buffer : 1); @@ -43,7 +44,7 @@ export class LinearProgressFoundation { if (this._determinate) { this._adapter.setProgress(this._progress); } - this._adapter.setHostAttribute(LINEAR_PROGRESS_CONSTANTS.attributes.PROGRESS, this._progress.toString()); + this._adapter.setHostAttribute(LINEAR_PROGRESS_CONSTANTS.attributes.PROGRESS, String(this._progress)); } } diff --git a/src/lib/linear-progress/linear-progress.ts b/src/lib/linear-progress/linear-progress.ts index bdbc99878..994c816dc 100644 --- a/src/lib/linear-progress/linear-progress.ts +++ b/src/lib/linear-progress/linear-progress.ts @@ -61,12 +61,7 @@ declare global { }) export class LinearProgressComponent extends WithElementInternals(WithDefaultAria(BaseComponent)) implements ILinearProgressComponent { public static get observedAttributes(): string[] { - return [ - LINEAR_PROGRESS_CONSTANTS.attributes.DETERMINATE, - LINEAR_PROGRESS_CONSTANTS.attributes.PROGRESS, - LINEAR_PROGRESS_CONSTANTS.attributes.BUFFER, - LINEAR_PROGRESS_CONSTANTS.attributes.THEME - ]; + return Object.values(LINEAR_PROGRESS_CONSTANTS.observedAttributes); } private _foundation: LinearProgressFoundation; @@ -83,16 +78,16 @@ export class LinearProgressComponent extends WithElementInternals(WithDefaultAri public attributeChangedCallback(name: string, oldValue: string, newValue: string): void { switch (name) { - case LINEAR_PROGRESS_CONSTANTS.attributes.DETERMINATE: + case LINEAR_PROGRESS_CONSTANTS.observedAttributes.DETERMINATE: this.determinate = coerceBoolean(newValue); break; - case LINEAR_PROGRESS_CONSTANTS.attributes.PROGRESS: + case LINEAR_PROGRESS_CONSTANTS.observedAttributes.PROGRESS: this.progress = coerceNumber(newValue); break; - case LINEAR_PROGRESS_CONSTANTS.attributes.BUFFER: + case LINEAR_PROGRESS_CONSTANTS.observedAttributes.BUFFER: this.buffer = coerceNumber(newValue); break; - case LINEAR_PROGRESS_CONSTANTS.attributes.THEME: + case LINEAR_PROGRESS_CONSTANTS.observedAttributes.THEME: this.theme = newValue as LinearProgressTheme; break; } From eec1a5398ee828bb0c25f616f3b40e41391cb076 Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 08:09:46 -0500 Subject: [PATCH 4/9] chore: fix button tabindex --- src/lib/button/base/base-button-adapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/button/base/base-button-adapter.ts b/src/lib/button/base/base-button-adapter.ts index f3820e637..ec1fc23df 100644 --- a/src/lib/button/base/base-button-adapter.ts +++ b/src/lib/button/base/base-button-adapter.ts @@ -263,7 +263,7 @@ export abstract class BaseButtonAdapter extends BaseAdapter impleme const role = this._component.getAttribute('role'); const setAttribute = !role || ['button', 'link'].includes(role); this._component[setDefaultAria]({ role: this._anchorElement ? 'link' : 'button' }, { setAttribute }); - this._component[isFocusable] = !!this._anchorElement ?? !this._component.disabled; + this._component[isFocusable] = !!this._anchorElement || !this._component.disabled; } /** From 2a1186e97e594acee7d17ec9988d4d652168672e Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 08:51:58 -0500 Subject: [PATCH 5/9] chore: fix text theme colors and update button toggle demo with custom style example --- src/dev/pages/button-toggle/button-toggle.ejs | 19 ++++++++++ .../pages/button-toggle/button-toggle.scss | 37 +++++++++++++++++++ src/dev/pages/theme/theme.ts | 26 +++++++++---- .../button-toggle/button-toggle.scss | 9 ++++- .../button-toggle/button-toggle/_tokens.scss | 3 +- .../styles/tokens/theme/_tokens.text.scss | 4 +- 6 files changed, 85 insertions(+), 13 deletions(-) diff --git a/src/dev/pages/button-toggle/button-toggle.ejs b/src/dev/pages/button-toggle/button-toggle.ejs index 0f427f013..a1e430756 100644 --- a/src/dev/pages/button-toggle/button-toggle.ejs +++ b/src/dev/pages/button-toggle/button-toggle.ejs @@ -126,6 +126,25 @@ + + +
+

Legacy (custom)

+ + + + By email + + + + By mail + + + + By phone + + +
diff --git a/src/dev/pages/button-toggle/button-toggle.scss b/src/dev/pages/button-toggle/button-toggle.scss index 6d4cc2d63..d5c7aaa3b 100644 --- a/src/dev/pages/button-toggle/button-toggle.scss +++ b/src/dev/pages/button-toggle/button-toggle.scss @@ -1,4 +1,6 @@ @use '../../../lib/button-toggle/button-toggle-group'; +@use '../../../lib/button-toggle/button-toggle'; +@use '../../../lib/core/styles/theme'; #toolbar-card { display: inline-block; @@ -16,4 +18,39 @@ height: auto; margin-block: 4px; } +} + +.legacy-button-toggle-group { + @include button-toggle-group.provide-theme(( + gap: 1px, + padding: 0 + )); + + forge-button-toggle { + @include button-toggle.provide-theme(( + selected-color: theme.variable(on-primary), + selected-background: theme.variable(primary), + focus-indicator-offset: 2px + )); + + &:first-of-type { + @include button-toggle.provide-theme(( + shape-start-end: 0, + shape-end-end: 0 + )); + } + + &:not(:first-of-type):not(:last-of-type) { + @include button-toggle.provide-theme(( + shape: 0 + )); + } + + &:last-of-type { + @include button-toggle.provide-theme(( + shape-start-start: 0, + shape-end-start: 0 + )); + } + } } \ No newline at end of file diff --git a/src/dev/pages/theme/theme.ts b/src/dev/pages/theme/theme.ts index ef8623838..7e36a402f 100644 --- a/src/dev/pages/theme/theme.ts +++ b/src/dev/pages/theme/theme.ts @@ -8,7 +8,8 @@ interface ISwatchGroup { interface ISwatch { text?: string; - background: string; + background?: string; + border?: string; foreground?: string; } @@ -105,17 +106,19 @@ const SWATCH_GROUPS: ISwatchGroup[] = [ { header: 'Text', swatches: [ - { text: 'High', background: 'text-high', foreground: 'text-high-inverse' }, - { text: 'Medium', background: 'text-medium', foreground: 'text-high-inverse' }, - { text: 'Low', background: 'text-low', foreground: 'text-high' }, - { text: 'Lowest', background: 'text-lowest', foreground: 'text-high' } + { text: 'High (87%)', foreground: 'text-high'}, + { text: 'Medium (54%)', foreground: 'text-medium'}, + { text: 'Low (38%)', foreground: 'text-low'}, + { text: 'Lowest (12%)', foreground: 'text-lowest' } ] }, { header: 'Utilities', swatches: [ - { text: 'Outline', background: 'outline', foreground: 'text-high' }, - { text: 'Outline (high)', background: 'outline-high', foreground: 'text-high-inverse' } + { text: 'Outline (high)', border: 'outline-high' }, + { text: 'Outline (medium)', border: 'outline-medium' }, + { text: 'Outline (low)', border: 'outline-low' }, + { text: 'Outline', border: 'outline' } ] } ]; @@ -148,7 +151,14 @@ function createSwatch(config: ISwatch): HTMLElement { if (config.text) { swatch.textContent = config.text; } - swatch.style.setProperty('background-color', `var(--forge-theme-${config.background})`); + + if (config.border) { + swatch.style.setProperty('border-color', `var(--forge-theme-${config.border})`); + } + + if (config.background) { + swatch.style.setProperty('background-color', `var(--forge-theme-${config.background})`); + } if (config.foreground) { swatch.style.setProperty('color', `var(--forge-theme-${config.foreground})`); diff --git a/src/lib/button-toggle/button-toggle/button-toggle.scss b/src/lib/button-toggle/button-toggle/button-toggle.scss index d1c8399dd..3c6d6bcff 100644 --- a/src/lib/button-toggle/button-toggle/button-toggle.scss +++ b/src/lib/button-toggle/button-toggle/button-toggle.scss @@ -39,8 +39,13 @@ $_host-tokens: [display]; forge-focus-indicator { @include focus-indicator.provide-theme(( - outward-offset: 0px, // Requires unit - color: #{token(focus-indicator-color)} + outward-offset: #{token(focus-indicator-offset)}, + color: #{token(focus-indicator-color)}, + shape: #{token(shape)}, + shape-start-start: #{token(shape-start-start)}, + shape-start-end: #{token(shape-start-end)}, + shape-end-start: #{token(shape-end-start)}, + shape-end-end: #{token(shape-end-end)}, )); } } diff --git a/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss b/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss index efa35d890..8bb8d745d 100644 --- a/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss +++ b/src/lib/core/styles/tokens/button-toggle/button-toggle/_tokens.scss @@ -54,7 +54,8 @@ $tokens: ( transition-timing: utils.module-val(button-toggle, transition-timing, animation.variable(easing-standard)), // Focus indicator - focus-indicator-color: utils.module-val(button-toggle, focus-indicator-color, theme.variable(primary)) + focus-indicator-color: utils.module-val(button-toggle, focus-indicator-color, theme.variable(primary)), + focus-indicator-offset: utils.module-val(button-toggle, focus-indicator-offset, 0px) // Requires unit ) !default; @function get($key) { diff --git a/src/lib/core/styles/tokens/theme/_tokens.text.scss b/src/lib/core/styles/tokens/theme/_tokens.text.scss index cf166b837..0402d6d05 100644 --- a/src/lib/core/styles/tokens/theme/_tokens.text.scss +++ b/src/lib/core/styles/tokens/theme/_tokens.text.scss @@ -21,8 +21,8 @@ text-medium-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(medium)), text-low: theme-utils.emphasized($text, color-emphasis.value(medium-low)), text-low-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(medium-low)), - text-lowest: theme-utils.emphasized($text, color-emphasis.value(lowest)), - text-lowest-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(lowest)), + text-lowest: theme-utils.emphasized($text, color-emphasis.value(lower)), + text-lowest-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(lower)), ); } From 8dd4dd3affc2e328975a3f6d2e627b3f2de4a1bd Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 09:07:45 -0500 Subject: [PATCH 6/9] chore: increase medium text theme to 60% and add contrast ratio validation for dynamic color computation --- src/dev/pages/theme/theme.ts | 2 +- .../styles/tokens/theme/_token-utils.scss | 30 +++++++++++++++---- .../styles/tokens/theme/_tokens.text.scss | 4 +-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/dev/pages/theme/theme.ts b/src/dev/pages/theme/theme.ts index 7e36a402f..2790a0216 100644 --- a/src/dev/pages/theme/theme.ts +++ b/src/dev/pages/theme/theme.ts @@ -107,7 +107,7 @@ const SWATCH_GROUPS: ISwatchGroup[] = [ header: 'Text', swatches: [ { text: 'High (87%)', foreground: 'text-high'}, - { text: 'Medium (54%)', foreground: 'text-medium'}, + { text: 'Medium (60%)', foreground: 'text-medium'}, { text: 'Low (38%)', foreground: 'text-low'}, { text: 'Lowest (12%)', foreground: 'text-lowest' } ] diff --git a/src/lib/core/styles/tokens/theme/_token-utils.scss b/src/lib/core/styles/tokens/theme/_token-utils.scss index 89be5ebd3..e5fb2bf50 100644 --- a/src/lib/core/styles/tokens/theme/_token-utils.scss +++ b/src/lib/core/styles/tokens/theme/_token-utils.scss @@ -18,10 +18,10 @@ $surface-tone: color-utils.tone($surface); // The container colors are the provided color mixed with the surface color at lower emphasis levels - $container-minimum: theme-utils.hexify($color, $surface, color-emphasis.value(minimum)); - $container-low: theme-utils.hexify($color, $surface, color-emphasis.value(lower)); - $container: theme-utils.hexify($color, $surface, color-emphasis.value(low)); $container-high: theme-utils.hexify($color, $surface, color-emphasis.value(medium-low)); + $container: theme-utils.hexify($color, $surface, color-emphasis.value(low)); + $container-low: theme-utils.hexify($color, $surface, color-emphasis.value(lower)); + $container-minimum: theme-utils.hexify($color, $surface, color-emphasis.value(minimum)); // The on-color is the contrast color against the provided color $on-color: theme-utils.contrast($color); @@ -29,10 +29,28 @@ // The on-container colors are the contrast color for the provided color mixed with the // container color at a lower emphasis to let the contrast color bleed through for // increased contrast against the lower emphasis container color - $on-container-minimum: theme-utils.hexify($color, theme-utils.contrast($container-minimum), color-emphasis.value(medium)); - $on-container-low: theme-utils.hexify($color, theme-utils.contrast($container-low), color-emphasis.value(medium)); - $on-container: theme-utils.hexify($color, theme-utils.contrast($container), color-emphasis.value(medium)); $on-container-high: theme-utils.contrast($container-high); + $on-container: theme-utils.hexify($color, theme-utils.contrast($container), color-emphasis.value(medium)); + $on-container-low: theme-utils.hexify($color, theme-utils.contrast($container-low), color-emphasis.value(medium)); + $on-container-minimum: theme-utils.hexify($color, theme-utils.contrast($container-minimum), color-emphasis.value(medium)); + + // Compute contrast ratio for foreground colors against their corresponding background + $minimum-ratio: 4.5; + @if color-utils.contrast-ratio($color, $on-color) < $minimum-ratio { + @warn 'The contrast ratio between "#{$name}" and "on-#{$name}" is less than 4.5:1.'; + } + @if color-utils.contrast-ratio($container, $on-container) < $minimum-ratio { + @warn 'The contrast ratio between "#{$name}-container" and "on-#{$name}-container" is less than 4.5:1.'; + } + @if color-utils.contrast-ratio($container-high, $on-container-high) < $minimum-ratio { + @warn 'The contrast ratio between "#{$name}-container-high" and "on-#{$name}-container-high" is less than 4.5:1.'; + } + @if color-utils.contrast-ratio($container-low, $on-container-low) < $minimum-ratio { + @warn 'The contrast ratio between "#{$name}-container-low" and "on-#{$name}-container-low" is less than 4.5:1.'; + } + @if color-utils.contrast-ratio($container-minimum, $on-container-minimum) < $minimum-ratio { + @warn 'The contrast ratio between "#{$name}-container-minimum" and "on-#{$name}-container-minimum" is less than 4.5:1.'; + } @return ( #{$name}: $color, diff --git a/src/lib/core/styles/tokens/theme/_tokens.text.scss b/src/lib/core/styles/tokens/theme/_tokens.text.scss index 0402d6d05..3d1f78477 100644 --- a/src/lib/core/styles/tokens/theme/_tokens.text.scss +++ b/src/lib/core/styles/tokens/theme/_tokens.text.scss @@ -17,8 +17,8 @@ @return ( text-high: theme-utils.emphasized($text, color-emphasis.value(highest)), text-high-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(highest)), - text-medium: theme-utils.emphasized($text, color-emphasis.value(medium)), - text-medium-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(medium)), + text-medium: theme-utils.emphasized($text, color-emphasis.value(medium-high)), + text-medium-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(medium-high)), text-low: theme-utils.emphasized($text, color-emphasis.value(medium-low)), text-low-inverse: theme-utils.emphasized($text-inverse, color-emphasis.value(medium-low)), text-lowest: theme-utils.emphasized($text, color-emphasis.value(lower)), From 18e333317c53474b65cd6ea6aac460edc0aa1139 Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 09:14:57 -0500 Subject: [PATCH 7/9] chore: remove unused MDC deps --- package-lock.json | 3 --- package.json | 3 --- 2 files changed, 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49f572437..5dcf480b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,6 @@ "@material/card": "^14.0.0", "@material/checkbox": "^14.0.0", "@material/chips": "^14.0.0", - "@material/density": "^14.0.0", - "@material/dom": "^14.0.0", "@material/drawer": "^14.0.0", "@material/elevation": "^14.0.0", "@material/feature-targeting": "^14.0.0", @@ -27,7 +25,6 @@ "@material/select": "^14.0.0", "@material/shape": "^14.0.0", "@material/theme": "^14.0.0", - "@material/touch-target": "^14.0.0", "@material/typography": "^14.0.0", "@tylertech/forge-core": "^2.3.0", "@tylertech/tyler-icons": "^1.12.0", diff --git a/package.json b/package.json index fd63d4481..3a6a96d85 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,6 @@ "@material/card": "^14.0.0", "@material/checkbox": "^14.0.0", "@material/chips": "^14.0.0", - "@material/density": "^14.0.0", - "@material/dom": "^14.0.0", "@material/drawer": "^14.0.0", "@material/elevation": "^14.0.0", "@material/feature-targeting": "^14.0.0", @@ -54,7 +52,6 @@ "@material/select": "^14.0.0", "@material/shape": "^14.0.0", "@material/theme": "^14.0.0", - "@material/touch-target": "^14.0.0", "@material/typography": "^14.0.0", "@tylertech/forge-core": "^2.3.0", "@tylertech/tyler-icons": "^1.12.0", From a766609d0286225758c2addce7ed5f77dc46fc0a Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 09:22:30 -0500 Subject: [PATCH 8/9] chore: remove border on text example in theme demo --- src/dev/pages/theme/theme.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dev/pages/theme/theme.ts b/src/dev/pages/theme/theme.ts index 2790a0216..ad9ba5b50 100644 --- a/src/dev/pages/theme/theme.ts +++ b/src/dev/pages/theme/theme.ts @@ -10,6 +10,7 @@ interface ISwatch { text?: string; background?: string; border?: string; + noBorder?: boolean; foreground?: string; } @@ -106,10 +107,10 @@ const SWATCH_GROUPS: ISwatchGroup[] = [ { header: 'Text', swatches: [ - { text: 'High (87%)', foreground: 'text-high'}, - { text: 'Medium (60%)', foreground: 'text-medium'}, - { text: 'Low (38%)', foreground: 'text-low'}, - { text: 'Lowest (12%)', foreground: 'text-lowest' } + { text: 'High (87%)', foreground: 'text-high', noBorder: true }, + { text: 'Medium (60%)', foreground: 'text-medium', noBorder: true }, + { text: 'Low (38%)', foreground: 'text-low', noBorder: true }, + { text: 'Lowest (12%)', foreground: 'text-lowest', noBorder: true } ] }, { @@ -152,8 +153,10 @@ function createSwatch(config: ISwatch): HTMLElement { swatch.textContent = config.text; } - if (config.border) { + if (config.border && !config.noBorder) { swatch.style.setProperty('border-color', `var(--forge-theme-${config.border})`); + } else if (config.noBorder) { + swatch.style.setProperty('border', 'none'); } if (config.background) { From fe067afd7e32e811368f917bb9e5c91668a04fc0 Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Thu, 14 Dec 2023 09:27:03 -0500 Subject: [PATCH 9/9] chore(expansion-panel): remove internal `aria-expanded` attr --- src/lib/expansion-panel/expansion-panel-adapter.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/lib/expansion-panel/expansion-panel-adapter.ts b/src/lib/expansion-panel/expansion-panel-adapter.ts index c6377fb9e..189e29009 100644 --- a/src/lib/expansion-panel/expansion-panel-adapter.ts +++ b/src/lib/expansion-panel/expansion-panel-adapter.ts @@ -51,8 +51,6 @@ export class ExpansionPanelAdapter extends BaseAdapter openIconElement.open = true; } } - - this._headerElement.setAttribute('aria-expanded', open ? 'true' : 'false'); } public setHeaderVisibility(visible: boolean): void { @@ -125,7 +123,6 @@ export class ExpansionPanelAdapter extends BaseAdapter this._contentElement.style.height = `${this._contentElement.scrollHeight}px`; } this._contentElement.style.opacity = '1'; - this._headerElement.setAttribute('aria-expanded', 'true'); if (openIconElement) { openIconElement.open = true; } @@ -136,7 +133,6 @@ export class ExpansionPanelAdapter extends BaseAdapter this._contentElement.style.height = '0px'; } this._contentElement.style.opacity = '0'; - this._headerElement.setAttribute('aria-expanded', 'false'); if (openIconElement) { openIconElement.open = false; } @@ -158,7 +154,6 @@ export class ExpansionPanelAdapter extends BaseAdapter } this._contentElement.style.removeProperty('visibility'); this._contentElement.style.removeProperty('opacity'); - this._headerElement.setAttribute('aria-expanded', 'true'); if (openIconElement) { openIconElement.open = true; } @@ -170,7 +165,6 @@ export class ExpansionPanelAdapter extends BaseAdapter } this._contentElement.style.opacity = '0'; this._contentElement.style.visibility = 'hidden'; - this._headerElement.setAttribute('aria-expanded', 'false'); if (openIconElement) { openIconElement.open = false; }