fix(item, card): aria-label is reflected to the inner button (#26028)

Resolves #25885
This commit is contained in:
Sean Perkins
2022-10-10 14:19:55 -04:00
committed by GitHub
parent a5d178f4c0
commit 3c89ebe721
4 changed files with 84 additions and 4 deletions

View File

@ -1,9 +1,11 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { Element, Component, Host, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import type { AnimationBuilder, Color, Mode, RouterDirection } from '../../interface';
import type { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
import type { Attributes } from '../../utils/helpers';
import { inheritAttributes } from '../../utils/helpers';
import { createColorClasses, openURL } from '../../utils/theme';
/**
@ -20,6 +22,9 @@ import { createColorClasses, openURL } from '../../utils/theme';
shadow: true,
})
export class Card implements ComponentInterface, AnchorInterface, ButtonInterface {
private inheritedAriaAttributes: Attributes = {};
@Element() el!: HTMLElement;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
@ -81,6 +86,10 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
*/
@Prop() target: string | undefined;
componentWillLoad() {
this.inheritedAriaAttributes = inheritAttributes(this.el, ['aria-label']);
}
private isClickable(): boolean {
return this.href !== undefined || this.button;
}
@ -91,7 +100,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
if (!clickable) {
return [<slot></slot>];
}
const { href, routerAnimation, routerDirection } = this;
const { href, routerAnimation, routerDirection, inheritedAriaAttributes } = this;
const TagType = clickable ? (href === undefined ? 'button' : 'a') : ('div' as any);
const attrs =
TagType === 'button'
@ -106,6 +115,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
return (
<TagType
{...attrs}
{...inheritedAriaAttributes}
class="card-native"
part="native"
disabled={this.disabled}

View File

@ -0,0 +1,17 @@
import { newSpecPage } from '@stencil/core/testing';
import { Card } from '../card';
describe('card: button', () => {
it('should reflect aria-label to button', async () => {
const page = await newSpecPage({
components: [Card],
html: `<ion-card button="true" aria-label="Test"></ion-card>`,
});
const button = page.body.querySelector('ion-card')!.shadowRoot!.querySelector('button')!;
const ariaLabel = button.getAttribute('aria-label');
expect(ariaLabel).toEqual('Test');
});
});

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Card - Basic</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Card - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-card>
<ion-card-header>
<ion-card-subtitle>Card Subtitle</ion-card-subtitle>
<ion-card-title>Card Title</ion-card-title>
</ion-card-header>
<ion-card-content>
Keep close to Nature's heart... and break clear away, once in awhile, and climb a mountain or spend a week
in the woods. Wash your spirit clean.
</ion-card-content>
</ion-card>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -5,7 +5,8 @@ import { chevronForward } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import type { AnimationBuilder, Color, CssClassMap, RouterDirection, StyleEventDetail } from '../../interface';
import type { AnchorInterface, ButtonInterface } from '../../utils/element-interface';
import { raf } from '../../utils/helpers';
import type { Attributes } from '../../utils/helpers';
import { inheritAttributes, raf } from '../../utils/helpers';
import { printIonError } from '../../utils/logging';
import { createColorClasses, hostContext, openURL } from '../../utils/theme';
import type { InputChangeEventDetail } from '../input/input-interface';
@ -38,6 +39,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
private labelColorStyles = {};
private itemStyles = new Map<string, CssClassMap>();
private clickListener?: (ev: Event) => void;
private inheritedAriaAttributes: Attributes = {};
@Element() el!: HTMLIonItemElement;
@ -226,6 +228,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
componentDidLoad() {
raf(() => {
this.inheritedAriaAttributes = inheritAttributes(this.el, ['aria-label']);
this.setMultipleInputs();
this.focusable = this.isFocusable();
});
@ -359,12 +362,14 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
target,
routerAnimation,
routerDirection,
inheritedAriaAttributes,
} = this;
const childStyles = {} as any;
const mode = getIonMode(this);
const clickable = this.isClickable();
const canActivate = this.canActivate();
const TagType = clickable ? (href === undefined ? 'button' : 'a') : ('div' as any);
const attrs =
TagType === 'button'
? { type: this.type }
@ -390,6 +395,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
const ariaDisabled = disabled || childStyles['item-interactive-disabled'] ? 'true' : null;
const fillValue = fill || 'none';
const inList = hostContext('ion-list', this.el);
return (
<Host
aria-disabled={ariaDisabled}
@ -412,7 +418,14 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
}}
role={inList ? 'listitem' : null}
>
<TagType {...attrs} class="item-native" part="native" disabled={disabled} {...clickFn}>
<TagType
{...attrs}
{...inheritedAriaAttributes}
class="item-native"
part="native"
disabled={disabled}
{...clickFn}
>
<slot name="start"></slot>
<div class="item-inner">
<div class="input-wrapper">