[MM-67456] Allow OptionItem labels to wrap to two lines (#9504)

This commit is contained in:
Guillermo Vayá 2026-02-24 18:17:04 +01:00 committed by GitHub
parent 1757654882
commit c3f83f9028
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 49 additions and 1 deletions

View file

@ -0,0 +1,33 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import OptionItem from '@components/option_item';
import {renderWithIntlAndTheme} from '@test/intl-test-helper';
import BaseOption from './index';
jest.mock('@components/option_item');
jest.mocked(OptionItem).mockImplementation((props) => React.createElement('OptionItem', props));
describe('BaseOption', () => {
it('should force single line labels', () => {
renderWithIntlAndTheme(
<BaseOption
message={{id: 'test.base_option.label', defaultMessage: 'Option label'}}
iconName='icon-name'
onPress={jest.fn()}
testID='base-option'
/>,
);
expect(jest.mocked(OptionItem)).toHaveBeenCalled();
expect(jest.mocked(OptionItem).mock.calls[0][0]).toEqual(expect.objectContaining({
label: 'Option label',
labelNumberOfLines: 1,
type: 'default',
testID: 'base-option',
}));
});
});

View file

@ -29,6 +29,7 @@ const BaseOption = ({
destructive={isDestructive} destructive={isDestructive}
icon={iconName} icon={iconName}
label={intl.formatMessage(message)} label={intl.formatMessage(message)}
labelNumberOfLines={1}
testID={testID} testID={testID}
type='default' type='default'
/> />

View file

@ -132,6 +132,7 @@ export type OptionItemProps = {
value?: string; value?: string;
onLayout?: (event: LayoutChangeEvent) => void; onLayout?: (event: LayoutChangeEvent) => void;
descriptionNumberOfLines?: number; descriptionNumberOfLines?: number;
labelNumberOfLines?: number;
longInfo?: boolean; longInfo?: boolean;
nonDestructiveDescription?: boolean; nonDestructiveDescription?: boolean;
isRadioCheckmark?: boolean; isRadioCheckmark?: boolean;
@ -155,6 +156,7 @@ const OptionItem = ({
value, value,
onLayout, onLayout,
descriptionNumberOfLines, descriptionNumberOfLines,
labelNumberOfLines = 2,
longInfo, longInfo,
nonDestructiveDescription = false, nonDestructiveDescription = false,
isRadioCheckmark = false, isRadioCheckmark = false,
@ -326,7 +328,7 @@ const OptionItem = ({
<Text <Text
style={labelTextStyle} style={labelTextStyle}
testID={`${testID}.label`} testID={`${testID}.label`}
numberOfLines={1} numberOfLines={labelNumberOfLines}
> >
{label} {label}
</Text> </Text>

View file

@ -40,6 +40,7 @@ describe('OptionItem', () => {
const label = getByText('Test Option'); const label = getByText('Test Option');
expect(label).toBeTruthy(); expect(label).toBeTruthy();
expect(label).toHaveStyle({fontWeight: '400'}); expect(label).toHaveStyle({fontWeight: '400'});
expect(label.props.numberOfLines).toBe(2);
// No description // No description
expect(queryByTestId('option-item.description')).toBeNull(); expect(queryByTestId('option-item.description')).toBeNull();
@ -65,6 +66,16 @@ describe('OptionItem', () => {
expect(queryByTestId('option-item.arrow.icon')).toBeNull(); expect(queryByTestId('option-item.arrow.icon')).toBeNull();
}); });
it('respects custom label number of lines', () => {
const props = getBaseProps();
props.labelNumberOfLines = 1;
const {getByText} = renderWithIntlAndTheme(<OptionItem {...props}/>);
const label = getByText('Test Option');
expect(label.props.numberOfLines).toBe(1);
});
it('renders with description when provided', () => { it('renders with description when provided', () => {
const props = getBaseProps(); const props = getBaseProps();
props.description = 'Test description'; props.description = 'Test description';

View file

@ -77,6 +77,7 @@ const BindingOptionItem = ({binding, onPress}: {binding: AppBinding; onPress: (b
return ( return (
<OptionItem <OptionItem
label={binding.label || ''} label={binding.label || ''}
labelNumberOfLines={1}
icon={binding.icon} icon={binding.icon}
action={handlePress} action={handlePress}
type='default' type='default'