From 0ff54b2d9561596f73f76f8c864cd2bbf24b04b2 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 28 Nov 2023 11:54:05 -0800 Subject: [PATCH 1/7] feat(picker-column-option): add the new component --- core/src/components.d.ts | 29 ++++++++++ .../picker-column-option.tsx | 55 ++++++++++++++++++ .../picker-column-option/test/a11y/index.html | 56 +++++++++++++++++++ .../test/basic/index.html | 55 ++++++++++++++++++ 4 files changed, 195 insertions(+) create mode 100644 core/src/components/picker-column-option/picker-column-option.tsx create mode 100644 core/src/components/picker-column-option/test/a11y/index.html create mode 100644 core/src/components/picker-column-option/test/basic/index.html diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 14d14454dec..08b817ae45f 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -2069,6 +2069,16 @@ export namespace Components { */ "value"?: string | number; } + interface IonPickerColumnOption { + /** + * If `true`, the user cannot interact with the select option. + */ + "disabled": boolean; + /** + * The text value of the option. + */ + "value"?: any | null; + } interface IonPickerInternal { "exitInputMode": () => Promise; /** @@ -4077,6 +4087,12 @@ declare global { prototype: HTMLIonPickerColumnInternalElement; new (): HTMLIonPickerColumnInternalElement; }; + interface HTMLIonPickerColumnOptionElement extends Components.IonPickerColumnOption, HTMLStencilElement { + } + var HTMLIonPickerColumnOptionElement: { + prototype: HTMLIonPickerColumnOptionElement; + new (): HTMLIonPickerColumnOptionElement; + }; interface HTMLIonPickerInternalElementEventMap { "ionInputModeChange": PickerInternalChangeEventDetail; } @@ -4648,6 +4664,7 @@ declare global { "ion-picker": HTMLIonPickerElement; "ion-picker-column": HTMLIonPickerColumnElement; "ion-picker-column-internal": HTMLIonPickerColumnInternalElement; + "ion-picker-column-option": HTMLIonPickerColumnOptionElement; "ion-picker-internal": HTMLIonPickerInternalElement; "ion-popover": HTMLIonPopoverElement; "ion-progress-bar": HTMLIonProgressBarElement; @@ -6712,6 +6729,16 @@ declare namespace LocalJSX { */ "value"?: string | number; } + interface IonPickerColumnOption { + /** + * If `true`, the user cannot interact with the select option. + */ + "disabled"?: boolean; + /** + * The text value of the option. + */ + "value"?: any | null; + } interface IonPickerInternal { /** * The mode determines which platform styles to use. @@ -8087,6 +8114,7 @@ declare namespace LocalJSX { "ion-picker": IonPicker; "ion-picker-column": IonPickerColumn; "ion-picker-column-internal": IonPickerColumnInternal; + "ion-picker-column-option": IonPickerColumnOption; "ion-picker-internal": IonPickerInternal; "ion-popover": IonPopover; "ion-progress-bar": IonProgressBar; @@ -8184,6 +8212,7 @@ declare module "@stencil/core" { "ion-picker": LocalJSX.IonPicker & JSXBase.HTMLAttributes; "ion-picker-column": LocalJSX.IonPickerColumn & JSXBase.HTMLAttributes; "ion-picker-column-internal": LocalJSX.IonPickerColumnInternal & JSXBase.HTMLAttributes; + "ion-picker-column-option": LocalJSX.IonPickerColumnOption & JSXBase.HTMLAttributes; "ion-picker-internal": LocalJSX.IonPickerInternal & JSXBase.HTMLAttributes; "ion-popover": LocalJSX.IonPopover & JSXBase.HTMLAttributes; "ion-progress-bar": LocalJSX.IonProgressBar & JSXBase.HTMLAttributes; diff --git a/core/src/components/picker-column-option/picker-column-option.tsx b/core/src/components/picker-column-option/picker-column-option.tsx new file mode 100644 index 00000000000..9e4145862a8 --- /dev/null +++ b/core/src/components/picker-column-option/picker-column-option.tsx @@ -0,0 +1,55 @@ +import type { ComponentInterface } from '@stencil/core'; +import { Component, Element, Host, Prop, h } from '@stencil/core'; +import type { Attributes } from '@utils/helpers'; +import { inheritAriaAttributes } from '@utils/helpers'; + +import { getIonMode } from '../../global/ionic-global'; + +@Component({ + tag: 'ion-picker-column-option', + shadow: true, +}) +export class PickerColumnOption implements ComponentInterface { + private optionId = `ion-picker-opt-${pickerOptionIds++}`; + + private inheritedAttributes: Attributes = {}; + + @Element() el!: HTMLElement; + + /** + * If `true`, the user cannot interact with the select option. + */ + @Prop() disabled = false; + + /** + * The text value of the option. + */ + @Prop() value?: any | null; + + componentWillLoad() { + this.inheritedAttributes = inheritAriaAttributes(this.el); + } + + render() { + const { value, disabled, inheritedAttributes } = this; + const ariaLabel = inheritedAttributes['aria-label'] || null; + + return ( + + + + ); + } +} + +let pickerOptionIds = 0; diff --git a/core/src/components/picker-column-option/test/a11y/index.html b/core/src/components/picker-column-option/test/a11y/index.html new file mode 100644 index 00000000000..560cc1ff188 --- /dev/null +++ b/core/src/components/picker-column-option/test/a11y/index.html @@ -0,0 +1,56 @@ + + + + + Picker Column Option - Basic + + + + + + + + + + + + + Picker Column Option - Basic + + + +
+
+

