UNPKG

@grafana/ui

Version:
230 lines (228 loc) • 7.44 kB
import { jsx, jsxs } from 'react/jsx-runtime'; import { css } from '@emotion/css'; import memoize from 'micro-memoize'; import RCCascader from 'rc-cascader'; import { PureComponent } from 'react'; import '@grafana/data'; import { withTheme2 } from '../../themes/ThemeContext.mjs'; import '@emotion/react'; import 'tinycolor2'; import '../../utils/skeleton.mjs'; import { t } from '../../utils/i18n.mjs'; import { Icon } from '../Icon/Icon.mjs'; import { IconButton } from '../IconButton/IconButton.mjs'; import { Input } from '../Input/Input.mjs'; import { Stack } from '../Layout/Stack/Stack.mjs'; import { Select } from '../Select/Select.mjs'; import { onChangeCascader } from './optionMappings.mjs'; import { getCascaderStyles } from './styles.mjs'; const disableDivFocus = css({ "&:focus": { outline: "none" } }); const DEFAULT_SEPARATOR = " / "; class UnthemedCascader extends PureComponent { constructor(props) { super(props); this.flattenOptions = (options, optionPath = []) => { let selectOptions = []; for (const option of options) { const cpy = [...optionPath]; cpy.push(option); if (!option.items || option.items.length === 0) { selectOptions.push({ singleLabel: cpy[cpy.length - 1].label, label: cpy.map((o) => o.label).join(this.props.separator || DEFAULT_SEPARATOR), value: cpy.map((o) => o.value) }); } else { selectOptions = [...selectOptions, ...this.flattenOptions(option.items, cpy)]; } } return selectOptions; }; this.getSearchableOptions = memoize((options) => this.flattenOptions(options)); //For rc-cascader this.onChange = (value, selectedOptions) => { const activeLabel = this.props.hideActiveLevelLabel ? "" : this.props.displayAllSelectedLevels ? selectedOptions.map((option) => option.label).join(this.props.separator || DEFAULT_SEPARATOR) : selectedOptions[selectedOptions.length - 1].label; const state = { rcValue: { value, label: activeLabel }, focusCascade: true, activeLabel, isSearching: false, inputValue: activeLabel }; this.setState(state); this.props.onSelect(selectedOptions[selectedOptions.length - 1].value); }; //For select this.onSelect = (obj) => { const valueArray = obj.value || []; const activeLabel = this.props.displayAllSelectedLevels ? obj.label : obj.singleLabel || ""; const state = { activeLabel, inputValue: activeLabel, rcValue: { value: valueArray, label: activeLabel }, isSearching: false, focusCascade: false }; this.setState(state); this.props.onSelect(valueArray[valueArray.length - 1]); }; this.onCreateOption = (value) => { this.setState({ activeLabel: value, inputValue: value, rcValue: [], isSearching: false }); this.props.onSelect(value); }; this.onBlur = () => { var _a, _b; this.setState({ isSearching: false, focusCascade: false }); if (this.state.activeLabel === "") { this.setState({ rcValue: [] }); } (_b = (_a = this.props).onBlur) == null ? void 0 : _b.call(_a); }; this.onBlurCascade = () => { var _a, _b; this.setState({ focusCascade: false }); (_b = (_a = this.props).onBlur) == null ? void 0 : _b.call(_a); }; this.onInputKeyDown = (e) => { if (["ArrowDown", "ArrowUp", "Enter", "ArrowLeft", "ArrowRight"].includes(e.key)) { return; } const { activeLabel } = this.state; this.setState({ focusCascade: false, isSearching: true, inputValue: activeLabel }); }; this.onSelectInputChange = (value) => { this.setState({ inputValue: value }); }; const searchableOptions = this.getSearchableOptions(props.options); const { rcValue, activeLabel } = this.setInitialValue(searchableOptions, props.initialValue); this.state = { isSearching: false, focusCascade: false, rcValue, activeLabel, inputValue: "" }; } setInitialValue(searchableOptions, initValue) { if (!initValue) { return { rcValue: [], activeLabel: "" }; } for (const option of searchableOptions) { const optionPath = option.value || []; if (optionPath[optionPath.length - 1] === initValue) { return { rcValue: optionPath, activeLabel: this.props.displayAllSelectedLevels ? option.label : option.singleLabel || "" }; } } if (this.props.allowCustomValue) { return { rcValue: [], activeLabel: initValue }; } return { rcValue: [], activeLabel: "" }; } render() { const { allowCustomValue, formatCreateLabel, placeholder, width, changeOnSelect, options, disabled, id, isClearable, theme } = this.props; const { focusCascade, isSearching, rcValue, activeLabel, inputValue } = this.state; const searchableOptions = this.getSearchableOptions(options); const styles = getCascaderStyles(theme); return /* @__PURE__ */ jsx("div", { children: isSearching ? /* @__PURE__ */ jsx( Select, { allowCustomValue, placeholder, autoFocus: !focusCascade, onChange: this.onSelect, onBlur: this.onBlur, options: searchableOptions, onCreateOption: this.onCreateOption, formatCreateLabel, width, onInputChange: this.onSelectInputChange, disabled, inputValue, inputId: id } ) : /* @__PURE__ */ jsx( RCCascader, { onChange: onChangeCascader(this.onChange), options, changeOnSelect, value: rcValue.value, fieldNames: { label: "label", value: "value", children: "items" }, expandIcon: null, open: this.props.alwaysOpen, disabled, dropdownClassName: styles.dropdown, children: /* @__PURE__ */ jsx("div", { className: disableDivFocus, children: /* @__PURE__ */ jsx( Input, { autoFocus: this.props.autoFocus, width, placeholder, onBlur: this.onBlurCascade, value: activeLabel, onKeyDown: this.onInputKeyDown, onChange: () => { }, suffix: /* @__PURE__ */ jsxs(Stack, { gap: 0.5, children: [ isClearable && activeLabel !== "" && /* @__PURE__ */ jsx( IconButton, { name: "times", "aria-label": t("grafana-ui.cascader.clear-button", "Clear selection"), onClick: (e) => { e.preventDefault(); e.stopPropagation(); this.setState({ rcValue: [], activeLabel: "", inputValue: "" }); this.props.onSelect(""); } } ), /* @__PURE__ */ jsx(Icon, { name: focusCascade ? "angle-up" : "angle-down" }) ] }), disabled, id } ) }) } ) }); } } UnthemedCascader.defaultProps = { changeOnSelect: true }; withTheme2(UnthemedCascader); //# sourceMappingURL=Cascader.mjs.map