UNPKG

@coocoon/react-awesome-query-builder

Version:

User-friendly query builder for React. Demo: https://ukrbublik.github.io/react-awesome-query-builder

143 lines (127 loc) 4.24 kB
import React, { useMemo } from "react"; import { Select, Spin, Divider } from "antd"; import { calcTextWidth, SELECT_WIDTH_OFFSET_RIGHT } from "../../../../utils/domUtils"; import { mapListValues } from "../../../../utils/stuff"; import { useOnPropsChanged } from "../../../../utils/reactUtils"; import omit from "lodash/omit"; import useListValuesAutocomplete from "../../../../hooks/useListValuesAutocomplete"; const Option = Select.Option; export default (props) => { const { config, placeholder, allowCustomValues, customProps, value, readonly, multiple, useAsyncSearch } = props; // hook const { open, onDropdownVisibleChange, onChange, isSpecialValue, onSearch, inputValue, options, isInitialLoading, isLoading, aPlaceholder, extendOptions, getOptionDisabled, getOptionLabel, } = useListValuesAutocomplete(props, { debounceTimeout: 100, multiple }); const filteredOptions = extendOptions(options); const optionsMaxWidth = useMemo(() => { return filteredOptions.reduce((max, option) => { return Math.max(max, calcTextWidth(option.title, null)); }, 0); }, [options]); const { defaultSelectWidth, defaultSearchWidth, renderSize } = config.settings; const placeholderWidth = calcTextWidth(placeholder); const aValue = value && value.length ? value : undefined; const width = aValue ? null : placeholderWidth + SELECT_WIDTH_OFFSET_RIGHT; const dropdownWidth = optionsMaxWidth + SELECT_WIDTH_OFFSET_RIGHT; const minWidth = width || defaultSelectWidth; const style = { width: (multiple ? undefined : minWidth), minWidth: minWidth }; const dropdownStyle = { width: dropdownWidth, }; const mode = !multiple ? undefined : (allowCustomValues ? "tags" : "multiple"); const dynamicPlaceholder = !readonly ? aPlaceholder : ""; // rendering special 'Load more' option has side effect: on change rc-select will save its title as internal value in own state const renderedOptions = filteredOptions?.filter(option => !option.specialValue).map((option) => ( <Option key={option.value} value={option.value} disabled={getOptionDisabled(option)} > {getOptionLabel(option)} </Option> )); const onSpecialClick = (specialValue) => () => { const option = filteredOptions.find(opt => opt.specialValue == specialValue); onChange(null, option); }; const specialOptions = filteredOptions?.filter(option => !!option.specialValue).map((option) => ( <a style={{ padding: "5px 10px", display: "block", cursor: "pointer" }} key={option.specialValue} disabled={getOptionDisabled(option)} onClick={onSpecialClick(option.specialValue)} > {getOptionLabel(option)} </a> )); const aOnSelect = async (label, option) => { if (isSpecialValue(option)) { await onChange(label, option); } }; const aOnChange = async (label, option) => { if (!isSpecialValue(option)) { await onChange(label, option); } }; const dropdownRender = (menu) => ( <div> {menu} {specialOptions.length > 0 && <> <Divider style={{ margin: "0px" }}/> <div style={{ display: "flex", flexDirection: "column" }}> {specialOptions} </div> </> } </div> ); return ( <Select filterOption={useAsyncSearch ? false : true} dropdownRender={dropdownRender} allowClear={true} notFoundContent={isLoading ? "Loading..." : null} disabled={readonly} mode={mode} style={customProps?.style || style} dropdownStyle={customProps?.dropdownStyle || dropdownStyle} key={"widget-autocomplete"} dropdownMatchSelectWidth={customProps?.dropdownMatchSelectWidth || false} placeholder={customProps?.placeholder || dynamicPlaceholder} onDropdownVisibleChange={onDropdownVisibleChange} onChange={aOnChange} onSelect={aOnSelect} onSearch={onSearch} showArrow showSearch size={renderSize} loading={isLoading} value={aValue} //searchValue={inputValue} open={open} {...customProps} > {renderedOptions} </Select> ); };