Skip to content

Commit 36b17fe

Browse files
fix(item): allow nested content to be conditionally interactive
1 parent 55017a3 commit 36b17fe

File tree

1 file changed

+43
-4
lines changed

1 file changed

+43
-4
lines changed

core/src/components/item/item.tsx

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
3232
private labelColorStyles = {};
3333
private itemStyles = new Map<string, CssClassMap>();
3434
private inheritedAriaAttributes: Attributes = {};
35+
private observer?: MutationObserver;
3536

3637
@Element() el!: HTMLIonItemElement;
3738

3839
@State() multipleInputs = false;
3940
@State() focusable = true;
41+
@State() isInteractive = false;
4042

4143
/**
4244
* The color to use from your application's color palette.
@@ -163,6 +165,19 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
163165

164166
connectedCallback() {
165167
this.hasStartEl();
168+
169+
// create MutationObserver to watch for changes in nested content
170+
// and update state to reflect change in behavior and rerender
171+
if (typeof MutationObserver !== 'undefined' && !this.observer) {
172+
this.observer = new MutationObserver(() => {
173+
this.setIsInteractive();
174+
this.setMultipleInputs();
175+
});
176+
177+
this.observer.observe(this.el, {
178+
childList: true,
179+
});
180+
}
166181
}
167182

168183
componentWillLoad() {
@@ -176,10 +191,14 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
176191
});
177192
}
178193

179-
// If the item contains multiple clickable elements and/or inputs, then the item
180-
// should not have a clickable input cover over the entire item to prevent
181-
// interfering with their individual click events
182-
private setMultipleInputs() {
194+
disconnectedCallback(): void {
195+
// disconnect MutationObserver when component is disconnected from the DOM
196+
if (this.observer) {
197+
this.observer.disconnect();
198+
}
199+
}
200+
201+
private totalNestedInputs() {
183202
// The following elements have a clickable cover that is relative to the entire item
184203
const covers = this.el.querySelectorAll('ion-checkbox, ion-datetime, ion-select, ion-radio');
185204

@@ -193,6 +212,19 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
193212
// The following elements should also stay clickable when an input with cover is present
194213
const clickables = this.el.querySelectorAll('ion-router-link, ion-button, a, button');
195214

215+
return {
216+
covers,
217+
inputs,
218+
clickables,
219+
};
220+
}
221+
222+
// If the item contains multiple clickable elements and/or inputs, then the item
223+
// should not have a clickable input cover over the entire item to prevent
224+
// interfering with their individual click events
225+
private setMultipleInputs() {
226+
const { covers, inputs, clickables } = this.totalNestedInputs();
227+
196228
// Check for multiple inputs to change the position of the input cover to relative
197229
// for all of the covered inputs above
198230
this.multipleInputs =
@@ -201,6 +233,13 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
201233
(covers.length > 0 && this.isClickable());
202234
}
203235

236+
private setIsInteractive() {
237+
// If item contains any interactive children, set isInteractive to `true`
238+
const { covers, inputs, clickables } = this.totalNestedInputs();
239+
240+
this.isInteractive = !!(covers.length + inputs.length + clickables.length);
241+
}
242+
204243
// If the item contains an input including a checkbox, datetime, select, or radio
205244
// then the item will have a clickable input cover that covers the item
206245
// that should get the hover, focused and activated states UNLESS it has multiple

0 commit comments

Comments
 (0)