import React, { type ReactNode } from 'react' // Noting that this is contingent on our displayName for our components - this something we control const allowedDisplayNames = ['Button', 'IconButton', 'FilterButtonBase'] export function extractDisplayName(type: React.FunctionComponent): string { return type.displayName ?? type.name ?? 'Unknown' } /** * Validates implicit or explicitly semantic roles required to make `aria-describedby` announce predictably with screen readers */ export const isSemanticElement = (element: ReactNode): element is React.ReactElement => { if (!React.isValidElement(element)) return false const { props, type } = element if ('role' in props) { return props.role !== 'presentation' && props.role !== 'none' } if (typeof type !== 'string') { // As we are only checking whether this matches to our allowedDisplayNames // type casting should be fine const displayName = extractDisplayName(type as unknown as React.FunctionComponent) return allowedDisplayNames.includes(displayName) } return !(type === 'div' || type === 'span') }