From 548015d86c77f0fa0cca880e84fc9634a0bc993f Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 6 Sep 2023 16:19:07 -0400 Subject: [PATCH 01/13] fix(item): click first interactive control within item --- core/src/components/item/item.tsx | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/core/src/components/item/item.tsx b/core/src/components/item/item.tsx index 6e2d48186da..8612b532850 100644 --- a/core/src/components/item/item.tsx +++ b/core/src/components/item/item.tsx @@ -350,6 +350,11 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac } } + private getFirstInteractive() { + const controls = this.el.querySelectorAll('ion-toggle, ion-checkbox, ion-radio'); + return controls[0]; + } + render() { const { counterString, @@ -367,6 +372,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac routerAnimation, routerDirection, inheritedAriaAttributes, + multipleInputs, } = this; const childStyles = {} as StyleEventDetail; const mode = getIonMode(this); @@ -383,15 +389,26 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac rel, target, }; + + let clickFn = {}; + + const firstInteractive = this.getFirstInteractive(); + // Only set onClick if the item is clickable to prevent screen // readers from reading all items as clickable - const clickFn = clickable - ? { - onClick: (ev: Event) => { + if (clickable || (firstInteractive !== undefined && !multipleInputs)) { + clickFn = { + onClick: (ev: Event) => { + if (clickable) { openURL(href, ev, routerDirection, routerAnimation); - }, - } - : {}; + } + if (firstInteractive !== undefined && !multipleInputs) { + firstInteractive.click(); + } + }, + }; + } + const showDetail = detail !== undefined ? detail : mode === 'ios' && clickable; this.itemStyles.forEach((value) => { Object.assign(childStyles, value); From 5eb1917965439e628b6226283b6339b565e9b24d Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 6 Sep 2023 16:50:54 -0400 Subject: [PATCH 02/13] fix(checkbox): clicking padded space within item clicks the checkbox --- core/src/components/checkbox/checkbox.tsx | 23 +++++++++++++++++-- .../checkbox/test/basic/checkbox.e2e.ts | 22 ++++++++++++++++++ .../test/legacy/basic/checkbox.e2e.ts | 22 ++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx index 08cfc581ff5..b47fa5dd229 100644 --- a/core/src/components/checkbox/checkbox.tsx +++ b/core/src/components/checkbox/checkbox.tsx @@ -31,6 +31,7 @@ import type { CheckboxChangeEventDetail } from './checkbox-interface'; export class Checkbox implements ComponentInterface { private inputId = `ion-cb-${checkboxIds++}`; private focusEl?: HTMLElement; + private labelEl?: HTMLLabelElement; private legacyFormController!: LegacyFormController; // TODO(FW-3100): remove this private inheritedAttributes: Attributes = {}; @@ -203,6 +204,20 @@ export class Checkbox implements ComponentInterface { this.ionBlur.emit(); }; + private onClick = (ev: MouseEvent) => { + const path = ev.composedPath(); + const { labelEl } = this; + + if (labelEl) { + // Prevents the parent ion-item click listener from firing twice. + ev.stopPropagation(); + if (path.includes(labelEl)) { + return; + } + this.toggleChecked(ev); + } + }; + // TODO(FW-3100): run contents of renderCheckbox directly instead render() { const { legacyFormController } = this; @@ -242,8 +257,9 @@ export class Checkbox implements ComponentInterface { [`checkbox-justify-${justify}`]: true, [`checkbox-label-placement-${labelPlacement}`]: true, })} + onClick={this.onClick} > -