diff --git a/src/__testing__/ListItemText.test.tsx b/src/__testing__/ListItemText.test.tsx
new file mode 100644
index 000000000..e26d8ce70
--- /dev/null
+++ b/src/__testing__/ListItemText.test.tsx
@@ -0,0 +1,197 @@
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { ListItemText } from '../base/ListItemText';
+
+describe('ListItemText', () => {
+ describe('default truncation behavior', () => {
+ it('applies noWrap by default to primary text', () => {
+ render();
+ const primaryElement = screen.getByText('Truncated Primary');
+ expect(primaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ });
+
+ it('applies noWrap by default to secondary text', () => {
+ render();
+ const secondaryElement = screen.getByText('Truncated Secondary');
+ expect(secondaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ });
+ });
+
+ describe('object-valued slotProps', () => {
+ it('preserves custom slotProps on primary while keeping noWrap by default', () => {
+ render(
+
+ }}
+ />
+ );
+ const primaryElement = screen.getByTestId('custom-primary');
+ expect(primaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ expect(primaryElement.classList.contains('custom-class')).toBe(true);
+ });
+
+ it('preserves custom slotProps on secondary while keeping noWrap by default', () => {
+ render(
+
+ }}
+ />
+ );
+ const secondaryElement = screen.getByTestId('custom-secondary');
+ expect(secondaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ expect(secondaryElement.classList.contains('custom-class-secondary')).toBe(true);
+ });
+
+ it('allows consumer to explicitly override noWrap to false on primary', () => {
+ render(
+
+ );
+ const primaryElement = screen.getByTestId('multiline-primary');
+ expect(primaryElement.classList.contains('MuiTypography-noWrap')).toBe(false);
+ });
+
+ it('allows consumer to explicitly override noWrap to false on secondary', () => {
+ render(
+
+ );
+ const secondaryElement = screen.getByTestId('multiline-secondary');
+ expect(secondaryElement.classList.contains('MuiTypography-noWrap')).toBe(false);
+ });
+ });
+
+ describe('function-valued slotProps', () => {
+ it('executes primary slot callback with ownerState and retains noWrap by default', () => {
+ const primaryFn = jest.fn((ownerState) => ({
+ 'data-testid': 'callback-primary',
+ className: ownerState.inset ? 'is-inset' : 'not-inset'
+ }));
+
+ render(
+
+ );
+
+ expect(primaryFn).toHaveBeenCalled();
+ const ownerStateArg = primaryFn.mock.calls[0][0];
+ expect(ownerStateArg.inset).toBe(true);
+
+ const primaryElement = screen.getByTestId('callback-primary');
+ expect(primaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ expect(primaryElement.classList.contains('is-inset')).toBe(true);
+ });
+
+ it('executes secondary slot callback with ownerState and retains noWrap by default', () => {
+ const secondaryFn = jest.fn(() => ({
+ 'data-testid': 'callback-secondary',
+ className: 'dynamic-secondary'
+ }));
+
+ render(
+
+ );
+
+ expect(secondaryFn).toHaveBeenCalled();
+ const secondaryElement = screen.getByTestId('callback-secondary');
+ expect(secondaryElement.classList.contains('MuiTypography-noWrap')).toBe(true);
+ expect(secondaryElement.classList.contains('dynamic-secondary')).toBe(true);
+ });
+
+ it('allows function callback to explicitly override noWrap to false on primary', () => {
+ render(
+ ({
+ noWrap: false,
+ 'data-testid': 'multiline-fn-primary'
+ })
+ }}
+ />
+ );
+ const primaryElement = screen.getByTestId('multiline-fn-primary');
+ expect(primaryElement.classList.contains('MuiTypography-noWrap')).toBe(false);
+ });
+
+ it('allows function callback to explicitly override noWrap to false on secondary', () => {
+ render(
+ ({
+ noWrap: false,
+ 'data-testid': 'multiline-fn-secondary'
+ })
+ }}
+ />
+ );
+ const secondaryElement = screen.getByTestId('multiline-fn-secondary');
+ expect(secondaryElement.classList.contains('MuiTypography-noWrap')).toBe(false);
+ });
+ });
+
+ describe('preservation of root slot and other props', () => {
+ it('preserves root slotProps', () => {
+ render(
+
+ }}
+ />
+ );
+ const rootElement = screen.getByTestId('custom-root-slot');
+ expect(rootElement.classList.contains('custom-root-class')).toBe(true);
+ });
+
+ it('forwards top-level props to root element', () => {
+ render(
+
+ );
+ const rootElement = screen.getByTestId('top-level-root');
+ expect(rootElement.classList.contains('top-level-class')).toBe(true);
+ });
+ });
+});
diff --git a/src/base/ListItemText/ListItemText.tsx b/src/base/ListItemText/ListItemText.tsx
index 158ef40d7..aa5e88d88 100644
--- a/src/base/ListItemText/ListItemText.tsx
+++ b/src/base/ListItemText/ListItemText.tsx
@@ -2,7 +2,34 @@ import {
ListItemText as MuiListItemText,
ListItemTextProps as MuiListItemTextProps
} from '@mui/material';
+import type { ListItemTextOwnerState } from '@mui/material/ListItemText';
-export function ListItemText(props: MuiListItemTextProps): JSX.Element {
- return ;
+function withNoWrapDefault(
+ slotProp: T | ((ownerState: ListItemTextOwnerState) => T) | undefined
+): T | ((ownerState: ListItemTextOwnerState) => T) {
+ if (typeof slotProp === 'function') {
+ return (ownerState: ListItemTextOwnerState) => ({
+ noWrap: true,
+ ...slotProp(ownerState)
+ });
+ }
+ return { noWrap: true, ...slotProp } as T;
+}
+
+export function ListItemText({
+ slotProps,
+ ...props
+}: MuiListItemTextProps): JSX.Element {
+ const { primary, secondary } = slotProps ?? {};
+
+ return (
+
+ );
}