Default

+ my option + other option +
+
+
+
+ + diff --git a/core/src/components/picker-column-option/test/basic/index.html b/core/src/components/picker-column-option/test/basic/index.html new file mode 100644 index 00000000000..e8d4fdd39d6 --- /dev/null +++ b/core/src/components/picker-column-option/test/basic/index.html @@ -0,0 +1,55 @@ + + + + + Picker Column Option - Basic + + + + + + + + + + + + + Picker Column Option - Basic + + + +
+
+

Default

+ my option +
+
+
+
+ + From fa5076b9438cac15b09cd94ffeb684c520408583 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 28 Nov 2023 12:23:39 -0800 Subject: [PATCH 2/7] test(picker-column-option): build files --- core/api.txt | 4 +++ .../picker-column-option/test/a11y/index.html | 20 +++------------ .../test/a11y/picker-column-option.e2e.ts | 15 +++++++++++ .../angular/src/directives/proxies-list.ts | 1 + packages/angular/src/directives/proxies.ts | 22 ++++++++++++++++ .../standalone/src/directives/proxies.ts | 25 +++++++++++++++++++ packages/react/src/components/proxies.ts | 2 ++ packages/vue/src/proxies.ts | 7 ++++++ 8 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts diff --git a/core/api.txt b/core/api.txt index 76ad30213e8..860d1f572b3 100644 --- a/core/api.txt +++ b/core/api.txt @@ -906,6 +906,10 @@ ion-note,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "second ion-note,prop,mode,"ios" | "md",undefined,false,false ion-note,css-prop,--color +ion-picker-column-option,shadow +ion-picker-column-option,prop,disabled,boolean,false,false,false +ion-picker-column-option,prop,value,any,undefined,false,false + ion-picker-legacy,scoped ion-picker-legacy,prop,animated,boolean,true,false,false ion-picker-legacy,prop,backdropDismiss,boolean,true,false,false diff --git a/core/src/components/picker-column-option/test/a11y/index.html b/core/src/components/picker-column-option/test/a11y/index.html index 560cc1ff188..06fcabdd171 100644 --- a/core/src/components/picker-column-option/test/a11y/index.html +++ b/core/src/components/picker-column-option/test/a11y/index.html @@ -36,21 +36,9 @@ - - - - Picker Column Option - Basic - - - -
-
-

Default

