Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiSelectable] Add configurable truncation #7388

Merged
merged 11 commits into from
Nov 29, 2023
2 changes: 2 additions & 0 deletions changelogs/upcoming/7388.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `EuiSelectable` now allows configurable text truncation via `listProps.truncationProps`
- `EuiTextTruncate` now supports a new `calculationDelayMs` prop for working around font loading or layout shifting scenarios
2 changes: 1 addition & 1 deletion src-docs/src/views/combo_box/combo_box_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ export const ComboBoxExample = {
By default, <strong>EuiComboBox</strong> truncates long option text at
the end of the string. You can use <EuiCode>truncationProps</EuiCode>{' '}
and almost any prop that{' '}
<Link to="/utilities/text-truncate">
<Link to="/utilities/text-truncation">
<strong>EuiTextTruncate</strong>
</Link>{' '}
accepts to configure this behavior. This can be configured at the{' '}
Expand Down
51 changes: 51 additions & 0 deletions src-docs/src/views/selectable/selectable_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
EuiSelectable,
EuiSelectableMessage,
EuiText,
EuiTextTruncate,
EuiCallOut,
EuiLink,
} from '../../../../src';
Expand Down Expand Up @@ -38,6 +39,9 @@ const selectableMessagesSource = require('!!raw-loader!./selectable_messages');
import SelectableSizing from './selectable_sizing';
const selectableSizingSource = require('!!raw-loader!./selectable_sizing');

import Truncation from './selectable_truncation';
const truncationSource = require('!!raw-loader!./selectable_truncation');

import SelectableCustomRender from './selectable_custom_render';
const selectableCustomRenderSource = require('!!raw-loader!./selectable_custom_render');

