import { ListIterator, type RaRecord, sanitizeListRestProps, useGetRecordRepresentation, useListContextWithProps, useRecordContext, useResourceContext, useTranslate, } from "ra-core"; import { isValidElement, type ReactElement } from "react"; import { ListNoResults } from "./ListNoResults.tsx"; import type { FunctionToElement } from "./SimpleListItem.tsx"; import { type SimpleListBaseProps, SimpleListItem, type SimpleListItemProps, } from "./SimpleListItem.tsx"; import { SimpleListLoading } from "./SimpleListLoading.tsx"; /** * The component renders a list of records * It is usually used as a child of shadcn-admin-kit's and components. * * Also widely used on Mobile. * * Props: * - primaryText: function returning a React element (or some text) based on the record * - secondaryText: same * - tertiaryText: same * - leftAvatar: function returning a React element based on the record * - leftIcon: same * - rightAvatar: same * - rightIcon: same * - linkType: deprecated - 'edit' or 'show', or a function returning 'edit' or 'show' based on the record * - rowClick: The action to trigger when the user clicks on a row. * - rowStyle: function returning a style object based on (record, index) * - rowSx: function returning a sx object based on (record, index) * * @example // Display all posts as a List * const postRowSx = (record, index) => ({ * backgroundColor: record.views >= 500 ? '#efe' : 'white', * }); * export const PostList = () => ( * * record.title} * secondaryText={record => `${record.views} views`} * tertiaryText={record => * new Date(record.published_at).toLocaleDateString() * } * rowSx={postRowSx} * /> * * ); */ export const SimpleList = ( props: SimpleListProps, ) => { const { className, empty = DefaultEmpty, leftAvatar, leftIcon, linkType, rowClick, primaryText, rightAvatar, rightIcon, secondaryText, tertiaryText, resource, ...rest } = props; const { data, isPending, total } = useListContextWithProps(props); if (isPending === true) { return ( ); } if (data == null || data.length === 0 || total === 0) { if (empty) { return empty; } return null; } return (
    data={data} total={total} render={(record, rowIndex) => ( )} />
); }; export interface SimpleListProps extends SimpleListBaseProps { className?: string; empty?: ReactElement; // can be injected when using the component without context resource?: string; data?: RecordType[]; isLoading?: boolean; isPending?: boolean; isLoaded?: boolean; total?: number; } const SimpleListItemContent = ( props: SimpleListItemProps, ) => { const { leftAvatar, leftIcon, primaryText, rightAvatar, rightIcon, secondaryText, tertiaryText, } = props; const resource = useResourceContext(props); const record = useRecordContext(props); const getRecordRepresentation = useGetRecordRepresentation(resource); const translate = useTranslate(); const renderAvatar = ( record: RecordType, avatarCallback: FunctionToElement, ) => { const avatarValue = avatarCallback(record, record.id); if ( typeof avatarValue === "string" && (avatarValue.startsWith("http") || avatarValue.startsWith("data:")) ) { return ( ); } else { return (
{avatarValue}
); } }; if (!record) return null; return (
{leftIcon && (
{leftIcon(record, record.id)}
)} {leftAvatar && (
{renderAvatar(record, leftAvatar)}
)}
{primaryText ? typeof primaryText === "string" ? translate(primaryText, { ...record, _: primaryText, }) : isValidElement(primaryText) ? primaryText : primaryText(record, record.id) : getRecordRepresentation(record)}
{!!tertiaryText && (
{typeof tertiaryText === "string" ? translate(tertiaryText, { ...record, _: tertiaryText, }) : isValidElement(tertiaryText) ? tertiaryText : tertiaryText(record, record.id)}
)}
{!!secondaryText && (
{typeof secondaryText === "string" ? translate(secondaryText, { ...record, _: secondaryText, }) : isValidElement(secondaryText) ? secondaryText : secondaryText(record, record.id)}
)}
{(rightAvatar || rightIcon) && (
{rightAvatar && renderAvatar(record, rightAvatar)} {rightIcon && rightIcon(record, record.id)}
)}
); }; const DefaultEmpty = ;