@grafana/ui
Version:
Grafana Components Library
184 lines (177 loc) • 6.69 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
var classNames = require('classnames');
var lodash = require('lodash');
var React = require('react');
var Plain = require('slate-plain-serializer');
var slateReact = require('slate-react');
var e2eSelectors = require('@grafana/e2e-selectors');
var clear = require('../../slate-plugins/clear.cjs');
var clipboard = require('../../slate-plugins/clipboard.cjs');
var indentation = require('../../slate-plugins/indentation.cjs');
var newline = require('../../slate-plugins/newline.cjs');
var runner = require('../../slate-plugins/runner.cjs');
var selection_shortcuts = require('../../slate-plugins/selection_shortcuts.cjs');
var suggestions = require('../../slate-plugins/suggestions.cjs');
var ThemeContext = require('../../themes/ThemeContext.cjs');
var mixins = require('../../themes/mixins.cjs');
var slate = require('../../utils/slate.cjs');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var classNames__default = /*#__PURE__*/_interopDefaultCompat(classNames);
var Plain__default = /*#__PURE__*/_interopDefaultCompat(Plain);
"use strict";
class UnThemedQueryField extends React.PureComponent {
constructor(props) {
super(props);
this.lastExecutedValue = null;
this.mounted = false;
this.editor = null;
/**
* Update local state, propagate change upstream and optionally run the query afterwards.
*/
this.onChange = (value, runQuery) => {
const documentChanged = value.document !== this.state.value.document;
const prevValue = this.state.value;
if (this.props.onRichValueChange) {
this.props.onRichValueChange(value);
}
this.setState({ value }, () => {
if (documentChanged) {
const textChanged = Plain__default.default.serialize(prevValue) !== Plain__default.default.serialize(value);
if (textChanged && runQuery) {
this.runOnChangeAndRunQuery();
}
if (textChanged && !runQuery) {
this.runOnChangeDebounced();
}
}
});
};
this.runOnChange = () => {
const { onChange } = this.props;
const value = Plain__default.default.serialize(this.state.value);
if (onChange) {
onChange(this.cleanText(value));
}
};
this.runOnRunQuery = () => {
const { onRunQuery } = this.props;
if (onRunQuery) {
onRunQuery();
this.lastExecutedValue = this.state.value;
}
};
this.runOnChangeAndRunQuery = () => {
this.runOnChange();
this.runOnRunQuery();
};
/**
* We need to handle blur events here mainly because of dashboard panels which expect to have query executed on blur.
*/
this.handleBlur = (_, editor, next) => {
const { onBlur } = this.props;
if (onBlur) {
onBlur();
} else {
const previousValue = this.lastExecutedValue ? Plain__default.default.serialize(this.lastExecutedValue) : "";
const currentValue = Plain__default.default.serialize(editor.value);
if (previousValue !== currentValue) {
this.runOnChangeAndRunQuery();
}
}
return next();
};
this.runOnChangeDebounced = lodash.debounce(this.runOnChange, 500);
const { onTypeahead, cleanText, portalOrigin, onWillApplySuggestion } = props;
this.plugins = [
// SuggestionsPlugin and RunnerPlugin need to be before NewlinePlugin
// because they override Enter behavior
suggestions.SuggestionsPlugin({ onTypeahead, cleanText, portalOrigin, onWillApplySuggestion }),
runner.RunnerPlugin({ handler: this.runOnChangeAndRunQuery }),
newline.NewlinePlugin(),
clear.ClearPlugin(),
selection_shortcuts.SelectionShortcutsPlugin(),
indentation.IndentationPlugin(),
clipboard.ClipboardPlugin(),
...props.additionalPlugins || []
].filter((p) => p);
this.state = {
suggestions: [],
typeaheadContext: null,
typeaheadPrefix: "",
typeaheadText: "",
value: slate.makeValue(props.query || "", props.syntax)
};
}
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
componentDidUpdate(prevProps, prevState) {
const { query, syntax, syntaxLoaded } = this.props;
if (!prevProps.syntaxLoaded && syntaxLoaded && this.editor) {
const editor = this.editor.insertText(" ").deleteBackward(1);
this.onChange(editor.value, true);
}
const { value } = this.state;
if (query !== prevProps.query) {
if (query !== Plain__default.default.serialize(value)) {
this.setState({ value: slate.makeValue(query || "", syntax) });
}
}
}
cleanText(text) {
const newText = text.replace(/[\r]/g, "");
return newText;
}
render() {
const { disabled, theme, ["aria-labelledby"]: ariaLabelledby } = this.props;
const wrapperClassName = classNames__default.default("slate-query-field__wrapper", {
"slate-query-field__wrapper--disabled": disabled
});
const styles = getStyles(theme);
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: css.cx(wrapperClassName, styles.wrapper), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "slate-query-field", "data-testid": e2eSelectors.selectors.components.QueryField.container, children: /* @__PURE__ */ jsxRuntime.jsx(
slateReact.Editor,
{
ref: (editor) => {
this.editor = editor;
},
"aria-labelledby": ariaLabelledby,
schema: slate.SCHEMA,
autoCorrect: false,
readOnly: this.props.disabled,
onBlur: this.handleBlur,
onClick: this.props.onClick,
onChange: (change) => {
this.onChange(change.value, false);
},
placeholder: this.props.placeholder,
plugins: this.plugins,
spellCheck: false,
value: this.state.value
}
) }) });
}
}
// By default QueryField calls onChange if onBlur is not defined, this will trigger a rerender
// And slate will claim the focus, making it impossible to leave the field.
UnThemedQueryField.defaultProps = {
onBlur: () => {
}
};
const QueryField = ThemeContext.withTheme2(UnThemedQueryField);
const getStyles = (theme) => {
const focusStyles = mixins.getFocusStyles(theme);
return {
wrapper: css.css({
"&:focus-within": focusStyles
})
};
};
exports.QueryField = QueryField;
exports.UnThemedQueryField = UnThemedQueryField;
//# sourceMappingURL=QueryField.cjs.map