From 787013131cbd4c180207ccfefdd84a1bb47658bc Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 6 Jan 2022 11:16:10 -0600 Subject: [PATCH 1/7] isVirtualized and labelProps --- .../__snapshots__/selectable.test.tsx.snap | 102 +++++++++++ src/components/selectable/selectable.test.tsx | 43 +++++ .../selectable_list.test.tsx.snap | 165 ++++++++++++++++++ .../selectable_list/selectable_list.test.tsx | 12 ++ .../selectable_list/selectable_list.tsx | 77 +++++--- .../selectable/selectable_option.tsx | 5 + 6 files changed, 383 insertions(+), 21 deletions(-) diff --git a/src/components/selectable/__snapshots__/selectable.test.tsx.snap b/src/components/selectable/__snapshots__/selectable.test.tsx.snap index 35ce39017b3..cc156de75be 100644 --- a/src/components/selectable/__snapshots__/selectable.test.tsx.snap +++ b/src/components/selectable/__snapshots__/selectable.test.tsx.snap @@ -1,5 +1,107 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`EuiSelectable custom options with labelProps 1`] = ` +
+
+
+
+
    +
  • + + + + + Titan: VI + + + +
  • +
  • + + + + + Enceladus: II + + + +
  • +
  • + + + + + Pandora is one of Saturn's moons, named for a Titaness of Greek mythology: XVII + + + +
  • +
+
+
+
+
+`; + exports[`EuiSelectable is rendered 1`] = `
{ (component.find('EuiSelectableList').props() as any).visibleOptions ).toEqual(options); }); + + test('with labelProps', () => { + type WithLabelProps = { + numeral?: string; + }; + const options = [ + { + label: 'Titan', + labelProps: { + numeral: 'VI', + }, + }, + { + label: 'Enceladus', + labelProps: { + numeral: 'II', + }, + }, + { + label: + "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology", + labelProps: { + numeral: 'XVII', + }, + }, + ]; + const component = render( + + options={options} + renderOption={(option) => { + return ( + + {option.label}: {option.numeral} + + ); + }} + > + {(list) => list} + + ); + + expect(component).toMatchSnapshot(); + }); }); }); diff --git a/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap b/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap index 0a69ca20b06..64f6b503dff 100644 --- a/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap +++ b/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap @@ -1087,6 +1087,171 @@ exports[`EuiSelectableListItem props height is full 1`] = `
`; +exports[`EuiSelectableListItem props isVirtualized 1`] = ` +
+
+
    +
  • + + + + + Titan + + + +
  • +
  • + + + + + Enceladus + + + +
  • +
  • + + + + + Mimas + + + +
  • +
  • + + + + + Pandora is one of Saturn's moons, named for a Titaness of Greek mythology + + + +
  • +
  • + + + + + Tethys + + + +
  • +
  • + + + + + Hyperion + + + +
  • +