- my option - other option -
-
-
-
+
+ my option + other option +
diff --git a/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts b/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts new file mode 100644 index 00000000000..7bcffef41d8 --- /dev/null +++ b/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts @@ -0,0 +1,15 @@ +import AxeBuilder from '@axe-core/playwright'; +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; + +configs({ directions: ['ltr'] }).forEach(({ config, title }) => { + test.describe(title('picker column option: a11y'), () => { + test('should not have accessibility violations', async ({ page }) => { + await page.goto(`/src/components/picker-column-option/test/a11y`, config); + + const results = await new AxeBuilder({ page }).analyze(); + + expect(results.violations).toEqual([]); + }); + }); +}); diff --git a/packages/angular/src/directives/proxies-list.ts b/packages/angular/src/directives/proxies-list.ts index 180a1e94216..d2e0bcdeb5c 100644 --- a/packages/angular/src/directives/proxies-list.ts +++ b/packages/angular/src/directives/proxies-list.ts @@ -51,6 +51,7 @@ export const DIRECTIVES = [ d.IonMenuToggle, d.IonNavLink, d.IonNote, + d.IonPickerColumnOption, d.IonPickerLegacy, d.IonProgressBar, d.IonRadio, diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 6342c3cbed5..3de9ddccb8b 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -1417,6 +1417,28 @@ export class IonNote { export declare interface IonNote extends Components.IonNote {} +@ProxyCmp({ + inputs: ['disabled', 'value'] +}) +@Component({ + selector: 'ion-picker-column-option', + changeDetection: ChangeDetectionStrategy.OnPush, + template: '', + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['disabled', 'value'], +}) +export class IonPickerColumnOption { + protected el: HTMLElement; + constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { + c.detach(); + this.el = r.nativeElement; + } +} + + +export declare interface IonPickerColumnOption extends Components.IonPickerColumnOption {} + + @ProxyCmp({ inputs: ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger'], methods: ['present', 'dismiss', 'onDidDismiss', 'onWillDismiss', 'getColumn'] diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index 99034b72370..f7665d72a18 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -51,6 +51,7 @@ import { defineCustomElement as defineIonMenuButton } from '@ionic/core/componen import { defineCustomElement as defineIonMenuToggle } from '@ionic/core/components/ion-menu-toggle.js'; import { defineCustomElement as defineIonNavLink } from '@ionic/core/components/ion-nav-link.js'; import { defineCustomElement as defineIonNote } from '@ionic/core/components/ion-note.js'; +import { defineCustomElement as defineIonPickerColumnOption } from '@ionic/core/components/ion-picker-column-option.js'; import { defineCustomElement as defineIonPickerLegacy } from '@ionic/core/components/ion-picker-legacy.js'; import { defineCustomElement as defineIonProgressBar } from '@ionic/core/components/ion-progress-bar.js'; import { defineCustomElement as defineIonRadio } from '@ionic/core/components/ion-radio.js'; @@ -1406,6 +1407,30 @@ export class IonNote { export declare interface IonNote extends Components.IonNote {} +@ProxyCmp({ + defineCustomElementFn: defineIonPickerColumnOption, + inputs: ['disabled', 'value'] +}) +@Component({ + selector: 'ion-picker-column-option', + changeDetection: ChangeDetectionStrategy.OnPush, + template: '', + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['disabled', 'value'], + standalone: true +}) +export class IonPickerColumnOption { + protected el: HTMLElement; + constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { + c.detach(); + this.el = r.nativeElement; + } +} + + +export declare interface IonPickerColumnOption extends Components.IonPickerColumnOption {} + + @ProxyCmp({ defineCustomElementFn: defineIonPickerLegacy, inputs: ['animated', 'backdropDismiss', 'buttons', 'columns', 'cssClass', 'duration', 'enterAnimation', 'htmlAttributes', 'isOpen', 'keyboardClose', 'leaveAnimation', 'mode', 'showBackdrop', 'trigger'], diff --git a/packages/react/src/components/proxies.ts b/packages/react/src/components/proxies.ts index 99897431763..cfec0333d2d 100644 --- a/packages/react/src/components/proxies.ts +++ b/packages/react/src/components/proxies.ts @@ -44,6 +44,7 @@ import { defineCustomElement as defineIonMenuToggle } from '@ionic/core/componen import { defineCustomElement as defineIonNav } from '@ionic/core/components/ion-nav.js'; import { defineCustomElement as defineIonNavLink } from '@ionic/core/components/ion-nav-link.js'; import { defineCustomElement as defineIonNote } from '@ionic/core/components/ion-note.js'; +import { defineCustomElement as defineIonPickerColumnOption } from '@ionic/core/components/ion-picker-column-option.js'; import { defineCustomElement as defineIonProgressBar } from '@ionic/core/components/ion-progress-bar.js'; import { defineCustomElement as defineIonRadio } from '@ionic/core/components/ion-radio.js'; import { defineCustomElement as defineIonRadioGroup } from '@ionic/core/components/ion-radio-group.js'; @@ -109,6 +110,7 @@ export const IonMenuToggle = /*@__PURE__*/createReactComponent('ion-nav', undefined, undefined, defineIonNav); export const IonNavLink = /*@__PURE__*/createReactComponent('ion-nav-link', undefined, undefined, defineIonNavLink); export const IonNote = /*@__PURE__*/createReactComponent('ion-note', undefined, undefined, defineIonNote); +export const IonPickerColumnOption = /*@__PURE__*/createReactComponent('ion-picker-column-option', undefined, undefined, defineIonPickerColumnOption); export const IonProgressBar = /*@__PURE__*/createReactComponent('ion-progress-bar', undefined, undefined, defineIonProgressBar); export const IonRadio = /*@__PURE__*/createReactComponent('ion-radio', undefined, undefined, defineIonRadio); export const IonRadioGroup = /*@__PURE__*/createReactComponent('ion-radio-group', undefined, undefined, defineIonRadioGroup); diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index 5a3451f8619..dc474a3b8eb 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -50,6 +50,7 @@ import { defineCustomElement as defineIonMenuToggle } from '@ionic/core/componen import { defineCustomElement as defineIonNav } from '@ionic/core/components/ion-nav.js'; import { defineCustomElement as defineIonNavLink } from '@ionic/core/components/ion-nav-link.js'; import { defineCustomElement as defineIonNote } from '@ionic/core/components/ion-note.js'; +import { defineCustomElement as defineIonPickerColumnOption } from '@ionic/core/components/ion-picker-column-option.js'; import { defineCustomElement as defineIonProgressBar } from '@ionic/core/components/ion-progress-bar.js'; import { defineCustomElement as defineIonRadio } from '@ionic/core/components/ion-radio.js'; import { defineCustomElement as defineIonRadioGroup } from '@ionic/core/components/ion-radio-group.js'; @@ -569,6 +570,12 @@ export const IonNote = /*@__PURE__*/ defineContainer('ion-note', de ]); +export const IonPickerColumnOption = /*@__PURE__*/ defineContainer('ion-picker-column-option', defineIonPickerColumnOption, [ + 'disabled', + 'value' +]); + + export const IonProgressBar = /*@__PURE__*/ defineContainer('ion-progress-bar', defineIonProgressBar, [ 'type', 'reversed', From decd0f4b5a0a1fd02673a362d970fbecc3b8775e Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 28 Nov 2023 13:00:31 -0800 Subject: [PATCH 3/7] feat(picker-column-option): remove unused styles --- .../picker-column-option/test/a11y/index.html | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/core/src/components/picker-column-option/test/a11y/index.html b/core/src/components/picker-column-option/test/a11y/index.html index 06fcabdd171..9c19fd0b737 100644 --- a/core/src/components/picker-column-option/test/a11y/index.html +++ b/core/src/components/picker-column-option/test/a11y/index.html @@ -8,31 +8,6 @@ - From 0a2c2b00a0fe64b966292127c901233578e5d7b7 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 28 Nov 2023 13:01:54 -0800 Subject: [PATCH 4/7] feat(picker-column-option): add comment --- .../picker-column-option/test/a11y/picker-column-option.e2e.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts b/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts index 7bcffef41d8..aef2df2c7e9 100644 --- a/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts +++ b/core/src/components/picker-column-option/test/a11y/picker-column-option.e2e.ts @@ -2,6 +2,9 @@ import AxeBuilder from '@axe-core/playwright'; import { expect } from '@playwright/test'; import { configs, test } from '@utils/test/playwright'; +/** + * This behavior does not vary across directions + */ configs({ directions: ['ltr'] }).forEach(({ config, title }) => { test.describe(title('picker column option: a11y'), () => { test('should not have accessibility violations', async ({ page }) => { From 6777923ee94766fa4588cbe2c4e462f8f4abacbd Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Wed, 29 Nov 2023 12:02:11 -0800 Subject: [PATCH 5/7] feat(picker-column-option): use @Watch for ariaLabel --- .../picker-column-option.tsx | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/core/src/components/picker-column-option/picker-column-option.tsx b/core/src/components/picker-column-option/picker-column-option.tsx index 9e4145862a8..987a9309c58 100644 --- a/core/src/components/picker-column-option/picker-column-option.tsx +++ b/core/src/components/picker-column-option/picker-column-option.tsx @@ -1,7 +1,6 @@ import type { ComponentInterface } from '@stencil/core'; -import { Component, Element, Host, Prop, h } from '@stencil/core'; -import type { Attributes } from '@utils/helpers'; -import { inheritAriaAttributes } from '@utils/helpers'; +import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core'; +import { inheritAttributes } from '@utils/helpers'; import { getIonMode } from '../../global/ionic-global'; @@ -12,10 +11,18 @@ import { getIonMode } from '../../global/ionic-global'; export class PickerColumnOption implements ComponentInterface { private optionId = `ion-picker-opt-${pickerOptionIds++}`; - private inheritedAttributes: Attributes = {}; - @Element() el!: HTMLElement; + /** + * The aria-label of the option. + * + * If the value changes, then it will trigger a + * re-render of the picker since it's a @State variable. + * Otherwise, the `aria-label` attribute cannot be updated + * after the component is loaded. + */ + @State() ariaLabel?: string | null = null; + /** * If `true`, the user cannot interact with the select option. */ @@ -26,13 +33,24 @@ export class PickerColumnOption implements ComponentInterface { */ @Prop() value?: any | null; + /** + * The aria-label of the option has changed + * and needs to be updated within the component. + * + * @param ariaLbl The new aria-label value. + */ + @Watch('aria-label') + onAriaLabelChange(ariaLbl: string) { + this.ariaLabel = ariaLbl; + } + componentWillLoad() { - this.inheritedAttributes = inheritAriaAttributes(this.el); + const inheritedAttributes = inheritAttributes(this.el, ['aria-label']); + this.ariaLabel = inheritedAttributes['aria-label'] || null; } render() { - const { value, disabled, inheritedAttributes } = this; - const ariaLabel = inheritedAttributes['aria-label'] || null; + const { value, disabled, ariaLabel } = this; return ( From 841ea51e963e32b4377a2518f88de5db30f84845 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Wed, 29 Nov 2023 12:34:03 -0800 Subject: [PATCH 6/7] feat(picker-column-option): add comment --- .../picker-column-option/picker-column-option.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/components/picker-column-option/picker-column-option.tsx b/core/src/components/picker-column-option/picker-column-option.tsx index 987a9309c58..5608ffe4fdc 100644 --- a/core/src/components/picker-column-option/picker-column-option.tsx +++ b/core/src/components/picker-column-option/picker-column-option.tsx @@ -34,8 +34,8 @@ export class PickerColumnOption implements ComponentInterface { @Prop() value?: any | null; /** - * The aria-label of the option has changed - * and needs to be updated within the component. + * The aria-label of the option has changed after the + * first render and needs to be updated within the component. * * @param ariaLbl The new aria-label value. */ @@ -46,6 +46,10 @@ export class PickerColumnOption implements ComponentInterface { componentWillLoad() { const inheritedAttributes = inheritAttributes(this.el, ['aria-label']); + /** + * The initial value of `aria-label` needs to be set for + * the first render. + */ this.ariaLabel = inheritedAttributes['aria-label'] || null; } From 04a0760bd1e687ce0358bbf8c646433215fbfcf4 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Wed, 29 Nov 2023 17:01:03 -0800 Subject: [PATCH 7/7] feat(picker-column-option): requested changes --- core/src/components.d.ts | 4 ++-- .../picker-column-option/picker-column-option.tsx | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 5e0ba7cf242..54929a21881 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -1988,7 +1988,7 @@ export namespace Components { } interface IonPickerColumnOption { /** - * If `true`, the user cannot interact with the select option. + * If `true`, the user cannot interact with the picker column option. */ "disabled": boolean; /** @@ -6635,7 +6635,7 @@ declare namespace LocalJSX { } interface IonPickerColumnOption { /** - * If `true`, the user cannot interact with the select option. + * If `true`, the user cannot interact with the picker column option. */ "disabled"?: boolean; /** diff --git a/core/src/components/picker-column-option/picker-column-option.tsx b/core/src/components/picker-column-option/picker-column-option.tsx index 5608ffe4fdc..b45adb6e2cb 100644 --- a/core/src/components/picker-column-option/picker-column-option.tsx +++ b/core/src/components/picker-column-option/picker-column-option.tsx @@ -2,15 +2,11 @@ import type { ComponentInterface } from '@stencil/core'; import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core'; import { inheritAttributes } from '@utils/helpers'; -import { getIonMode } from '../../global/ionic-global'; - @Component({ tag: 'ion-picker-column-option', shadow: true, }) export class PickerColumnOption implements ComponentInterface { - private optionId = `ion-picker-opt-${pickerOptionIds++}`; - @Element() el!: HTMLElement; /** @@ -24,7 +20,7 @@ export class PickerColumnOption implements ComponentInterface { @State() ariaLabel?: string | null = null; /** - * If `true`, the user cannot interact with the select option. + * If `true`, the user cannot interact with the picker column option. */ @Prop() disabled = false; @@ -57,7 +53,7 @@ export class PickerColumnOption implements ComponentInterface { const { value, disabled, ariaLabel } = this; return ( - +