diff --git a/packages/react-core/src/demos/SearchInput/SearchInput.md b/packages/react-core/src/demos/SearchInput/SearchInput.md
index e7570ab47e5..764517f576b 100644
--- a/packages/react-core/src/demos/SearchInput/SearchInput.md
+++ b/packages/react-core/src/demos/SearchInput/SearchInput.md
@@ -3,24 +3,25 @@ id: Search input
section: components
beta: true
---
-import {
- Button,
- Card,
- CardBody,
- CardFooter,
- DatePicker,
- Form,
- FormGroup,
- Grid,
- GridItem,
- Menu,
- MenuContent,
- MenuItem,
- MenuList,
- MenuToggle,
- Popper,
- SearchInput,
- TextInput
+
+import {
+Button,
+Card,
+CardBody,
+CardFooter,
+DatePicker,
+Form,
+FormGroup,
+Grid,
+GridItem,
+Menu,
+MenuContent,
+MenuItem,
+MenuList,
+MenuToggle,
+Popper,
+SearchInput,
+TextInput
} from '@patternfly/react-core';
import { words } from './words.js';
@@ -31,17 +32,9 @@ import { words } from './words.js';
This demo handles building the advanced search form using the composable Menu, and the `SearchInput`'s `hint` prop.
It also demonstrates wiring up the appropriate keyboard interactions, focus management, and general event handling.
-
```js
import React from 'react';
-import {
- Menu,
- MenuContent,
- MenuItem,
- MenuList,
- Popper,
- SearchInput
-} from '@patternfly/react-core';
+import { Menu, MenuContent, MenuItem, MenuList, Popper, SearchInput } from '@patternfly/react-core';
import { words } from './words.js';
@@ -49,32 +42,52 @@ SearchAutocomplete = () => {
const [value, setValue] = React.useState('');
const [hint, setHint] = React.useState('');
const [autocompleteOptions, setAutocompleteOptions] = React.useState([]);
-
+
const [isAutocompleteOpen, setIsAutocompleteOpen] = React.useState(false);
-
+
const searchInputRef = React.useRef(null);
const autocompleteRef = React.useRef(null);
-
+
const onClear = () => {
setValue('');
};
-
- const onChange = (newValue) => {
- if (newValue !== '' && searchInputRef && searchInputRef.current && searchInputRef.current.contains(document.activeElement)) {
+
+ const onChange = (_event, newValue) => {
+ if (
+ newValue !== '' &&
+ searchInputRef &&
+ searchInputRef.current &&
+ searchInputRef.current.contains(document.activeElement)
+ ) {
setIsAutocompleteOpen(true);
-
+
// When the value of the search input changes, build a list of no more than 10 autocomplete options.
// Options which start with the search input value are listed first, followed by options which contain
// the search input value.
- let options = words.filter((option) => option.startsWith(newValue.toLowerCase())).map((option) => );
+ let options = words
+ .filter((option) => option.startsWith(newValue.toLowerCase()))
+ .map((option) => (
+
+ ));
if (options.length > 10) {
- options = options.slice(0,10);
+ options = options.slice(0, 10);
} else {
- options = [...options, ...words.filter((option) => !option.startsWith(newValue.toLowerCase()) && option.includes(newValue.toLowerCase())).map((option) => )].slice(0, 10)
+ options = [
+ ...options,
+ ...words
+ .filter((option) => !option.startsWith(newValue.toLowerCase()) && option.includes(newValue.toLowerCase()))
+ .map((option) => (
+
+ ))
+ ].slice(0, 10);
}
-
+
// The hint is set whenever there is only one autocomplete option left.
- setHint(options.length === 1? options[0].props.itemId : '');
+ setHint(options.length === 1 ? options[0].props.itemId : '');
// The menu is hidden if there are no options
setIsAutocompleteOpen(options.length > 0);
setAutocompleteOptions(options);
@@ -83,7 +96,7 @@ SearchAutocomplete = () => {
}
setValue(newValue);
};
-
+
// Whenever an autocomplete option is selected, set the search input value, close the menu, and put the browser
// focus back on the search input
const onSelect = (e, itemId) => {
@@ -92,53 +105,57 @@ SearchAutocomplete = () => {
setIsAutocompleteOpen(false);
searchInputRef.current.focus();
};
-
- const handleMenuKeys = event => {
- // If there is a hint while the browser focus is on the search input, tab or right arrow will 'accept' the hint value
+
+ const handleMenuKeys = (event) => {
+ // If there is a hint while the browser focus is on the search input, tab or right arrow will 'accept' the hint value
// and set it as the search input value
if (hint && (event.key === 'Tab' || event.key === 'ArrowRight') && searchInputRef.current === event.target) {
setValue(hint);
setHint('');
setIsAutocompleteOpen(false);
if (event.key === 'ArrowRight') {
- event.preventDefault();
+ event.preventDefault();
}
- // if the autocomplete is open and the browser focus is on the search input,
+ // if the autocomplete is open and the browser focus is on the search input,
} else if (isAutocompleteOpen && searchInputRef.current && searchInputRef.current === event.target) {
// the escape key closes the autocomplete menu and keeps the focus on the search input.
if (event.key === 'Escape') {
setIsAutocompleteOpen(false);
searchInputRef.current.focus();
- // the up and down arrow keys move browser focus into the autocomplete menu
+ // the up and down arrow keys move browser focus into the autocomplete menu
} else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
const firstElement = autocompleteRef.current.querySelector('li > button:not(:disabled)');
firstElement && firstElement.focus();
event.preventDefault(); // by default, the up and down arrow keys scroll the window
- // the tab, enter, and space keys will close the menu, and the tab key will move browser
- // focus forward one element (by default)
- } else if (event.key === 'Tab'|| event.key === "Enter" || event.key === 'Space'){
+ // the tab, enter, and space keys will close the menu, and the tab key will move browser
+ // focus forward one element (by default)
+ } else if (event.key === 'Tab' || event.key === 'Enter' || event.key === 'Space') {
setIsAutocompleteOpen(false);
- if (event.key === "Enter" || event.key === 'Space') {
+ if (event.key === 'Enter' || event.key === 'Space') {
event.preventDefault();
}
}
- // If the autocomplete is open and the browser focus is in the autocomplete menu
- // hitting tab will close the autocomplete and but browser focus back on the search input.
- } else if (isAutocompleteOpen && autocompleteRef.current.contains(event.target) && (event.key === 'Tab')) {
+ // If the autocomplete is open and the browser focus is in the autocomplete menu
+ // hitting tab will close the autocomplete and but browser focus back on the search input.
+ } else if (isAutocompleteOpen && autocompleteRef.current.contains(event.target) && event.key === 'Tab') {
event.preventDefault();
setIsAutocompleteOpen(false);
searchInputRef.current.focus();
}
-
};
-
+
// The autocomplete menu should close if the user clicks outside the menu.
- const handleClickOutside = event => {
- if (isAutocompleteOpen && autocompleteRef && autocompleteRef.current && !autocompleteRef.current.contains(event.target)) {
+ const handleClickOutside = (event) => {
+ if (
+ isAutocompleteOpen &&
+ autocompleteRef &&
+ autocompleteRef.current &&
+ !autocompleteRef.current.contains(event.target)
+ ) {
setIsAutocompleteOpen(false);
}
};
-
+
React.useEffect(() => {
window.addEventListener('keydown', handleMenuKeys);
window.addEventListener('click', handleClickOutside);
@@ -147,7 +164,7 @@ SearchAutocomplete = () => {
window.removeEventListener('click', handleClickOutside);
};
}, [isAutocompleteOpen, hint, searchInputRef.current]);
-
+
const searchInput = (
{
id="autocomplete-search"
/>
);
-
+
const autocomplete = (
);
-
return (
{
### Composable advanced search
-This demo handles building the advanced search form using the composable Menu, as well as wiring up a
+This demo handles building the advanced search form using the composable Menu, as well as wiring up a
select using the composable Menu and MenuToggle components. This demo also demonstrates wiring up the appropriate
keyboard interactions, focus management, and general event handling.
@@ -195,14 +209,14 @@ Note: This demo and its handling of 'date within' and a date picker is modeled a
```js
import React from 'react';
-import {
+import {
ActionGroup,
- Button,
+ Button,
DatePicker,
- Form,
+ Form,
FormGroup,
Grid,
- GridItem,
+ GridItem,
isValidDate,
Menu,
MenuContent,
@@ -212,8 +226,8 @@ import {
Panel,
PanelMain,
PanelMainBody,
- Popper,
- SearchInput,
+ Popper,
+ SearchInput,
TextInput,
yyyyMMddFormat
} from '@patternfly/react-core';
@@ -223,25 +237,25 @@ AdvancedComposableSearchInput = () => {
const [hasWords, setHasWords] = React.useState('');
const [dateWithin, setDateWithin] = React.useState('1 day');
const [date, setDate] = React.useState();
-
+
const [isAdvancedSearchOpen, setIsAdvancedSearchOpen] = React.useState(false);
const [isDateWithinOpen, setIsDateWithinOpen] = React.useState(false);
-
+
const isInitialMount = React.useRef(true);
const firstAttrRef = React.useRef(null);
const searchInputRef = React.useRef(null);
const advancedSearchPaneRef = React.useRef(null);
const dateWithinToggleRef = React.useRef();
const dateWithinMenuRef = React.useRef();
-
+
const onClear = () => {
setValue('');
setHasWords('');
setDateWithin('');
setDate('');
};
-
- const onChange = (value) => {
+
+ const onChange = (_event, value) => {
if (value.length <= hasWords.length + 1) {
setValue(value);
setHasWords(value);
@@ -249,7 +263,7 @@ AdvancedComposableSearchInput = () => {
setValue(hasWords);
}
};
-
+
// After initial page load, whenever the advanced search menu is opened, the browser focus should be placed on the
// first advanced search form input. Whenever the advanced search menu is closed, the browser focus should
// be returned to the search input.
@@ -264,38 +278,51 @@ AdvancedComposableSearchInput = () => {
}
}
}, [isAdvancedSearchOpen]);
-
- // If a menu is open and has browser focus, then the escape key closes them and puts the browser focus onto their
+
+ // If a menu is open and has browser focus, then the escape key closes them and puts the browser focus onto their
// respective toggle. The 'date within' menu also needs to close when the 'tab' key is hit. However, hitting tab while
// focus is in the advanced search form should move the focus to the next form input, not close the advanced search
// menu.
- const handleMenuKeys = event => {
+ const handleMenuKeys = (event) => {
if (isDateWithinOpen && dateWithinMenuRef.current && dateWithinMenuRef.current.contains(event.target)) {
if (event.key === 'Escape' || event.key === 'Tab') {
setIsDateWithinOpen(!isDateWithinOpen);
dateWithinToggleRef.current.focus();
}
- }
+ }
if (isAdvancedSearchOpen && advancedSearchPaneRef.current && advancedSearchPaneRef.current.contains(event.target)) {
- if (event.key === 'Escape' ||
- (event.key === 'Tab' && !event.shiftKey && advancedSearchPaneRef.current.querySelector('button[type=reset]') === event.target)
+ if (
+ event.key === 'Escape' ||
+ (event.key === 'Tab' &&
+ !event.shiftKey &&
+ advancedSearchPaneRef.current.querySelector('button[type=reset]') === event.target)
) {
setIsAdvancedSearchOpen(!isAdvancedSearchOpen);
searchInputRef.current.focus();
}
- }
+ }
};
-
+
// If a menu is open and has browser focus, then clicking outside the menu should close it.
- const handleClickOutside = event => {
- if (isDateWithinOpen && dateWithinMenuRef && dateWithinMenuRef.current && !dateWithinMenuRef.current.contains(event.target)) {
+ const handleClickOutside = (event) => {
+ if (
+ isDateWithinOpen &&
+ dateWithinMenuRef &&
+ dateWithinMenuRef.current &&
+ !dateWithinMenuRef.current.contains(event.target)
+ ) {
setIsDateWithinOpen(false);
- }
- if (isAdvancedSearchOpen && advancedSearchPaneRef && advancedSearchPaneRef.current && !advancedSearchPaneRef.current.contains(event.target)) {
+ }
+ if (
+ isAdvancedSearchOpen &&
+ advancedSearchPaneRef &&
+ advancedSearchPaneRef.current &&
+ !advancedSearchPaneRef.current.contains(event.target)
+ ) {
setIsAdvancedSearchOpen(false);
}
};
-
+
React.useEffect(() => {
window.addEventListener('keydown', handleMenuKeys);
window.addEventListener('click', handleClickOutside);
@@ -304,12 +331,11 @@ AdvancedComposableSearchInput = () => {
window.removeEventListener('click', handleClickOutside);
};
}, [dateWithinMenuRef.current, advancedSearchPaneRef.current, isAdvancedSearchOpen, isDateWithinOpen]);
-
-
+
// This demo and its handling of 'date within' and a date picker is modeled after the gmail advanced search form.
const onSubmit = (event, value) => {
event.preventDefault();
-
+
if (isValidDate(new Date(date)) && dateWithin) {
let afterDate = new Date(date);
let toDate = new Date(date);
@@ -355,21 +381,21 @@ AdvancedComposableSearchInput = () => {
toDate.setDate(toDate.getDate() + 1);
break;
}
- setValue(`${hasWords && (hasWords + " ")}after:${yyyyMMddFormat(afterDate)} to:${yyyyMMddFormat(toDate)}`)
+ setValue(`${hasWords && hasWords + ' '}after:${yyyyMMddFormat(afterDate)} to:${yyyyMMddFormat(toDate)}`);
} else {
setValue(hasWords);
}
-
+
setIsAdvancedSearchOpen(false);
};
-
+
const searchInput = (
onChange(value)}
+ onChange={onChange}
onToggleAdvancedSearch={(e, isOpen) => {
e.stopPropagation();
- setIsAdvancedSearchOpen(isOpen)
+ setIsAdvancedSearchOpen(isOpen);
}}
isAdvancedSearchOpen={isAdvancedSearchOpen}
onClear={onClear}
@@ -378,10 +404,10 @@ AdvancedComposableSearchInput = () => {
id="custom-advanced-search"
/>
);
-
- // Clicking the 'date within' toggle should open its associated menu and then place the browser
- // focus on the first menu item.
- const toggleDateWithinMenu = ev => {
+
+ // Clicking the 'date within' toggle should open its associated menu and then place the browser
+ // focus on the first menu item.
+ const toggleDateWithinMenu = (ev) => {
ev.stopPropagation(); // Stop handleClickOutside from handling
setTimeout(() => {
if (dateWithinMenuRef.current) {
@@ -391,7 +417,7 @@ AdvancedComposableSearchInput = () => {
}, 0);
setIsDateWithinOpen(!isDateWithinOpen);
};
-
+
// Selecting a date within option closes the menu, sets the value of date within, and puts browser focus back
// on the date within toggle.
const onDateWithinSelect = (e, itemId) => {
@@ -402,7 +428,7 @@ AdvancedComposableSearchInput = () => {
dateWithinToggleRef.current.focus();
}
};
-
+
const dateWithinOptions = (
);
-
+
const dateWithinToggle = (
-
+
{dateWithin}
);
-
+
const advancedForm = (
-
+
@@ -484,7 +525,7 @@ AdvancedComposableSearchInput = () => {
popperRef={advancedSearchPaneRef}
isVisible={isAdvancedSearchOpen}
enableFlip={false}
- appendTo={() => document.querySelector("#custom-advanced-search")}
+ appendTo={() => document.querySelector('#custom-advanced-search')}
/>
);
};