+
+
+`; + exports[`EuiSelectableListItem props renderOption 1`] = `
{ expect(component).toMatchSnapshot(); }); + + test('isVirtualized', () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); }); }); diff --git a/src/components/selectable/selectable_list/selectable_list.tsx b/src/components/selectable/selectable_list/selectable_list.tsx index a4cd93b029c..32387011a8b 100644 --- a/src/components/selectable/selectable_list/selectable_list.tsx +++ b/src/components/selectable/selectable_list/selectable_list.tsx @@ -61,6 +61,11 @@ export type EuiSelectableOptionsListProps = CommonProps & * The default content when `true` is `↩ to select/deselect/include/exclude` */ onFocusBadge?: EuiSelectableListItemProps['onFocusBadge']; + /** + * Use virtualized rendering for list items with `react-window`. + * Requires that each option be the same height. + */ + isVirtualized?: boolean; }; export type EuiSelectableListProps = EuiSelectableOptionsListProps & { @@ -109,6 +114,7 @@ export class EuiSelectableList extends Component> { static defaultProps = { rowHeight: 32, searchValue: '', + isVirtualized: true, }; listRef: FixedSizeList | null = null; @@ -186,6 +192,7 @@ export class EuiSelectableList extends Component> { ListRow = memo(({ data, index, style }: ListChildComponentProps) => { const option = data[index]; + const { labelProps, ..._option } = option; const { label, isGroupLabel, @@ -196,6 +203,7 @@ export class EuiSelectableList extends Component> { ref, key, searchableLabel, + labelProps: _labelProps, ...optionRest } = option; @@ -241,7 +249,11 @@ export class EuiSelectableList extends Component> { {...(optionRest as EuiSelectableListItemProps)} > {this.props.renderOption ? ( - this.props.renderOption(option, this.props.searchValue) + this.props.renderOption( + // @ts-ignore complex + { ..._option, ...labelProps }, + this.props.searchValue + ) ) : ( {label} )} @@ -273,6 +285,7 @@ export class EuiSelectableList extends Component> { 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, + isVirtualized, ...rest } = this.props; @@ -310,26 +323,48 @@ export class EuiSelectableList extends Component> { return (
- - {({ width, height }) => ( - - {this.ListRow} - - )} - + {isVirtualized ? ( + + {({ width, height }) => ( + + {this.ListRow} + + )} + + ) : ( +
+
    + {optionArray.map((_, index) => + React.createElement( + this.ListRow, + { + key: index, + data: optionArray, + index, + style: {}, + }, + null + ) + )} +
+
+ )}
); } diff --git a/src/components/selectable/selectable_option.tsx b/src/components/selectable/selectable_option.tsx index 7b4ca6bfbcb..2304160e552 100644 --- a/src/components/selectable/selectable_option.tsx +++ b/src/components/selectable/selectable_option.tsx @@ -53,6 +53,11 @@ export type EuiSelectableOptionBase = CommonProps & { * Option item `id`s are coordinated at a higher level for a11y reasons. */ id?: never; + /** + * Props to pass through to the `renderOptions` element. + * Bypass `EuiSelectableItem` and avoid DOM attribute warnings. + */ + labelProps?: { [key: string]: any }; }; type _EuiSelectableGroupLabelOption = Omit< From fa98a22460a1d417873bbf00286f178e9eba337d Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 6 Jan 2022 11:17:01 -0600 Subject: [PATCH 2/7] update docs --- .../views/selectable/selectable_custom_render.js | 5 ++++- src-docs/src/views/selectable/selectable_example.js | 13 ++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src-docs/src/views/selectable/selectable_custom_render.js b/src-docs/src/views/selectable/selectable_custom_render.js index 75e4f2050e8..6ca05463d1b 100644 --- a/src-docs/src/views/selectable/selectable_custom_render.js +++ b/src-docs/src/views/selectable/selectable_custom_render.js @@ -20,6 +20,9 @@ export default () => { prepend: country.flag, append: {country.code}, showIcons: false, + labelProps: { + secondaryContent: 'I am secondary content, I am!', + }, }; }); @@ -46,7 +49,7 @@ export default () => { - I am secondary content, I am! + {option.secondaryContent} diff --git a/src-docs/src/views/selectable/selectable_example.js b/src-docs/src/views/selectable/selectable_example.js index 9f36c676b1f..3747a417ded 100644 --- a/src-docs/src/views/selectable/selectable_example.js +++ b/src-docs/src/views/selectable/selectable_example.js @@ -356,6 +356,14 @@ export const SelectableExample = { single option object and the{' '} searchValue to use for highlighting.

+

+ To provide data that can be used by the{' '} + renderOption function that does not match the + standard option API, use option.labelProps which + will be make custom data available in the option{' '} + parameter. See the secondaryContent configuration + in the following example. +

In order for the list to know how to scroll to the selected or highlighted option, it must also know the height of the rows. It @@ -365,7 +373,10 @@ export const SelectableExample = { listProps.rowHeight.

- Every row must be the same height. + Every row must be the same height unless{' '} + listProps.isVirtualized is set to{' '} + false, in which case we recommend having a large + enough container to accomodate all optons and eliminate scrolling.

), From 75805ad0d1e89261c08ceacda6497b82a29f6611 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 6 Jan 2022 11:24:34 -0600 Subject: [PATCH 3/7] CL --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47d55dd0fe8..33967368d53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## [`main`](https://github.com/elastic/eui/tree/main) +- Added virtulized rendering option to `EuiSelectableList` with `isVirtualized` ([#5521](https://github.com/elastic/eui/pull/5521)) +- Added expanded option properties to `EuiSelectableOption` with `labelProps` ([#5521](https://github.com/elastic/eui/pull/5521)) + **Breaking changes** - Changed `EuiSearchBar` to preserve phrases with leading and trailing spaces, instead of dropping surrounding whitespace ([#5514](https://github.com/elastic/eui/pull/5514)) From 8c3855505949e7b55e03539d9a26d2c8f30a2436 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 6 Jan 2022 13:30:19 -0600 Subject: [PATCH 4/7] review feedback --- .../src/views/selectable/selectable_example.js | 14 +++++++------- .../__snapshots__/selectable.test.tsx.snap | 6 +++--- src/components/selectable/selectable.test.tsx | 2 +- .../__snapshots__/selectable_list.test.tsx.snap | 2 +- .../selectable_list/selectable_list.test.tsx | 2 +- .../selectable/selectable_list/selectable_list.tsx | 14 ++++++++++---- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src-docs/src/views/selectable/selectable_example.js b/src-docs/src/views/selectable/selectable_example.js index 3747a417ded..757589e8127 100644 --- a/src-docs/src/views/selectable/selectable_example.js +++ b/src-docs/src/views/selectable/selectable_example.js @@ -360,10 +360,16 @@ export const SelectableExample = { To provide data that can be used by the{' '} renderOption function that does not match the standard option API, use option.labelProps which - will be make custom data available in the option{' '} + will make custom data available in the option{' '} parameter. See the secondaryContent configuration in the following example.

+

+ Every row must be the same height unless{' '} + listProps.isVirtualized is set to{' '} + false, in which case we recommend having a large + enough container to accomodate all optons and eliminate scrolling. +

In order for the list to know how to scroll to the selected or highlighted option, it must also know the height of the rows. It @@ -372,12 +378,6 @@ export const SelectableExample = { you will need to recalculate this height and apply it via{' '} listProps.rowHeight.

-

- Every row must be the same height unless{' '} - listProps.isVirtualized is set to{' '} - false, in which case we recommend having a large - enough container to accomodate all optons and eliminate scrolling. -

), demo: , diff --git a/src/components/selectable/__snapshots__/selectable.test.tsx.snap b/src/components/selectable/__snapshots__/selectable.test.tsx.snap index cc156de75be..f21538848e2 100644 --- a/src/components/selectable/__snapshots__/selectable.test.tsx.snap +++ b/src/components/selectable/__snapshots__/selectable.test.tsx.snap @@ -38,7 +38,7 @@ exports[`EuiSelectable custom options with labelProps 1`] = ` class="euiSelectableListItem__text" > - Titan: VI + VI: Titan @@ -64,7 +64,7 @@ exports[`EuiSelectable custom options with labelProps 1`] = ` class="euiSelectableListItem__text" > - Enceladus: II + II: Enceladus @@ -90,7 +90,7 @@ exports[`EuiSelectable custom options with labelProps 1`] = ` class="euiSelectableListItem__text" > - Pandora is one of Saturn's moons, named for a Titaness of Greek mythology: XVII + XVII: Pandora is one of Saturn's moons, named for a Titaness of Greek mythology diff --git a/src/components/selectable/selectable.test.tsx b/src/components/selectable/selectable.test.tsx index e45f9012536..cb37c32a33c 100644 --- a/src/components/selectable/selectable.test.tsx +++ b/src/components/selectable/selectable.test.tsx @@ -240,7 +240,7 @@ describe('EuiSelectable', () => { renderOption={(option) => { return ( - {option.label}: {option.numeral} + {option.numeral}: {option.label} ); }} diff --git a/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap b/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap index 64f6b503dff..e695d3effb2 100644 --- a/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap +++ b/src/components/selectable/selectable_list/__snapshots__/selectable_list.test.tsx.snap @@ -1087,7 +1087,7 @@ exports[`EuiSelectableListItem props height is full 1`] = `
`; -exports[`EuiSelectableListItem props isVirtualized 1`] = ` +exports[`EuiSelectableListItem props isVirtualized can be false 1`] = `
{ expect(component).toMatchSnapshot(); }); - test('isVirtualized', () => { + test('isVirtualized can be false', () => { const component = render( - extends ReactWindowListChildComponentProps { + extends Omit { data: Array>; + style?: CSSProperties; } // Consumer Configurable Props via `EuiSelectable.listProps` @@ -63,7 +70,7 @@ export type EuiSelectableOptionsListProps = CommonProps & onFocusBadge?: EuiSelectableListItemProps['onFocusBadge']; /** * Use virtualized rendering for list items with `react-window`. - * Requires that each option be the same height. + * Sets each row's height to the value of `rowHeight`. */ isVirtualized?: boolean; }; @@ -357,7 +364,6 @@ export class EuiSelectableList extends Component> { key: index, data: optionArray, index, - style: {}, }, null ) From 077bb158267701584111f2e22b9290ceaae3718c Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 6 Jan 2022 14:57:29 -0600 Subject: [PATCH 5/7] update list types --- src/components/selectable/selectable.tsx | 23 +++++++++++- .../selectable/selectable_list/index.ts | 1 + .../selectable_list/selectable_list.tsx | 37 ++++++++++++------- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/components/selectable/selectable.tsx b/src/components/selectable/selectable.tsx index b2cd6af939d..5d4a63e8550 100644 --- a/src/components/selectable/selectable.tsx +++ b/src/components/selectable/selectable.tsx @@ -18,7 +18,10 @@ import classNames from 'classnames'; import { CommonProps, ExclusiveUnion } from '../common'; import { EuiSelectableSearch } from './selectable_search'; import { EuiSelectableMessage } from './selectable_message'; -import { EuiSelectableList } from './selectable_list'; +import { + EuiSelectableList, + EuiSelectableOptionsListVirtualizedProps, +} from './selectable_list'; import { EuiLoadingSpinner } from '../loading'; import { EuiSpacer } from '../spacer'; import { getMatchingOptions } from './matching_options'; @@ -434,8 +437,23 @@ export class EuiSelectable extends Component< const { 'aria-label': listAriaLabel, 'aria-describedby': listAriaDescribedby, + isVirtualized, + rowHeight, ...cleanedListProps - } = listProps || unknownAccessibleName; + } = (listProps || unknownAccessibleName) as typeof listProps & + typeof unknownAccessibleName; + + let virtualizedProps: EuiSelectableOptionsListVirtualizedProps; + + if (isVirtualized === false) { + virtualizedProps = { + isVirtualized, + }; + } else if (rowHeight != null) { + virtualizedProps = { + rowHeight, + }; + } const classes = classNames( 'euiSelectable', @@ -629,6 +647,7 @@ export class EuiSelectable extends Component< ? listAccessibleName : searchable && { 'aria-label': placeholderName })} {...cleanedListProps} + {...virtualizedProps} /> )} diff --git a/src/components/selectable/selectable_list/index.ts b/src/components/selectable/selectable_list/index.ts index 34e6b3f63d7..ba498f70b37 100644 --- a/src/components/selectable/selectable_list/index.ts +++ b/src/components/selectable/selectable_list/index.ts @@ -10,6 +10,7 @@ export { EuiSelectableList, EuiSelectableListProps, EuiSelectableOptionsListProps, + EuiSelectableOptionsListVirtualizedProps, } from './selectable_list'; export { EuiSelectableListItem, diff --git a/src/components/selectable/selectable_list/selectable_list.tsx b/src/components/selectable/selectable_list/selectable_list.tsx index ac06170191f..178d9b1333b 100644 --- a/src/components/selectable/selectable_list/selectable_list.tsx +++ b/src/components/selectable/selectable_list/selectable_list.tsx @@ -20,7 +20,7 @@ import { ListChildComponentProps as ReactWindowListChildComponentProps, areEqual, } from 'react-window'; -import { CommonProps } from '../../common'; +import { CommonProps, ExclusiveUnion } from '../../common'; import { EuiAutoSizer } from '../../auto_sizer'; import { EuiHighlight } from '../../highlight'; import { EuiSelectableOption } from '../selectable_option'; @@ -35,6 +35,24 @@ interface ListChildComponentProps style?: CSSProperties; } +export type EuiSelectableOptionsListVirtualizedProps = ExclusiveUnion< + { + /** + * Use virtualized rendering for list items with `react-window`. + * Sets each row's height to the value of `rowHeight`. + */ + isVirtualized?: true; + /** + * The height of each option in pixels. Defaults to `32`. + * Has no effect if `isVirtualized=false`. + */ + rowHeight: number; + }, + { + isVirtualized: false; + } +>; + // Consumer Configurable Props via `EuiSelectable.listProps` export type EuiSelectableOptionsListProps = CommonProps & HTMLAttributes & { @@ -44,10 +62,6 @@ export type EuiSelectableOptionsListProps = CommonProps & * directly to that option */ activeOptionIndex?: number; - /** - * The height of each option in pixels. Defaults to `32` - */ - rowHeight: number; /** * Show the check/cross selection indicator icons */ @@ -68,12 +82,7 @@ export type EuiSelectableOptionsListProps = CommonProps & * The default content when `true` is `↩ to select/deselect/include/exclude` */ onFocusBadge?: EuiSelectableListItemProps['onFocusBadge']; - /** - * Use virtualized rendering for list items with `react-window`. - * Sets each row's height to the value of `rowHeight`. - */ - isVirtualized?: boolean; - }; + } & EuiSelectableOptionsListVirtualizedProps; export type EuiSelectableListProps = EuiSelectableOptionsListProps & { /** @@ -313,9 +322,9 @@ export class EuiSelectableList extends Component> { if (numVisibleMoreThanMax) { // Show only half of the last one to indicate there's more to scroll to - calculatedHeight = (maxVisibleOptions - 0.5) * rowHeight; + calculatedHeight = (maxVisibleOptions - 0.5) * rowHeight!; } else { - calculatedHeight = numVisibleOptions * rowHeight; + calculatedHeight = numVisibleOptions * rowHeight!; } } @@ -342,7 +351,7 @@ export class EuiSelectableList extends Component> { height={calculatedHeight || height} itemCount={optionArray.length} itemData={optionArray} - itemSize={rowHeight} + itemSize={rowHeight!} innerElementType="ul" innerRef={this.setListBoxRef} {...windowProps} From 7a0df309225abdfd896c9fc60bab01ad0d9979b8 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Tue, 11 Jan 2022 13:01:14 -0600 Subject: [PATCH 6/7] labelProps -> data --- CHANGELOG.md | 2 +- .../src/views/selectable/selectable_custom_render.js | 2 +- src-docs/src/views/selectable/selectable_example.js | 4 ++-- .../__snapshots__/selectable.test.tsx.snap | 2 +- src/components/selectable/selectable.test.tsx | 12 ++++++------ .../selectable/selectable_list/selectable_list.tsx | 6 +++--- src/components/selectable/selectable_option.tsx | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33967368d53..5b089c8b4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## [`main`](https://github.com/elastic/eui/tree/main) - Added virtulized rendering option to `EuiSelectableList` with `isVirtualized` ([#5521](https://github.com/elastic/eui/pull/5521)) -- Added expanded option properties to `EuiSelectableOption` with `labelProps` ([#5521](https://github.com/elastic/eui/pull/5521)) +- Added expanded option properties to `EuiSelectableOption` with `data` ([#5521](https://github.com/elastic/eui/pull/5521)) **Breaking changes** diff --git a/src-docs/src/views/selectable/selectable_custom_render.js b/src-docs/src/views/selectable/selectable_custom_render.js index 6ca05463d1b..528e4ef96f7 100644 --- a/src-docs/src/views/selectable/selectable_custom_render.js +++ b/src-docs/src/views/selectable/selectable_custom_render.js @@ -20,7 +20,7 @@ export default () => { prepend: country.flag, append: {country.code}, showIcons: false, - labelProps: { + data: { secondaryContent: 'I am secondary content, I am!', }, }; diff --git a/src-docs/src/views/selectable/selectable_example.js b/src-docs/src/views/selectable/selectable_example.js index 757589e8127..367ec440880 100644 --- a/src-docs/src/views/selectable/selectable_example.js +++ b/src-docs/src/views/selectable/selectable_example.js @@ -359,8 +359,8 @@ export const SelectableExample = {

To provide data that can be used by the{' '} renderOption function that does not match the - standard option API, use option.labelProps which - will make custom data available in the option{' '} + standard option API, use option.data which will + make custom data available in the option{' '} parameter. See the secondaryContent configuration in the following example.

diff --git a/src/components/selectable/__snapshots__/selectable.test.tsx.snap b/src/components/selectable/__snapshots__/selectable.test.tsx.snap index f21538848e2..dfb568309cf 100644 --- a/src/components/selectable/__snapshots__/selectable.test.tsx.snap +++ b/src/components/selectable/__snapshots__/selectable.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`EuiSelectable custom options with labelProps 1`] = ` +exports[`EuiSelectable custom options with data 1`] = `
diff --git a/src/components/selectable/selectable.test.tsx b/src/components/selectable/selectable.test.tsx index cb37c32a33c..35c8fbea1da 100644 --- a/src/components/selectable/selectable.test.tsx +++ b/src/components/selectable/selectable.test.tsx @@ -209,33 +209,33 @@ describe('EuiSelectable', () => { ).toEqual(options); }); - test('with labelProps', () => { - type WithLabelProps = { + test('with data', () => { + type WithData = { numeral?: string; }; const options = [ { label: 'Titan', - labelProps: { + data: { numeral: 'VI', }, }, { label: 'Enceladus', - labelProps: { + data: { numeral: 'II', }, }, { label: "Pandora is one of Saturn's moons, named for a Titaness of Greek mythology", - labelProps: { + data: { numeral: 'XVII', }, }, ]; const component = render( - + options={options} renderOption={(option) => { return ( diff --git a/src/components/selectable/selectable_list/selectable_list.tsx b/src/components/selectable/selectable_list/selectable_list.tsx index 178d9b1333b..98085662232 100644 --- a/src/components/selectable/selectable_list/selectable_list.tsx +++ b/src/components/selectable/selectable_list/selectable_list.tsx @@ -208,7 +208,7 @@ export class EuiSelectableList extends Component> { ListRow = memo(({ data, index, style }: ListChildComponentProps) => { const option = data[index]; - const { labelProps, ..._option } = option; + const { data: optionData, ..._option } = option; const { label, isGroupLabel, @@ -219,7 +219,7 @@ export class EuiSelectableList extends Component> { ref, key, searchableLabel, - labelProps: _labelProps, + data: _data, ...optionRest } = option; @@ -267,7 +267,7 @@ export class EuiSelectableList extends Component> { {this.props.renderOption ? ( this.props.renderOption( // @ts-ignore complex - { ..._option, ...labelProps }, + { ..._option, ...optionData }, this.props.searchValue ) ) : ( diff --git a/src/components/selectable/selectable_option.tsx b/src/components/selectable/selectable_option.tsx index 2304160e552..17fdaeafb54 100644 --- a/src/components/selectable/selectable_option.tsx +++ b/src/components/selectable/selectable_option.tsx @@ -54,10 +54,10 @@ export type EuiSelectableOptionBase = CommonProps & { */ id?: never; /** - * Props to pass through to the `renderOptions` element. + * Option data to pass through to the `renderOptions` element. * Bypass `EuiSelectableItem` and avoid DOM attribute warnings. */ - labelProps?: { [key: string]: any }; + data?: { [key: string]: any }; }; type _EuiSelectableGroupLabelOption = Omit< From 1485d4a660fe151bdb7c357647534398b83bad3e Mon Sep 17 00:00:00 2001 From: cchaos Date: Tue, 11 Jan 2022 15:13:08 -0500 Subject: [PATCH 7/7] Update docs with virtualization toggle and hide overflow of selectable item --- .../selectable/selectable_custom_render.js | 30 ++++++++++++++----- .../views/selectable/selectable_example.js | 29 ++++++++++-------- .../_selectable_list_item.scss | 3 +- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src-docs/src/views/selectable/selectable_custom_render.js b/src-docs/src/views/selectable/selectable_custom_render.js index 528e4ef96f7..ef4c3dcea12 100644 --- a/src-docs/src/views/selectable/selectable_custom_render.js +++ b/src-docs/src/views/selectable/selectable_custom_render.js @@ -12,6 +12,7 @@ import { createDataStore } from '../tables/data_store'; export default () => { const [useCustomContent, setUseCustomContent] = useState(false); + const [isVirtualized, setIsVirtualized] = useState(true); const countries = createDataStore().countries.map((country) => { return { @@ -41,12 +42,16 @@ export default () => { setUseCustomContent(e.currentTarget.checked); }; + const onVirtualized = (e) => { + setIsVirtualized(e.currentTarget.checked); + }; + const renderCountryOption = (option, searchValue) => { return ( <> {option.label} -
- + {/*
*/} + {option.secondaryContent} @@ -57,33 +62,42 @@ export default () => { ); }; + let listProps = { + isVirtualized, + }; + let customProps; if (useCustomContent) { customProps = { height: 240, renderOption: renderCountryOption, - listProps: { - rowHeight: 50, - showIcons: false, - }, + }; + listProps = { + rowHeight: 50, + isVirtualized, }; } return ( <> + {' '} +   - - {(list, search) => ( diff --git a/src-docs/src/views/selectable/selectable_example.js b/src-docs/src/views/selectable/selectable_example.js index 367ec440880..cfc07fc6491 100644 --- a/src-docs/src/views/selectable/selectable_example.js +++ b/src-docs/src/views/selectable/selectable_example.js @@ -347,6 +347,20 @@ export const SelectableExample = { similar to a title. Add one of these by setting the{' '} option.isGroupLabel to true.{' '}

+

Row height and virtualization

+

+ When virtualization is on,{' '} + every row must be the same height in order for the + list to know how to scroll to the selected or highlighted option. It + applies the listProps.rowHeight (in pixels) + directly to each option hiding any overflow. +

+

+ If listProps.isVirtualized is set to{' '} + false, each row will fit its contents and removes + all scrolling. Therefore, we recommend having a large enough + container to accomodate all optons. +

Custom content

While it is best to stick to the{' '} @@ -365,18 +379,9 @@ export const SelectableExample = { in the following example.

- Every row must be the same height unless{' '} - listProps.isVirtualized is set to{' '} - false, in which case we recommend having a large - enough container to accomodate all optons and eliminate scrolling. -

-

- In order for the list to know how to scroll to the selected or - highlighted option, it must also know the height of the rows. It - applies this pixel height directly to options. If your custom - content is taller than the default of 32px tall, - you will need to recalculate this height and apply it via{' '} - listProps.rowHeight. + Also, if your custom content is taller than the default{' '} + listProps.rowHeight of 32px{' '} + tall, you will need to pass in a custom value to this prop.

), diff --git a/src/components/selectable/selectable_list/_selectable_list_item.scss b/src/components/selectable/selectable_list/_selectable_list_item.scss index 0fa04412130..1f3623519d0 100644 --- a/src/components/selectable/selectable_list/_selectable_list_item.scss +++ b/src/components/selectable/selectable_list/_selectable_list_item.scss @@ -5,6 +5,7 @@ text-align: left; color: $euiTextColor; cursor: pointer; + overflow: hidden; &:not(:last-of-type) { border-bottom: $euiSelectableListItemBorder; @@ -12,7 +13,7 @@ &-isFocused:not([aria-disabled='true']), &:hover:not([aria-disabled='true']) { - color: $euiColorPrimary; + color: $euiColorPrimaryText; background-color: $euiFocusBackgroundColor; .euiSelectableListItem__text {