UNPKG

@coocoon/react-awesome-query-builder

Version:

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

151 lines (133 loc) 4.78 kB
import React, { PureComponent } from "react"; import { Tooltip, TreeSelect } from "antd"; import {BUILT_IN_PLACEMENTS, SELECT_WIDTH_OFFSET_RIGHT, calcTextWidth} from "../../../../utils/domUtils"; import {useOnPropsChanged} from "../../../../utils/reactUtils"; import PropTypes from "prop-types"; export default class FieldTreeSelect extends PureComponent { static propTypes = { config: PropTypes.object.isRequired, customProps: PropTypes.object, items: PropTypes.array.isRequired, placeholder: PropTypes.string, selectedKey: PropTypes.string, selectedKeys: PropTypes.array, selectedPath: PropTypes.array, selectedLabel: PropTypes.string, selectedAltLabel: PropTypes.string, selectedFullLabel: PropTypes.string, selectedOpts: PropTypes.object, readonly: PropTypes.bool, //actions setField: PropTypes.func.isRequired, }; constructor(props) { super(props); useOnPropsChanged(this); this.onPropsChanged(props); } onPropsChanged(props) { const { items, config: {settings: {fieldSeparator}}} = props; let optionsMaxWidth = 0; const initialOffset = 24; // arrow + checkbox for leftmost item const offset = 20; const padding = 5 * 2; this.treeData = this.getTreeData(items, ({label, path}) => { optionsMaxWidth = Math.max(optionsMaxWidth, calcTextWidth(label, null) + padding + (path.split(fieldSeparator).length - 1) * offset + initialOffset ); }); this.optionsMaxWidth = optionsMaxWidth; } getTreeData(fields, fn = null) { return fields.map(field => { const {items, key, path, label, fullLabel, altLabel, tooltip, disabled} = field; if (fn) fn(field); const pathKey = path || key; const option = tooltip ? <Tooltip title={tooltip}>{label}</Tooltip> : label; if (items) { return { value: pathKey, title: option, children: this.getTreeData(items, fn), selectable: false, altLabel: altLabel, fullLabel: fullLabel, label: label, disabled: disabled, }; } else { return { value: pathKey, title: option, altLabel: altLabel, fullLabel: fullLabel, label: label, disabled: disabled, }; } }); } onChange = (key) => { this.props.setField(key); }; filterTreeNode = (input, option) => { const dataForFilter = option; const keysForFilter = ["title", "value", "label", "altLabel", "fullLabel"]; const valueForFilter = keysForFilter .map(k => (typeof dataForFilter[k] == "string" ? dataForFilter[k] : "")) .join("\0"); return valueForFilter.toLowerCase().indexOf(input.toLowerCase()) >= 0; }; render() { const { config, customProps = {}, placeholder, selectedKey, selectedLabel, selectedOpts, selectedAltLabel, selectedFullLabel, readonly, } = this.props; const { renderSize, fieldSeparator } = config.settings; let tooltipText = selectedAltLabel || selectedFullLabel; if (tooltipText == selectedLabel) tooltipText = null; const selectedPath = selectedKey ? selectedKey.split(fieldSeparator) : null; const treeDefaultExpandedKeys = selectedPath && selectedPath.length > 1 ? selectedPath.slice(0, -1).map((_key, i) => (selectedPath.slice(0, i+1).join(fieldSeparator))) : null; const placeholderWidth = calcTextWidth(placeholder) + 6; const isFieldSelected = !!selectedKey; const minWidth = placeholderWidth + SELECT_WIDTH_OFFSET_RIGHT; const dropdownMinWidth = 100; const dropdownMaxWidth = 800; const useAutoWidth = true; //tip: "auto" is good, but width will jump on expand/collapse const dropdownWidth = Math.max(dropdownMinWidth, Math.min(dropdownMaxWidth, this.optionsMaxWidth)); let res = ( <TreeSelect onChange={this.onChange} value={selectedKey || undefined} style={{ minWidth: minWidth, width: isFieldSelected ? null : minWidth, }} dropdownStyle={{ width: useAutoWidth ? "auto" : dropdownWidth + 20, paddingRight: "10px" }} multiple={false} treeCheckable={false} treeDataSimpleMode={false} treeData={this.treeData} size={renderSize} placeholder={placeholder} filterTreeNode={this.filterTreeNode} treeDefaultExpandedKeys={treeDefaultExpandedKeys} dropdownMatchSelectWidth={false} disabled={readonly} {...customProps} /> ); if (tooltipText && !selectedOpts.tooltip) { res = <Tooltip title={tooltipText}>{res}</Tooltip>; } return res; } }