Expand Down Expand Up @@ -385,6 +389,53 @@ export const SelectableExample = {
{list => list}
</EuiSelectable>`,
},
{
title: 'Truncation',
source: [
{
type: GuideSectionTypes.TSX,
code: truncationSource,
},
],
text: (
<>
<p>
<strong>EuiSelectable</strong> defaults to{' '}
<EuiCode>listProps.textWrap="truncate"</EuiCode>, which truncates
long option text at the end of the string.
</p>
<p>
You can use <EuiCode>listProps.truncationProps</EuiCode> and almost
any prop that{' '}
<Link to="/utilities/text-truncation">
<strong>EuiTextTruncate</strong>
</Link>{' '}
accepts to configure this behavior. This can be configured at the{' '}
<strong>EuiSelectable</strong> level, as well as by each individual
option.
</p>
</>
),
props: {
EuiSelectableOptionsList,
EuiSelectableOptionProps,
EuiTextTruncate,
},
snippet: `<EuiSelectable
options={[]}
onChange={newOptions => setOptions(newOptions)}
listProps={{
textWrap: 'truncate',
truncationProps: {
truncation: 'start',
truncationOffset: 5,
},
}}
>
{list => list}
</EuiSelectable>`,
demo: <Truncation />,
},
{
title: 'Rendering the options',
source: [
Expand Down
153 changes: 153 additions & 0 deletions src-docs/src/views/selectable/selectable_truncation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React, { useState } from 'react';

import {
useGeneratedHtmlId,
EuiFlexGroup,
EuiFlexItem,
EuiButtonGroup,
EuiFieldNumber,
EuiTextTruncationTypes,
EuiTitle,
EuiSpacer,
EuiSelectable,
EuiSelectableOptionsListProps,
EuiSelectableOption,
EuiPanel,
EuiIcon,
EuiText,
} from '../../../../src';

export default () => {
const [options, setOptions] = useState<EuiSelectableOption[]>([
{
label:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, lorem ispum',
checked: 'on',
},
{
label:
'Phasellus enim turpis, molestie ut nisi ut, suscipit tristique libero',
},
{
label: 'Ut sagittis interdum nisi, pellentesque laoreet arcu blandit a',
},
{
label: 'Fusce sed viverra nisl',
},
{
label: 'Donec maximus est justo, eget semper lorem lacinia nec',
},
{
label: 'Vestibulum lobortis ipsum sit amet tellus scelerisque vestibulum',
},
{
prepend: <EuiIcon type="alert" color="warning" aria-label="Note!" />,
label:
'This option has `textWrap` and `truncationProps` settings that will override the parent',
textWrap: 'truncate',
truncationProps: {
truncation: 'start',
truncationOffset: 5,
},
},
]);

type TextWrap = NonNullable<EuiSelectableOptionsListProps['textWrap']>;
const [textWrap, setTextWrap] = useState<TextWrap>('truncate');
const [truncation, setTruncation] = useState<EuiTextTruncationTypes>('end');
const [truncationOffset, setTruncationOffset] = useState(0);
const offsetId = useGeneratedHtmlId();

return (
<>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h3>Text wrap</h3>
</EuiTitle>
<EuiSpacer size="xs" />
<EuiButtonGroup
legend="Text wrap"
idSelected={textWrap}
onChange={(id) => setTextWrap(id as TextWrap)}
options={[
{ id: 'truncate', label: 'truncate' },
{ id: 'wrap', label: 'wrap' },
]}
color="primary"
/>
</EuiFlexItem>
{textWrap === 'wrap' && (
<EuiFlexItem grow={false} css={{ alignSelf: 'center' }}>
<EuiText color="danger" size="s">
<EuiIcon type="alert" /> Wrapping text requires disabling
virtualization. We do not recommend this for large (50+) amounts
of options.
</EuiText>
</EuiFlexItem>
)}
{textWrap === 'truncate' && (
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h3>Truncation type</h3>
</EuiTitle>
<EuiSpacer size="xs" />
<EuiButtonGroup
legend="Truncation type"
idSelected={truncation}
onChange={(id) => setTruncation(id as EuiTextTruncationTypes)}
options={[
{ id: 'start', label: 'start ' },
{ id: 'end', label: 'end' },
{ id: 'startEnd', label: 'startEnd' },
{ id: 'middle', label: 'middle' },
]}
color="primary"
/>
</EuiFlexItem>
)}
{textWrap === 'truncate' &&
(truncation === 'start' || truncation === 'end') && (
<EuiFlexItem grow={false}>
<EuiTitle size="xxs">
<h3 id={offsetId}>Truncation offset</h3>
</EuiTitle>
<EuiSpacer size="xs" />
<EuiFieldNumber
aria-labelledby={offsetId}
value={truncationOffset}
onChange={(e) => setTruncationOffset(Number(e.target.value))}
compressed
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
<EuiSpacer />
<EuiPanel
paddingSize="s"
style={{ inlineSize: 400, resize: 'horizontal', overflow: 'auto' }}
>
<EuiSelectable
searchable={true}
options={options}
onChange={(updatedOptions) => setOptions(updatedOptions)}
listProps={{
isVirtualized: textWrap !== 'wrap',
textWrap,
truncationProps: {
truncation,
truncationOffset,
},
}}
>
{(list, search) => (
<>
{search}
{list}
</>
)}
</EuiSelectable>
</EuiPanel>
</>
);
};
8 changes: 7 additions & 1 deletion src/components/auto_sizer/auto_sizer.testenv.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@
* Side Public License, v 1.
*/

import React from 'react';
import React, { useEffect } from 'react';

export const EuiAutoSizer = ({
children,
defaultHeight,
defaultWidth,
onResize,
}: any) => {
const childrenParams = {
height: defaultHeight ?? 600,
width: defaultWidth ?? 600,
};

useEffect(() => {
onResize?.(childrenParams);
}, [onResize, defaultHeight, defaultWidth]); // eslint-disable-line react-hooks/exhaustive-deps

return <div data-eui="EuiAutoSizer">{children(childrenParams)}</div>;
};
2 changes: 1 addition & 1 deletion src/components/combo_box/combo_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export interface _EuiComboBoxProps<T>
/**
* By default, EuiComboBox will truncate option labels at the end of
* the string. You can use pass in a custom truncation configuration that
* accepts any prop that [EuiTextTruncate](/#/utilities/text-truncate) prop
* accepts any [EuiTextTruncate](/#/utilities/text-truncation) prop,
* except for `text` and `children`.
*
* Note: when searching, custom truncation props are ignored. The highlighted search
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,7 @@ exports[`EuiSelectable errorMessage prop does not render the message when not de
<span
class="euiSelectableListItem__text euiSelectableListItem__text--truncate"
>
<span>
Titan
</span>
Titan
</span>
</span>
</li>
Expand All @@ -205,9 +203,7 @@ exports[`EuiSelectable errorMessage prop does not render the message when not de
<span
class="euiSelectableListItem__text euiSelectableListItem__text--truncate"
>
<span>
Enceladus
</span>
Enceladus
</span>
</span>
</li>
Expand All @@ -232,9 +228,7 @@ exports[`EuiSelectable errorMessage prop does not render the message when not de
<span
class="euiSelectableListItem__text euiSelectableListItem__text--truncate"
>
<span>
Pandora is one of Saturn's moons, named for a Titaness of Greek mythology
</span>
Pandora is one of Saturn's moons, named for a Titaness of Greek mythology
</span>
</span>
</li>
Expand Down
Loading
Loading