diff --git a/CHANGELOG.md b/CHANGELOG.md index 9baec012..10a03c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 6.3.9 (2022-11-02) + +- [885](https://github.com/influxdata/clockface/pull/885): (MultiSelect): make MultiSelectDropdown optionally searchable through `isSearchable` prop + ### 6.3.8 (2022-10-04) - [857](https://github.com/influxdata/clockface/pull/857): (TimeInput): Fix the dropdown button width to accomodate for multi-character units @@ -39,6 +43,7 @@ ### 6.2.0 (2022-08-24) - [814](https://github.com/influxdata/clockface/pull/814): Added Collapse functionality to the Draggable Resizer + ### 6.1.1 (2022-08-17) - [823](https://github.com/influxdata/clockface/pull/823): Typeahead Dropdown select text on focus works on all browsers @@ -55,7 +60,6 @@ - [804](https://github.com/influxdata/clockface/pull/804): Add DoubleCaretVertical icon and trailingIcon prop to Dropdown.Button - ### 6.0.0 (2022-08-01) - [812](https://github.com/influxdata/clockface/pull/812): Remove unused MenuDropdown code diff --git a/package.json b/package.json index 91bc72dc..fbb2dafa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@influxdata/clockface", - "version": "6.3.8", + "version": "6.3.9", "license": "MIT", "main": "dist/index.js", "style": "dist/index.css", diff --git a/src/Components/Dropdowns/Composed/MultiSelectDropdown.tsx b/src/Components/Dropdowns/Composed/MultiSelectDropdown.tsx index ba313167..8cc75643 100644 --- a/src/Components/Dropdowns/Composed/MultiSelectDropdown.tsx +++ b/src/Components/Dropdowns/Composed/MultiSelectDropdown.tsx @@ -1,5 +1,5 @@ // Libraries -import React, {MouseEvent, forwardRef} from 'react' +import React, {MouseEvent, forwardRef, useState} from 'react' // Components import {Dropdown, DropdownRef} from '../' @@ -17,6 +17,7 @@ import { ComponentStatus, StandardFunctionProps, } from '../../../Types' +import {Input} from '../../Inputs' export interface MultiSelectDropdownProps extends StandardFunctionProps { /** Text to render in button as currently selected option */ @@ -43,6 +44,9 @@ export interface MultiSelectDropdownProps extends StandardFunctionProps { menuMaxHeight?: number /** Renders the menu element above the button instead of below */ dropUp?: boolean + /** Enables the search bar in the dropdown menu */ + isSearchable?: boolean + searchbarInputPlaceholder?: string } export type MultiSelectDropdownRef = DropdownRef @@ -69,6 +73,8 @@ export const MultiSelectDropdown = forwardRef< buttonStatus = ComponentStatus.Default, menuMaxHeight, selectedOptions, + isSearchable = false, + searchbarInputPlaceholder = 'Search', }, ref ) => { @@ -76,6 +82,8 @@ export const MultiSelectDropdown = forwardRef< ? selectedOptions.join(', ') : emptyText + const [filterString, setFilterString] = useState('') + const button = ( active: boolean, onClick: (e: MouseEvent) => void @@ -92,32 +100,79 @@ export const MultiSelectDropdown = forwardRef< ) + const NoResults = () => ( + + {filterString.length > 0 + ? `no matches for ${filterString}` + : 'No results'} + + ) + + const handleFiltering = (e: any) => { + const filterStr = e.currentTarget.value + setFilterString(filterStr) + } + + const clearFilter = () => { + setFilterString('') + } + const menu = () => ( - - {options.map(o => { - if (o === DROPDOWN_DIVIDER_SHORTCODE) { - return - } - - if (o.includes(DROPDOWN_DIVIDER_SHORTCODE)) { - const dividerText = o.replace(DROPDOWN_DIVIDER_SHORTCODE, '') - return - } - - return ( - - {o} - - ) - })} - + <> + {isSearchable && ( + + + + )} + + {options.map(o => { + // case-insensitive search + if ( + isSearchable && + !o.toUpperCase().includes(filterString.toUpperCase()) + ) { + return + } + + if (o === DROPDOWN_DIVIDER_SHORTCODE) { + return + } + + if (o.includes(DROPDOWN_DIVIDER_SHORTCODE)) { + const dividerText = o.replace(DROPDOWN_DIVIDER_SHORTCODE, '') + return + } + + return ( + + {o} + + ) + })} + + {options.filter(option => + option.toUpperCase().includes(filterString.toUpperCase()) + ).length === 0 ? ( + + ) : null} + + ) return ( diff --git a/src/Components/Dropdowns/Documentation/Dropdowns.stories.tsx b/src/Components/Dropdowns/Documentation/Dropdowns.stories.tsx index c9a37548..f049471b 100644 --- a/src/Components/Dropdowns/Documentation/Dropdowns.stories.tsx +++ b/src/Components/Dropdowns/Documentation/Dropdowns.stories.tsx @@ -906,6 +906,11 @@ dropdownComposedStories.add( emptyText={text('emptyText', 'None selected')} selectedOptions={selectedOptions} options={array('options', defaultMultiSelectOptions)} + isSearchable={boolean('isSearchable', true)} + searchbarInputPlaceholder={text( + 'searchbarInputPlaceholder', + 'Search' + )} />