@geezee/react-ui
Version:
Modern and minimalist React UI library.
251 lines (222 loc) • 10.1 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _JSXStyle from "styled-jsx/style";
import React, { useEffect, useMemo, useRef, useState, useImperativeHandle } from 'react';
import Input, { defaultProps as inputDefaultProps } from '../input/input';
import { useAutoCompleteHandle } from '../input/use-input-handle';
import Loading from '../loading';
import CSSTransition, { defaultProps as CSSTransitionDefaultProps } from '../shared/css-transition';
import { pickChild } from '../utils/collections';
import useClickAway from '../utils/use-click-away';
import { AutoCompleteContext } from './auto-complete-context';
import AutoCompleteDropdown from './auto-complete-dropdown';
import AutoCompleteEmpty from './auto-complete-empty';
import AutoCompleteItem from './auto-complete-item';
import AutoCompleteSearching from './auto-complete-searching';
var DEFAULT_CSS_TRANSITION_LEAVE_TIME = CSSTransitionDefaultProps.leaveTime + CSSTransitionDefaultProps.clearTime;
export var defaultProps = Object.assign({}, inputDefaultProps, {
width: 'max-content',
defaultOpen: false,
options: [],
disableMatchWidth: false,
disableFreeSolo: false
});
var childrenToOptionsNode = function childrenToOptionsNode(options, variant) {
return options.map(function (item, index) {
var key = "auto-complete-item-".concat(index);
if (React.isValidElement(item)) return React.cloneElement(item, {
key: key
});
var validItem = item;
return /*#__PURE__*/React.createElement(AutoCompleteItem, {
variant: variant,
key: key,
label: validItem.label,
isLabelOnly: true
});
});
}; // When the search is not set, the "clearable" icon can be displayed in the original location.
// When the search is set, at least one element should exist to avoid re-render.
var getSearchIcon = function getSearchIcon(searching) {
if (searching === undefined) return null;
return searching ? /*#__PURE__*/React.createElement(Loading, {
size: "small"
}) : /*#__PURE__*/React.createElement("span", null);
};
var AutoComplete = React.forwardRef(function (_ref, ref) {
var variant = _ref.variant,
options = _ref.options,
defaultValue = _ref.defaultValue,
onSelect = _ref.onSelect,
onSearch = _ref.onSearch,
onChange = _ref.onChange,
searching = _ref.searching,
onClearClick = _ref.onClearClick,
children = _ref.children,
size = _ref.size,
value = _ref.value,
width = _ref.width,
clearable = _ref.clearable,
disabled = _ref.disabled,
dropdownClassName = _ref.dropdownClassName,
dropdownStyle = _ref.dropdownStyle,
disableMatchWidth = _ref.disableMatchWidth,
disableFreeSolo = _ref.disableFreeSolo,
open = _ref.open,
onFocus = _ref.onFocus,
onBlur = _ref.onBlur,
defaultOpen = _ref.defaultOpen,
props = _objectWithoutProperties(_ref, ["variant", "options", "defaultValue", "onSelect", "onSearch", "onChange", "searching", "onClearClick", "children", "size", "value", "width", "clearable", "disabled", "dropdownClassName", "dropdownStyle", "disableMatchWidth", "disableFreeSolo", "open", "onFocus", "onBlur", "defaultOpen"]);
var isValueControlled = value !== undefined;
var isOpenControlled = open !== undefined;
var autoCompleteDivRef = useRef(null);
var _useAutoCompleteHandl = useAutoCompleteHandle(),
inputRef = _useAutoCompleteHandl.ref,
focusInput = _useAutoCompleteHandl.focus;
useImperativeHandle(ref, function () {
return inputRef.current;
});
var resetTimer = useRef();
var _useState = useState(defaultValue || ''),
_useState2 = _slicedToArray(_useState, 2),
inputValue = _useState2[0],
setInputValue = _useState2[1];
var computedInputValue = isValueControlled ? value : inputValue;
var _useState3 = useState(defaultValue || ''),
_useState4 = _slicedToArray(_useState3, 2),
selectVal = _useState4[0],
setSelectVal = _useState4[1];
var _useState5 = useState(defaultOpen),
_useState6 = _slicedToArray(_useState5, 2),
dropdownOpen = _useState6[0],
setDropdownOpen = _useState6[1];
var isDropdownOpen = isOpenControlled ? open : dropdownOpen;
var _useState7 = useState(false),
_useState8 = _slicedToArray(_useState7, 2),
focus = _useState8[0],
setFocus = _useState8[1];
var _pickChild = pickChild(children, AutoCompleteSearching),
_pickChild2 = _slicedToArray(_pickChild, 2),
searchChild = _pickChild2[1];
var _pickChild3 = pickChild(children, AutoCompleteEmpty),
_pickChild4 = _slicedToArray(_pickChild3, 2),
emptyChild = _pickChild4[1];
var autoCompleteItems = useMemo(function () {
var hasSearchChild = searchChild && React.Children.count(searchChild) > 0;
var hasEmptyChild = emptyChild && React.Children.count(emptyChild) > 0;
if (searching) {
return hasSearchChild ? searchChild : /*#__PURE__*/React.createElement(AutoCompleteSearching, null, "Searching...");
}
if (options.length === 0) {
if (computedInputValue === '') return null;
return hasEmptyChild ? emptyChild : /*#__PURE__*/React.createElement(AutoCompleteEmpty, null, "No Options");
}
return childrenToOptionsNode(options, variant);
}, [searching, options, variant]);
var showClearIcon = useMemo(function () {
return clearable && searching === undefined;
}, [clearable, searching]);
var onSelectHandler = function onSelectHandler(val) {
if (disabled) return;
setSelectVal(val);
onSelect && onSelect(val);
if (!isValueControlled) setInputValue(val);
focusInput();
};
var onInputChange = function onInputChange(event) {
if (!isOpenControlled) setDropdownOpen(true);
if (!isValueControlled) setInputValue(event.target.value);
onSearch && onSearch(event.target.value);
};
var resetInputValueOnClickAway = function resetInputValueOnClickAway() {
if (isValueControlled) return;
if (!disableFreeSolo) return;
if (!computedInputValue || computedInputValue === '') return;
if (computedInputValue !== selectVal) {
setInputValue(selectVal);
}
};
var defaultContextValue = useMemo(function () {
return {
ref: autoCompleteDivRef,
size: size,
focus: focus,
value: computedInputValue,
onSelect: onSelectHandler,
visible: isDropdownOpen,
updateVisible: function updateVisible(open) {
if (!isOpenControlled) setDropdownOpen(open);
}
};
}, [computedInputValue, isDropdownOpen, size, focus]);
var onInputFocus = function onInputFocus(e) {
setFocus(true);
onFocus && onFocus(e);
if (!isOpenControlled) setDropdownOpen(true);
clearTimeout(resetTimer.current);
};
var onInputClearClick = function onInputClearClick(event) {
if (!isValueControlled) setInputValue('');
onClearClick && onClearClick(event);
};
useClickAway(autoCompleteDivRef, function (e) {
if (!isOpenControlled) setDropdownOpen(false);
resetTimer.current = window.setTimeout(function () {
resetInputValueOnClickAway();
clearTimeout(resetTimer.current);
onBlur && onBlur(e);
setFocus(false);
}, DEFAULT_CSS_TRANSITION_LEAVE_TIME);
});
var inputProps = _extends(_extends({}, props), {}, {
value: computedInputValue,
defaultValue: undefined,
width: width,
disabled: disabled
});
var dropdownVisible = isOpenControlled ? open : dropdownOpen && Boolean(autoCompleteItems);
useEffect(function () {
onChange && onChange(computedInputValue);
}, [computedInputValue]);
return /*#__PURE__*/React.createElement(AutoCompleteContext.Provider, {
value: defaultContextValue
}, /*#__PURE__*/React.createElement("div", {
ref: autoCompleteDivRef,
className: _JSXStyle.dynamic([["297735136", [width]]]) + " " + "auto-complete ".concat(variant === 'solid' ? 'solid' : 'line')
}, /*#__PURE__*/React.createElement(CSSTransition, {
renderable: true,
visible: dropdownVisible,
clearTime: computedInputValue === '' ? 0 : 60,
leaveTime: computedInputValue === '' ? 0 : 60,
className: "in-auto-complete ".concat(focus ? 'auto-complete-focus' : '')
}, /*#__PURE__*/React.createElement(Input, _extends({
variant: variant,
ref: inputRef,
size: size,
onChange: onInputChange,
onFocus: onInputFocus,
onClick: onInputFocus,
clearable: showClearIcon,
onClearClick: onInputClearClick,
iconRight: getSearchIcon(searching)
}, inputProps))), /*#__PURE__*/React.createElement(AutoCompleteDropdown, {
variant: variant,
visible: dropdownVisible,
disableMatchWidth: disableMatchWidth,
className: dropdownClassName,
dropdownStyle: dropdownStyle
}, autoCompleteItems), /*#__PURE__*/React.createElement(_JSXStyle, {
id: "297735136",
dynamic: [width]
}, ".auto-complete.__jsx-style-dynamic-selector{width:".concat(width, ";}.auto-complete.__jsx-style-dynamic-selector .loading{left:-3px;right:-3px;width:-webkit-max-content;width:-moz-max-content;width:max-content;}.auto-complete.__jsx-style-dynamic-selector .in-auto-complete .input-wrapper{-webkit-transition:0s;transition:0s;}.auto-complete.__jsx-style-dynamic-selector .in-auto-complete.transition-leave .input-wrapper.focus:not(.disabled),.auto-complete.__jsx-style-dynamic-selector .in-auto-complete.transition-enter .input-wrapper.focus:not(.disabled){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-color:transparent;}"))));
});
var AutoCompleteComponent = AutoComplete;
AutoCompleteComponent.defaultProps = defaultProps;
AutoCompleteComponent.Item = AutoCompleteItem;
AutoCompleteComponent.Option = AutoCompleteItem;
AutoCompleteComponent.Searching = AutoCompleteSearching;
AutoCompleteComponent.Empty = AutoCompleteEmpty;
AutoCompleteComponent.useAutoCompleteHandle = useAutoCompleteHandle;
export { useAutoCompleteHandle };
export default AutoCompleteComponent;