Skip to content

Commit

Permalink
Updated Typeahead Dropdown (#776)
Browse files Browse the repository at this point in the history
* feat: finished updating the new search fun tionality

* feat: added pre value filtering

* feat: finished updating the typeahead

* chore: updated version

* chore: removed dead code

* chore: pr feedback
  • Loading branch information
brandenTenbrink authored May 27, 2022
1 parent 2630910 commit b03beb7
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 34 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

### 4.3.0 (2022-05-27)

- [776](https://github.com/influxdata/clockface/pull/776): Updated Typeahead Dropdown to force searching on large list sizes

### 4.2.1 (2022-05-23)

- [772](https://github.com/influxdata/clockface/pull/772): chore: update Roboto Mono and Proxima Nova files to woff2
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@influxdata/clockface",
"version": "4.2.1",
"version": "4.3.0",
"license": "MIT",
"main": "dist/index.js",
"style": "dist/index.css",
Expand Down
104 changes: 72 additions & 32 deletions src/Components/Dropdowns/Composed/TypeAheadDropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ interface OwnProps extends StandardFunctionProps {
testIdSuffix?: string
/**optional pre-selected option, must match exactly (name and id) an item in the items array */
selectedOption?: SelectableItem | null
/**enables forced searching once dropdown list exceeds largeListSearch value */
largeListSearch?: boolean
/**the number of total items in the dropdown list before search is forced */
largeListCeiling?: number
/** which theme to apply */
menuTheme?: DropdownMenuTheme
buttonTestId?: string
Expand Down Expand Up @@ -70,6 +74,8 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
testIdSuffix = 'typeAhead',
selectedOption = null,
className,
largeListSearch = false,
largeListCeiling = 0,
menuTheme = DropdownMenuTheme.Onyx,
buttonTestId = 'type-ahead-dropdown--button',
menuTestID = 'type-ahead-dropdown--menu',
Expand All @@ -87,22 +93,40 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
}

const [selectIndex, setSelectIndex] = useState(-1)
const [shownValues, setShownValues] = useState(items)
const [queryResults, setQueryResults] = useState(items)
const [menuOpen, setMenuOpen] = useState<MenuStatus>(MenuStatus.Closed)

const [selectedItem, setSelectedItem] = useState<SelectableItem | null>(
selectedOption
)

let initialTypedValue = ''

if (selectedOption) {
initialTypedValue = getValueWithBackup(selectedOption.name, defaultNameText)
}

const [selectedItem, setSelectedItem] = useState<SelectableItem | null>(
selectedOption
)
const [typedValue, setTypedValue] = useState<string>(initialTypedValue)

const largeListValidation =
largeListSearch && queryResults.length > largeListCeiling

useEffect(() => {
setShownValues(items)
}, [items])
if (typedValue.length > 0) {
const result = items.filter(val => {
const name = val?.name || ''
return name.toLowerCase().includes(typedValue.toLowerCase())
})

// always reset the selectIndex when doing filtering; because
// if it had a value, and then they type, the queryResults changes
// so need to reset
setQueryResults(result)
setSelectIndex(-1)
} else {
setQueryResults(items)
}
}, [items, typedValue])

/**
* using a ref to hold an instance variable: what was last typed,
Expand All @@ -123,11 +147,11 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
* if the needle is empty; then there is nothing to filter; so return everything
*/
const doFilter = (needle: string) => {
// if there is no value, set the shownValues to everything
// if there is no value, set the queryResults to everything
// and set the typedValue to nothing (zero it out)
// reset the selectIndex too
if (!needle) {
setShownValues(items)
setQueryResults(items)
setTypedValue('')
setSelectIndex(-1)
} else {
Expand All @@ -137,9 +161,9 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
})

// always reset the selectIndex when doing filtering; because
// if it had a value, and then they type, the shownValues changes
// if it had a value, and then they type, the queryResults changes
// so need to reset
setShownValues(result)
setQueryResults(result)
setTypedValue(needle)
setMenuOpen(MenuStatus.Open)
setSelectIndex(-1)
Expand Down Expand Up @@ -181,7 +205,7 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
newIndex = selectIndex - 1
}

