"use client";
import { type HTMLAttributes, type ReactElement, type Ref } from "react";
import { type ComponentWithRippleProps } from "../interaction/types.js";
import { useElementInteraction } from "../interaction/useElementInteraction.js";
import { useHigherContrastChildren } from "../interaction/useHigherContrastChildren.js";
import { ListItemChildren } from "./ListItemChildren.js";
import { getListItemHeight } from "./getListItemHeight.js";
import {
type BaseListItemClassNameOptions,
listItem,
} from "./listItemStyles.js";
import { type ListItemChildrenProps } from "./types.js";
/**
* @since 6.0.0 Renamed `threeLines` to `multiline` since it can
* support more than three lines of text.
* @since 6.3.1 Extends the BaseListItemClassNameOptions
*/
export interface ListItemProps
extends
HTMLAttributes,
ListItemChildrenProps,
BaseListItemClassNameOptions,
ComponentWithRippleProps {
ref?: Ref;
/**
* @defaultValue `"button"`
*/
role?: HTMLAttributes["role"];
/**
* @defaultValue `disabled ? -1 : 0`
*/
tabIndex?: number;
/**
* Set this to `false` if the list item should not gain the interaction
* states: hover, focus, press, etc. This is kind of like being disabled
* without the disabled styles being applied.
*
* @defaultValue `role === "presentation"`
*/
presentational?: boolean;
}
/**
* **Client Component**
*
* The `ListItem` is used to create a clickable/focusable button within a
* `List` and removes the normal `` styles.
*
* @example Simple Example
* ```tsx
* import { List } from "@react-md/core/list/List";
* import { ListItem } from "@react-md/core/list/ListItem";
* import type { ReactElement } from "react";
*
* function Example(): ReactElement {
* return (
*
* {
* // do something
* }}
* >
* Item 1
*
* {
* // do something
* }}
* secondaryText={Some additional content.}
* >
* Item 2
*
*
* );
* );
* }
* ```
*
* @example Applying Addons Example
* ```tsx
* import { List } from "@react-md/core/list/List";
* import { ListItem } from "@react-md/core/list/ListItem";
* import FavoriteIcon from "@react-md/material-icons/FavoriteIcon";
* import type { ReactElement } from "react";
*
* function Example(): ReactElement {
* return (
*
* }>
* Item 1
*
* }>
* Item 2
*
* }
* rightAddon={
}
* rightAddonType="media"
* >
* Item 3
*
*
* );
* );
* }
* ```
*
* @see {@link https://react-md.dev/components/list | List Demos}
*/
export function ListItem(props: ListItemProps): ReactElement {
const {
ref,
className,
textProps,
textClassName,
secondaryTextClassName,
primaryText,
secondaryText,
secondaryTextProps,
disableTextChildren = false,
height: propHeight,
leftAddon,
leftAddonType,
leftAddonPosition,
leftAddonClassName,
leftAddonForceWrap,
rightAddon,
rightAddonType,
rightAddonPosition,
rightAddonClassName,
rightAddonForceWrap,
disableLeftAddonSpacing,
disableLeftAddonCenteredMedia,
disableRightAddonCenteredMedia,
multiline = false,
disabled = false,
disableRipple,
disabledOpacity = false,
role = "button",
onBlur,
onClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseUp,
onMouseLeave,
onDragStart,
onTouchStart,
onTouchEnd,
onTouchMove,
tabIndex: propTabIndex,
children: propChildren,
presentational = role === "presentation",
...remaining
} = props;
let tabIndex = propTabIndex;
if (!presentational && tabIndex === undefined) {
tabIndex = disabled ? -1 : 0;
}
const { pressedClassName, ripples, handlers } = useElementInteraction({
mode: disableRipple ? "none" : undefined,
onBlur,
onClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseUp,
onMouseLeave,
onDragStart,
onTouchStart,
onTouchEnd,
onTouchMove,
disabled: disabled || presentational,
});
const children = useHigherContrastChildren(
propChildren,
!disableTextChildren
);
const height = getListItemHeight({
height: propHeight,
leftAddon,
leftAddonType,
rightAddon,
rightAddonType,
secondaryText,
});
return (
{children}
{ripples}
);
}