diff --git a/src/components/common/mixins/combo-box.ts b/src/components/common/mixins/combo-box.ts index 31f32143f..cb05725d3 100644 --- a/src/components/common/mixins/combo-box.ts +++ b/src/components/common/mixins/combo-box.ts @@ -115,18 +115,20 @@ export abstract class IgcBaseComboBoxLikeComponent extends LitElement { } export function getItems(root: Node, tagName: string) { - return iterNodes(root, 'SHOW_ELEMENT', (item) => item.matches(tagName)); + return iterNodes(root, { + show: 'SHOW_ELEMENT', + filter: (item) => item.matches(tagName), + }); } export function getActiveItems( root: Node, tagName: string ) { - return iterNodes( - root, - 'SHOW_ELEMENT', - (item) => item.matches(tagName) && !item.disabled - ); + return iterNodes(root, { + show: 'SHOW_ELEMENT', + filter: (item) => item.matches(tagName) && !item.disabled, + }); } export function getNextActiveItem< diff --git a/src/components/common/util.ts b/src/components/common/util.ts index b4f157cf6..22b16d593 100644 --- a/src/components/common/util.ts +++ b/src/components/common/util.ts @@ -100,36 +100,40 @@ export function isDefined(value: T) { return value !== undefined; } -export function* iterNodes( +export type IterNodesOptions = { + show?: keyof typeof NodeFilter; + filter?: (node: T) => boolean; +}; + +function createNodeFilter(predicate: (node: T) => boolean) { + return { + acceptNode: (node: T): number => + !predicate || predicate(node) + ? NodeFilter.FILTER_ACCEPT + : NodeFilter.FILTER_SKIP, + }; +} + +export function* iterNodes( root: Node, - whatToShow?: keyof typeof NodeFilter, - filter?: (node: T) => boolean + options?: IterNodesOptions ): Generator { if (!isDefined(globalThis.document)) { return; } - const iter = globalThis.document.createTreeWalker( - root, - NodeFilter[whatToShow ?? 'SHOW_ALL'] - ); - - let node = iter.nextNode() as T; + const whatToShow = options?.show + ? NodeFilter[options.show] + : NodeFilter.SHOW_ALL; - while (node) { - if (filter) { - if (filter(node)) { - yield node; - } - } else { - yield node; - } + const nodeFilter = options?.filter + ? createNodeFilter(options.filter) + : undefined; - if (isElement(node) && node.shadowRoot && node.shadowRoot.mode === 'open') { - yield* iterNodes(node.shadowRoot, whatToShow, filter); - } + const treeWalker = document.createTreeWalker(root, whatToShow, nodeFilter); - node = iter.nextNode() as T; + while (treeWalker.nextNode()) { + yield treeWalker.currentNode as T; } } diff --git a/src/components/radio/utils.ts b/src/components/radio/utils.ts index 921af4a8b..5dadf4eb7 100644 --- a/src/components/radio/utils.ts +++ b/src/components/radio/utils.ts @@ -1,4 +1,4 @@ -import { iterNodes } from '../common/util.js'; +import { type IterNodesOptions, getRoot, iterNodes } from '../common/util.js'; import type IgcRadioComponent from './radio.js'; type RadioQueryResult = { @@ -36,13 +36,13 @@ export function getGroup(member: IgcRadioComponent) { return result; } - const iterator = iterNodes( - globalThis.document.documentElement, - 'SHOW_ELEMENT', - (radio) => radio.matches(member.tagName) && radio.name === member.name - ); + const options: IterNodesOptions = { + show: 'SHOW_ELEMENT', + filter: (radio) => + radio.matches(member.tagName) && radio.name === member.name, + }; - for (const each of iterator) { + for (const each of iterNodes(getRoot(member), options)) { result.radios.push(each); if (!each.disabled) {