@grafana/ui
Version:
Grafana Components Library
238 lines (231 loc) • 8.31 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
var RCCascader = require('@rc-component/cascader');
var React = require('react');
var i18n = require('@grafana/i18n');
var ThemeContext = require('../../themes/ThemeContext.cjs');
var Icon = require('../Icon/Icon.cjs');
var IconButton = require('../IconButton/IconButton.cjs');
var Input = require('../Input/Input.cjs');
var Stack = require('../Layout/Stack/Stack.cjs');
var Select = require('../Select/Select.cjs');
var optionMappings = require('./optionMappings.cjs');
var styles = require('./styles.cjs');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var RCCascader__default = /*#__PURE__*/_interopDefaultCompat(RCCascader);
"use strict";
const disableDivFocus = css.css({
"&:focus": {
outline: "none"
}
});
const DEFAULT_SEPARATOR = " / ";
const flattenOptions = (options, optionPath = [], separator) => {
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(separator || DEFAULT_SEPARATOR),
value: cpy.map((o) => o.value)
});
} else {
selectOptions = [...selectOptions, ...flattenOptions(option.items, cpy, separator)];
}
}
return selectOptions;
};
const Cascader = React.memo(
({
separator,
placeholder,
options,
changeOnSelect = true,
onSelect,
width,
initialValue,
allowCustomValue,
formatCreateLabel,
displayAllSelectedLevels,
onBlur,
autoFocus,
alwaysOpen,
hideActiveLevelLabel,
disabled,
id,
isClearable,
"data-testid": dataTestId
}) => {
const searchableOptions = React.useMemo(() => flattenOptions(options, [], separator), [options, separator]);
const getInitialValue = React.useCallback(
(searchableOptions2, initValue) => {
if (!initValue) {
return {
initialRCValue: { value: [], label: "" },
initialActiveLabel: ""
};
}
for (const option of searchableOptions2) {
const optionPath = option.value || [];
if (optionPath[optionPath.length - 1] === initValue) {
const label = displayAllSelectedLevels ? option.label : option.singleLabel || "";
return {
initialRCValue: { value: optionPath, label },
initialActiveLabel: label
};
}
}
if (allowCustomValue) {
return {
initialRCValue: { value: [], label: initValue },
initialActiveLabel: initValue
};
}
return {
initialRCValue: { value: [], label: "" },
initialActiveLabel: ""
};
},
[allowCustomValue, displayAllSelectedLevels]
);
const { initialRCValue, initialActiveLabel } = React.useMemo(
() => getInitialValue(searchableOptions, initialValue),
[getInitialValue, initialValue, searchableOptions]
);
const [isSearching, setIsSearching] = React.useState(false);
const [focusCascade, setFocusCascade] = React.useState(false);
const [rcValue, setRcValue] = React.useState(initialRCValue);
const [activeLabel, setActiveLabel] = React.useState(initialActiveLabel);
const [inputValue, setInputValue] = React.useState("");
const styles$1 = ThemeContext.useStyles2(styles.getCascaderStyles);
const handleChange = (value, selectedOptions) => {
const activeLabel2 = hideActiveLevelLabel ? "" : displayAllSelectedLevels ? selectedOptions.map((option) => option.label).join(separator || DEFAULT_SEPARATOR) : selectedOptions[selectedOptions.length - 1].label;
setRcValue({ value, label: activeLabel2 });
setFocusCascade(true);
setActiveLabel(activeLabel2);
setIsSearching(false);
setInputValue(activeLabel2);
onSelect(selectedOptions[selectedOptions.length - 1].value);
};
const handleSelect = (obj) => {
const valueArray = obj.value || [];
const activeLabel2 = displayAllSelectedLevels ? obj.label : obj.singleLabel || "";
setActiveLabel(activeLabel2);
setInputValue(activeLabel2);
setRcValue({ value: valueArray, label: activeLabel2 });
setIsSearching(false);
setFocusCascade(false);
onSelect(valueArray[valueArray.length - 1]);
};
const handleCreateOption = (value) => {
setActiveLabel(value);
setInputValue(value);
setRcValue({ value: [], label: value });
setIsSearching(false);
onSelect(value);
};
const handleBlur = () => {
setIsSearching(false);
setFocusCascade(false);
if (activeLabel === "") {
setRcValue({ value: [], label: "" });
}
onBlur == null ? void 0 : onBlur();
};
const handleBlurCascade = () => {
setFocusCascade(false);
onBlur == null ? void 0 : onBlur();
};
const handleInputKeyDown = (e) => {
if (["ArrowDown", "ArrowUp", "Enter", "ArrowLeft", "ArrowRight"].includes(e.key)) {
return;
}
const selectionStart = e.currentTarget.selectionStart;
const selectionEnd = e.currentTarget.selectionEnd;
let inputValue2 = e.currentTarget.value;
if (selectionStart !== selectionEnd) {
inputValue2 = inputValue2.substring(0, selectionStart != null ? selectionStart : 0) + inputValue2.substring(selectionEnd != null ? selectionEnd : 0);
}
setFocusCascade(false);
setIsSearching(true);
setInputValue(inputValue2);
};
const handleSelectInputChange = (value) => {
setInputValue(value);
};
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": dataTestId, children: isSearching ? /* @__PURE__ */ jsxRuntime.jsx(
Select.Select,
{
allowCustomValue,
placeholder,
autoFocus: !focusCascade,
onChange: handleSelect,
onBlur: handleBlur,
options: searchableOptions,
onCreateOption: handleCreateOption,
formatCreateLabel,
width,
onInputChange: handleSelectInputChange,
disabled,
inputValue,
inputId: id
}
) : /* @__PURE__ */ jsxRuntime.jsx(
RCCascader__default.default,
{
onChange: optionMappings.onChangeCascader(handleChange),
options,
changeOnSelect,
value: rcValue.value,
fieldNames: { label: "label", value: "value", children: "items" },
expandIcon: null,
open: alwaysOpen,
disabled,
popupClassName: styles$1.dropdown,
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: disableDivFocus, children: /* @__PURE__ */ jsxRuntime.jsx(
Input.Input,
{
autoFocus,
width,
placeholder,
onBlur: handleBlurCascade,
value: activeLabel,
onFocus: (e) => {
e.currentTarget.select();
},
onKeyDown: handleInputKeyDown,
onChange: () => {
},
suffix: /* @__PURE__ */ jsxRuntime.jsxs(Stack.Stack, { gap: 0.5, children: [
isClearable && activeLabel !== "" && /* @__PURE__ */ jsxRuntime.jsx(
IconButton.IconButton,
{
name: "times",
"aria-label": i18n.t("grafana-ui.cascader.clear-button", "Clear selection"),
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
setRcValue({ value: [], label: "" });
setActiveLabel("");
setInputValue("");
onSelect("");
}
}
),
/* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: focusCascade ? "angle-up" : "angle-down" })
] }),
disabled,
id
}
) })
}
) });
}
);
Cascader.displayName = "Cascader";
exports.Cascader = Cascader;
//# sourceMappingURL=Cascader.cjs.map