import { useAddItem, useErrorCount, useRemoveItem } from '@/components/ra-forms/LongForm/Provider'; import { useIsActive } from '@/components/ra-forms/LongForm/hooks'; import { IItem } from '@/components/ra-forms/LongForm/types'; import { getId } from '@/components/ra-forms/LongForm/utils'; import { Optional } from '@/types'; import { walkChildren } from '@/utils'; import { Box } from '@mui/material'; import _ from 'lodash'; import React, { Children, cloneElement, isValidElement, useEffect, useMemo } from 'react'; import { useFormState } from 'react-hook-form'; type IBaseItemProps = React.PropsWithChildren & { sources: Array }>; type ITabProps = IBaseItemProps; type IGroupProps = IBaseItemProps; function BaseItem(props: IBaseItemProps) { const { errors } = useFormState(); const countErrors = useErrorCount(); const { label, icon, badge, index = 0, children } = props; const id = getId(props); const addItem = useAddItem(); const removeItem = useRemoveItem(); const visible = useIsActive(id); const sources: Array = []; if (countErrors) { if (props.sources !== undefined) { sources.push(...props.sources); } else { walkChildren(children, (el) => { if (el?.props?.source !== undefined) { sources.push(el.props.source); } }); } } const errorsCount = _.chain(sources) .uniq() .map((s) => _.get(errors, s)) .reject((s) => s === undefined) .value().length; useEffect(() => { addItem({ id: id, index: index, label: label, icon: icon, badge: badge, errors: errorsCount }); }, [addItem, removeItem, label, icon, id, badge, index, errorsCount]); useEffect(() => { return () => { removeItem(id); }; }, [id, removeItem]); /* All tabs are rendered (not only the one in focus), to allow validation on tabs not in focus. The tabs receive a `hidden` property, which they'll use to hide the tab using CSS if it's not the one in focus. See https://github.com/marmelab/react-admin/issues/1866 */ return {props.children}; } function Group(props: IGroupProps) { const filteredChildren = useBaseItemChildren(props); const groupId = getId(props); return ( {Children.map(filteredChildren, (Child) => { const childId = getId(Child.props); return cloneElement(Child, { id: `${groupId}.${childId}` }); })} ); } function Tab(props: ITabProps) { return ; } function useBaseItemChildren(props: React.PropsWithChildren): Array> { const { children } = props; const result = useMemo>>( () => //@ts-ignore _.chain(Children.toArray(children)) .filter((Child) => isValidElement(Child) && (Child?.type === Tab || Child?.type === Group)) .map((Child: React.FunctionComponentElement, index) => cloneElement(Child, { index: index })) .value(), [children] ); return result; } export { Group, Tab, useBaseItemChildren };