UNPKG

@grafana/ui

Version:
184 lines (177 loc) 6.69 kB
'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