UNPKG

@patternfly/react-core

Version:

This library provides a set of common React components for use with the PatternFly reference implementation.

171 lines • 12.4 kB
import { __rest } from "tslib"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { forwardRef, useEffect, useRef, useState } from 'react'; import { css } from '@patternfly/react-styles'; import { Button, ButtonVariant } from '../Button'; import { Badge } from '../Badge'; import { Icon } from '../Icon'; import AngleDownIcon from '@patternfly/react-icons/dist/esm/icons/angle-down-icon'; import AngleUpIcon from '@patternfly/react-icons/dist/esm/icons/angle-up-icon'; import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon'; import CaretDownIcon from '@patternfly/react-icons/dist/esm/icons/caret-down-icon'; import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon'; import { AdvancedSearchMenu } from './AdvancedSearchMenu'; import { TextInputGroup, TextInputGroupMain, TextInputGroupUtilities } from '../TextInputGroup'; import { InputGroup, InputGroupItem } from '../InputGroup'; import { Popper } from '../../helpers'; import textInputGroupStyles from '@patternfly/react-styles/css/components/TextInputGroup/text-input-group.mjs'; const SearchInputBase = (_a) => { var { className, searchInputId, value = '', attributes = [], formAdditionalItems, hasWordsAttrLabel = 'Has words', advancedSearchDelimiter, placeholder, hint, onChange, onSearch, onClear, onToggleAdvancedSearch, isAdvancedSearchOpen = false, resultsCount, onNextClick, onPreviousClick, innerRef, expandableInput, 'aria-label': ariaLabel = 'Search input', resetButtonLabel = 'Reset', openMenuButtonAriaLabel = 'Open advanced search', previousNavigationButtonAriaLabel = 'Previous', isPreviousNavigationButtonDisabled = false, isNextNavigationButtonDisabled = false, nextNavigationButtonAriaLabel = 'Next', submitSearchButtonLabel = 'Search', isDisabled = false, appendTo, zIndex = 9999, name, areUtilitiesDisplayed, inputProps } = _a, props = __rest(_a, ["className", "searchInputId", "value", "attributes", "formAdditionalItems", "hasWordsAttrLabel", "advancedSearchDelimiter", "placeholder", "hint", "onChange", "onSearch", "onClear", "onToggleAdvancedSearch", "isAdvancedSearchOpen", "resultsCount", "onNextClick", "onPreviousClick", "innerRef", "expandableInput", 'aria-label', "resetButtonLabel", "openMenuButtonAriaLabel", "previousNavigationButtonAriaLabel", "isPreviousNavigationButtonDisabled", "isNextNavigationButtonDisabled", "nextNavigationButtonAriaLabel", "submitSearchButtonLabel", "isDisabled", "appendTo", "zIndex", "name", "areUtilitiesDisplayed", "inputProps"]); const [isSearchMenuOpen, setIsSearchMenuOpen] = useState(false); const [searchValue, setSearchValue] = useState(value); const searchInputRef = useRef(null); const ref = useRef(null); const searchInputInputRef = innerRef || ref; const searchInputExpandableToggleRef = useRef(null); const triggerRef = useRef(null); const popperRef = useRef(null); const [focusAfterExpandChange, setFocusAfterExpandChange] = useState(false); const { isExpanded, onToggleExpand, toggleAriaLabel } = expandableInput || {}; useEffect(() => { var _a, _b; // this effect and the focusAfterExpandChange variable are needed to focus the input/toggle as needed when the // expansion toggle is fired without focusing on mount if (!focusAfterExpandChange) { return; } else if (isExpanded) { (_a = searchInputInputRef === null || searchInputInputRef === void 0 ? void 0 : searchInputInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); } else { (_b = searchInputExpandableToggleRef === null || searchInputExpandableToggleRef === void 0 ? void 0 : searchInputExpandableToggleRef.current) === null || _b === void 0 ? void 0 : _b.focus(); } setFocusAfterExpandChange(false); }, [focusAfterExpandChange, isExpanded, searchInputInputRef, searchInputExpandableToggleRef]); useEffect(() => { setSearchValue(value); }, [value]); useEffect(() => { if (attributes.length > 0 && !advancedSearchDelimiter) { // eslint-disable-next-line no-console console.error('An advancedSearchDelimiter prop is required when advanced search attributes are provided using the attributes prop'); } }); useEffect(() => { setIsSearchMenuOpen(isAdvancedSearchOpen); }, [isAdvancedSearchOpen]); const onChangeHandler = (event, value) => { if (onChange) { onChange(event, value); } setSearchValue(value); }; const onToggle = (e) => { const isOpen = !isSearchMenuOpen; setIsSearchMenuOpen(isOpen); if (onToggleAdvancedSearch) { onToggleAdvancedSearch(e, isOpen); } }; const onSearchHandler = (event) => { event.preventDefault(); if (onSearch) { onSearch(event, value, getAttrValueMap()); } setIsSearchMenuOpen(false); }; const splitStringExceptInQuotes = (str) => { let quoteType; return str.match(/\\?.|^$/g).reduce((p, c) => { if (c === "'" || c === '"') { if (!quoteType) { quoteType = c; } if (c === quoteType) { p.quote = !p.quote; } } else if (!p.quote && c === ' ') { p.a.push(''); } else { p.a[p.a.length - 1] += c.replace(/\\(.)/, '$1'); } return p; }, { a: [''] }).a; }; const getAttrValueMap = () => { const attrValue = {}; const pairs = splitStringExceptInQuotes(searchValue); pairs.map((pair) => { const splitPair = pair.split(advancedSearchDelimiter); if (splitPair.length === 2) { attrValue[splitPair[0]] = splitPair[1].replace(/(^'|'$)/g, ''); } else if (splitPair.length === 1) { attrValue.haswords = attrValue.hasOwnProperty('haswords') ? `${attrValue.haswords} ${splitPair[0]}` : splitPair[0]; } }); return attrValue; }; const onEnter = (event) => { if (event.key === 'Enter') { onSearchHandler(event); } }; const onClearInput = (e) => { if (onClear) { onClear(e); } if (searchInputInputRef && searchInputInputRef.current) { searchInputInputRef.current.focus(); } }; const onExpandHandler = (event) => { setSearchValue(''); onToggleExpand(event, isExpanded); setFocusAfterExpandChange(true); }; const renderUtilities = value && (resultsCount || (!!onNextClick && !!onPreviousClick) || (!!onClear && !expandableInput)); const buildTextInputGroup = (_a = {}) => { var searchInputProps = __rest(_a, []); return (_jsxs(TextInputGroup, Object.assign({ isDisabled: isDisabled }, searchInputProps, { children: [_jsx(TextInputGroupMain, { hint: hint, icon: _jsx(SearchIcon, {}), innerRef: searchInputInputRef, value: searchValue, placeholder: placeholder, "aria-label": ariaLabel, onKeyDown: onEnter, onChange: onChangeHandler, name: name, inputId: searchInputId, inputProps: inputProps }), (renderUtilities || areUtilitiesDisplayed) && (_jsxs(TextInputGroupUtilities, { children: [resultsCount && _jsx(Badge, { isRead: true, children: resultsCount }), !!onNextClick && !!onPreviousClick && (_jsxs("div", { className: textInputGroupStyles.textInputGroupGroup, children: [_jsx(Button, { variant: ButtonVariant.plain, "aria-label": previousNavigationButtonAriaLabel, isDisabled: isDisabled || isPreviousNavigationButtonDisabled, onClick: onPreviousClick, icon: _jsx(AngleUpIcon, {}) }), _jsx(Button, { variant: ButtonVariant.plain, "aria-label": nextNavigationButtonAriaLabel, isDisabled: isDisabled || isNextNavigationButtonDisabled, onClick: onNextClick, icon: _jsx(AngleDownIcon, {}) })] })), !!onClear && !expandableInput && (_jsx(Button, { variant: ButtonVariant.plain, isDisabled: isDisabled, "aria-label": resetButtonLabel, onClick: onClearInput, icon: _jsx(TimesIcon, {}) }))] }))] }))); }; const expandableToggle = (_jsx(Button, { variant: ButtonVariant.plain, "aria-label": toggleAriaLabel, "aria-expanded": isExpanded, icon: isExpanded ? _jsx(TimesIcon, {}) : _jsx(SearchIcon, {}), onClick: onExpandHandler, ref: searchInputExpandableToggleRef })); const buildExpandableSearchInput = (_a = {}) => { var searchInputProps = __rest(_a, []); return (_jsxs(InputGroup, Object.assign({}, searchInputProps, { children: [_jsxs(InputGroupItem, { isFill: true, children: [buildTextInputGroup(), " "] }), _jsx(InputGroupItem, { isPlain: true, children: expandableToggle })] }))); }; const buildSearchTextInputGroup = (_a = {}) => { var searchInputProps = __rest(_a, []); if (expandableInput) { return buildExpandableSearchInput(Object.assign({}, searchInputProps)); } return buildTextInputGroup(Object.assign({}, searchInputProps)); }; const buildSearchTextInputGroupWithExtraButtons = (_a = {}) => { var searchInputProps = __rest(_a, []); return (_jsxs(InputGroup, Object.assign({ ref: triggerRef }, searchInputProps, { children: [_jsx(InputGroupItem, { isFill: true, children: buildTextInputGroup() }), (attributes.length > 0 || onToggleAdvancedSearch) && (_jsx(InputGroupItem, { isPlain: true, children: _jsx(Button, { className: isSearchMenuOpen && 'pf-m-expanded', variant: ButtonVariant.control, "aria-label": openMenuButtonAriaLabel, onClick: onToggle, isDisabled: isDisabled, "aria-expanded": isSearchMenuOpen, icon: _jsx(CaretDownIcon, {}) }) })), !!onSearch && (_jsx(InputGroupItem, { children: _jsx(Button, { type: "submit", variant: ButtonVariant.control, "aria-label": submitSearchButtonLabel, onClick: onSearchHandler, isDisabled: isDisabled, icon: _jsx(Icon, { shouldMirrorRTL: true, children: _jsx(ArrowRightIcon, {}) }) }) })), expandableInput && _jsx(InputGroupItem, { children: expandableToggle })] }))); }; const searchInputProps = Object.assign(Object.assign({}, props), { className: className && css(className), innerRef: searchInputRef }); if (!!expandableInput && !isExpanded) { return (_jsx(InputGroup, Object.assign({}, searchInputProps, { children: _jsx(InputGroupItem, { children: expandableToggle }) }))); } if (!!onSearch || attributes.length > 0 || !!onToggleAdvancedSearch) { if (attributes.length > 0) { const AdvancedSearch = (_jsx("div", { ref: popperRef, children: _jsx(AdvancedSearchMenu, { value: value, parentRef: searchInputRef, parentInputRef: searchInputInputRef, onSearch: onSearch, onClear: onClear, onChange: onChange, onToggleAdvancedMenu: onToggle, resetButtonLabel: resetButtonLabel, submitSearchButtonLabel: submitSearchButtonLabel, attributes: attributes, formAdditionalItems: formAdditionalItems, hasWordsAttrLabel: hasWordsAttrLabel, advancedSearchDelimiter: advancedSearchDelimiter, getAttrValueMap: getAttrValueMap, isSearchMenuOpen: isSearchMenuOpen }) })); const AdvancedSearchWithPopper = (_jsx("div", Object.assign({ className: css(className), ref: searchInputRef }, props, { children: _jsx(Popper, { trigger: buildSearchTextInputGroupWithExtraButtons(), triggerRef: triggerRef, popper: AdvancedSearch, popperRef: popperRef, isVisible: isSearchMenuOpen, enableFlip: true, appendTo: () => appendTo || searchInputRef.current, zIndex: zIndex }) }))); const AdvancedSearchInline = (_jsxs("div", Object.assign({ className: css(className), ref: searchInputRef }, props, { children: [buildSearchTextInputGroupWithExtraButtons(), AdvancedSearch] }))); return appendTo !== 'inline' ? AdvancedSearchWithPopper : AdvancedSearchInline; } return buildSearchTextInputGroupWithExtraButtons(Object.assign({}, searchInputProps)); } return buildSearchTextInputGroup(searchInputProps); }; SearchInputBase.displayName = 'SearchInputBase'; export const SearchInput = forwardRef((props, ref) => (_jsx(SearchInputBase, Object.assign({}, props, { innerRef: ref })))); SearchInput.displayName = 'SearchInput'; //# sourceMappingURL=SearchInput.js.map