const numItems = shownValues.length
const numItems = queryResults.length
const newValueWasHighlighted =
numItems && newIndex >= 0 && newIndex < numItems
if (newValueWasHighlighted) {
Expand All @@ -195,7 +219,7 @@ export const TypeAheadDropDown: FC<OwnProps> = ({

if (numItems && selectIndex >= 0 && selectIndex < numItems) {
// they used the arrows; just pressed return
doSelection(shownValues[selectIndex], true)
doSelection(queryResults[selectIndex], true)
} else {
// the person could have been typing and pressed return, need to
// make sure the value in the input field is real/legal:
Expand Down Expand Up @@ -273,6 +297,11 @@ export const TypeAheadDropDown: FC<OwnProps> = ({

const props: any = {id, style, className, menuOpen}

const largeListValidationText =
typedValue.length >= 1
? 'There are still too many results. Please input more characters.'
: 'Please input a character to start seeing results.'

return (
<Dropdown
{...props}
Expand All @@ -295,27 +324,38 @@ export const TypeAheadDropDown: FC<OwnProps> = ({
onCollapse={onCollapse}
theme={menuTheme}
>
{shownValues.map((value, index) => {
// add the 'active' class to highlight when arrowing; like a hover
const classN = classnames({
active: index === selectIndex,
{largeListValidation ? (
<Dropdown.Item
key="nada-no-values-in-filter"
testID="nothing-in-filter-typeAhead"
disabled={true}
wrapText={true}
>
{largeListValidationText}
</Dropdown.Item>
) : (
queryResults.map((value, index) => {
// add the 'active' class to highlight when arrowing; like a hover
const classN = classnames({
active: index === selectIndex,
})

return (
<Dropdown.Item
key={value.id}
id={value.id}
value={value}
onClick={doSelection}
selected={value.id === selectedItem?.id}
testID={`${itemTestIdPrefix}-${value.id}`}
className={classN}
>
{value.name || defaultNameText}
</Dropdown.Item>
)
})

return (
<Dropdown.Item
key={value.id}
id={value.id}
value={value}
onClick={doSelection}
selected={value.id === selectedItem?.id}
testID={`${itemTestIdPrefix}-${value.id}`}
className={classN}
>
{value.name || defaultNameText}
</Dropdown.Item>
)
})}
{!shownValues || shownValues.length === 0 ? (
)}
{!queryResults || queryResults.length === 0 ? (
<Dropdown.Item
key="nada-no-values-in-filter"
testID="nothing-in-filter-typeAhead"
Expand Down
9 changes: 9 additions & 0 deletions src/Components/Dropdowns/Documentation/Dropdowns.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,11 @@ dropdownComposedStories.add(
{name: 'Kiwi', id: '8'},
{name: 'Banana', id: '9'},
{name: 'Strawberry', id: '1099'},
{name: 'Strawberry1', id: '123412'},
{name: 'Strawberry2', id: '2'},
{name: 'Strawberry3', id: '109'},
{name: 'Strawberry4', id: '19'},
{name: 'Strawberry5', id: '1'},
{name: 'blueberry', id: 'blueberry113'},
{id: '1234.3.33'},
]
Expand All @@ -616,6 +621,8 @@ dropdownComposedStories.add(
style={object('style', defaultDropdownStyle)}
onSelect={onSelect}
testIdSuffix="fooTest"
largeListSearch={boolean('largeListSearch', false)}
largeListCeiling={number('largeListCeiling', 0)}
items={selectDropdownOptions}
menuTestID={text('menu test id', 'menuTest')}
status={
Expand Down Expand Up @@ -643,6 +650,8 @@ dropdownComposedStories.add(
onSelect={onSelect}
testIdSuffix="fooTest"
items={selectDropdownOptions}
largeListSearch={boolean('largeListSearch', false)}
largeListCeiling={number('largeListCeiling', 0)}
menuTestID={text('menu test id 2', 'menuTest')}
itemTestIdPrefix={text('item test id prefix 2', 'my-prefix')}
defaultNameText={text(
Expand Down
7 changes: 7 additions & 0 deletions src/Components/Dropdowns/Documentation/TypeAheadDropdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ const items = [
{name: 'Kiwi', id: '8'},
{name: 'Banana', id: '9'},
{name: 'Strawberry', id: '1099'},
{name: 'Strawberry', id: '1099'},
{name: 'Strawberry1', id: '123412'},
{name: 'Strawberry2', id: '2'},
{name: 'Strawberry3', id: '109'},
{name: 'Strawberry4', id: '19'},
{name: 'Strawberry5', id: '1'},
{id: '1234.3.33'},
]

Expand All @@ -68,6 +74,7 @@ And here's rendering the component:
items={items}
buttonTestId='buttonTestID'
menuTestID='menuTest'
minSearchItems={15}
itemTestIdPrefix= 'my-prefix'
defaultNameText='default empty name here'
selectedOption={selectedOption}
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Dropdowns/Dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ $dropdown-item--padding-v: $cf-space-2xs;
.cf-dropdown-item__wrap .cf-dropdown-item--children,
.cf-dropdown-item__wrap.cf-dropdown-link-item a,
.cf-dropdown-item__wrap.cf-dropdown-item-empty {
word-break: break-all;
word-break: keep-all;
white-space: pre-wrap;
}

Expand Down

0 comments on commit b03beb7

Please sign in to comment.