import React from 'react'; import type { TreeItemContentRenderProps } from 'react-aria-components'; import type { Collection as CollectionInterface, Node } from 'react-stately'; import classNames from 'classnames'; import { Text as CoreText } from '@shoptet/ui-core-web'; import type { SafeOmit } from '@shoptet/utils'; import { type ScreenSize } from '../../../hooks/useScreenSize'; import { getTypographyProps } from '../../Typography/getTypographyProps'; import type { TreeItemKey } from '../useTreeState'; import { TreeItemCheckbox } from './TreeItemCheckbox'; import { TreeItemChevron } from './TreeItemChevron'; import { TreeItemHandle } from './TreeItemHandle'; export interface TreeItemState extends TreeItemContentRenderProps {} export interface TreeItemRenderProps { /** The state of the tree item. */ state: TreeItemState; /** The unique key/value for the tree item. */ value: V; /** The original item data object. */ item: T; /** The text label to display for the item. */ label: string; /** Optional text description to display for the item. */ description?: string; /** Whether the item is currently loading its children. */ loading?: boolean; /** The current screen size. */ screenSize?: ScreenSize; /** Display checkbox error state. */ error?: boolean; /** Display checkbox warning state. */ warning?: boolean; } export interface TreeItemProps extends SafeOmit< TreeItemRenderProps, 'item' > { /** Optional action buttons or elements to display for the item. */ actions?: React.ReactNode; } export function TreeItem({ state: { selectionMode, level, isExpanded, hasChildItems, allowsDragging, isSelected, state }, label, description, loading, actions, value, screenSize, error, warning, ..._rest }: TreeItemProps) { const isSelectable = selectionMode !== 'none'; const isIndeterminate = isSelectable && !isSelected && hasChildItems && collectNestedValues(value, state.collection).some(key => state.selectionManager.isSelected(key)); return ( <> {allowsDragging && }
{hasChildItems ? ( ) : (
)} {isSelectable && ( )} {label} {description ? ( ({description}) ) : null} {actions && (
event.stopPropagation()} onPointerDown={event => event.stopPropagation()} onKeyDown={event => event.stopPropagation()} > {actions}
)} ); } function collectNestedValues(value: V, collection: CollectionInterface>): V[] { const values: V[] = []; const children = [...(collection.getChildren?.(value) ?? [])].filter(c => c.type === 'item'); for (const child of children) { const childValue = child.key as V; const nestedValues = collectNestedValues(childValue, collection); values.push(childValue, ...nestedValues); } return values; }