import React, { ReactElement } from 'react'; import isObject from 'lodash/isObject'; import isUndefined from 'lodash/isUndefined'; import { consoleOnce } from '.'; /** Helper type to check if element is a specific React Component */ export function isComponentType< T extends React.ReactElement = React.ReactElement, >(element: React.ReactNode, displayName: string): element is T { return ( element != null && typeof element === 'object' && 'type' in element && ((element.type as any).displayName === displayName || // TODO: temp solution; Components using InferredPolymorphic have a displayName inside render. // https://jira.mongodb.org/browse/LG-3232 (isObject(element.type as any) && 'render' in (element.type as any) && (element.type as any).render?.displayName === displayName)) ); } /** * Filters children down to a restricted set of component types. * * Example: * ```ts * // `options` will only include `ComboboxOption` components, * // and log an error to the console for any invalid children * const options = validateChildren(children, ['ComboboxOption']) * ``` * * @returns Array */ export const validateChildren = ( /** Any React children */ children: React.ReactNode, /** Array of `displayNames` for valid components */ validTypes: Array, ): Array | undefined => { const validChildren = React.Children.map(children, child => { if (validTypes.some(type => isComponentType(child, type))) { return child as React.ReactElement; } })?.filter(child => !isUndefined(child)); if ( !isUndefined(children) && validChildren?.length !== React.Children.count(children) ) { consoleOnce.error( `Children must be one of: ${validTypes.join(', ')}`, `Received children: `, children, ); } return validChildren; };