slate#Value TypeScript Examples

The following examples show how to use slate#Value. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: QueryField.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
render() {
    const { disabled } = this.props;
    const wrapperClassName = classnames('slate-query-field__wrapper', {
      'slate-query-field__wrapper--disabled': disabled,
    });

    return (
      <div className={wrapperClassName}>
        <div className="slate-query-field">
          <Editor
            ref={editor => (this.editor = editor!)}
            schema={SCHEMA}
            autoCorrect={false}
            readOnly={this.props.disabled}
            onBlur={this.handleBlur}
            // onKeyDown={this.onKeyDown}
            onChange={(change: { value: Value }) => {
              this.onChange(change.value, false);
            }}
            placeholder={this.props.placeholder}
            plugins={this.plugins}
            spellCheck={false}
            value={this.state.value}
          />
        </div>
      </div>
    );
  }
Example #2
Source File: QueryField.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
/**
   * Update local state, propagate change upstream and optionally run the query afterwards.
   */
  onChange = (value: Value, runQuery?: boolean) => {
    const documentChanged = value.document !== this.state.value.document;
    const prevValue = this.state.value;

    // Update local state with new value and optionally change value upstream.
    this.setState({ value }, () => {
      // The diff is needed because the actual value of editor have much more metadata (for example text selection)
      // that is not passed upstream so every change of editor value does not mean change of the query text.
      if (documentChanged) {
        const textChanged = Plain.serialize(prevValue) !== Plain.serialize(value);
        if (textChanged && runQuery) {
          this.runOnChangeAndRunQuery();
        }
        if (textChanged && !runQuery) {
          // Debounce change propagation by default for perf reasons.
          this.runOnChangeDebounced();
        }
      }
    });
  };
Example #3
Source File: query_field.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
onChange = ({ value }: { value: Value }) => {
    const changed = value.document !== this.state.value.document;
    this.setState({ value }, () => {
      if (changed) {
        // call typeahead only if query changed
        requestAnimationFrame(() => this.onTypeahead());
        this.onChangeQuery();
      }
    });
  };
Example #4
Source File: QueryField.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
lastExecutedValue: Value | null = null;
Example #5
Source File: slate.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
makeValue = (text: string, syntax?: string): Value => {
  const fragment = makeFragment(text, syntax);

  return Value.create({
    document: fragment,
  });
}
Example #6
Source File: query_field.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
applyTypeahead = (
    editor?: CoreEditor,
    suggestion?: { text: any; type: string; deleteBackwards: any }
  ): { value: Value } => {
    return { value: new Value() };
  };
Example #7
Source File: query_field.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
getInitialValue = (query: string) => Value.create({ document: makeFragment(query) })
Example #8
Source File: language_provider.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
getAggregationCompletionItems = async (value: Value): Promise<TypeaheadOutput> => {
    const suggestions: CompletionItemGroup[] = [];

    // Stitch all query lines together to support multi-line queries
    let queryOffset;
    const queryText = value.document.getBlocks().reduce((text: string, block) => {
      const blockText = block.getText();
      if (value.anchorBlock.key === block.key) {
        // Newline characters are not accounted for but this is irrelevant
        // for the purpose of extracting the selector string
        queryOffset = value.selection.anchor.offset + text.length;
      }

      return text + blockText;
    }, '');

    // Try search for selector part on the left-hand side, such as `sum (m) by (l)`
    const openParensAggregationIndex = queryText.lastIndexOf('(', queryOffset);
    let openParensSelectorIndex = queryText.lastIndexOf('(', openParensAggregationIndex - 1);
    let closeParensSelectorIndex = queryText.indexOf(')', openParensSelectorIndex);

    // Try search for selector part of an alternate aggregation clause, such as `sum by (l) (m)`
    if (openParensSelectorIndex === -1) {
      const closeParensAggregationIndex = queryText.indexOf(')', queryOffset);
      closeParensSelectorIndex = queryText.indexOf(')', closeParensAggregationIndex + 1);
      openParensSelectorIndex = queryText.lastIndexOf('(', closeParensSelectorIndex);
    }

    const result = {
      suggestions,
      context: 'context-aggregation',
    };

    // Suggestions are useless for alternative aggregation clauses without a selector in context
    if (openParensSelectorIndex === -1) {
      return result;
    }

    // Range vector syntax not accounted for by subsequent parse so discard it if present
    const selectorString = queryText
      .slice(openParensSelectorIndex + 1, closeParensSelectorIndex)
      .replace(/\[[^\]]+\]$/, '');

    const selector = parseSelector(selectorString, selectorString.length - 2).selector;

    const labelValues = await this.getLabelValues(selector);
    if (labelValues) {
      suggestions.push({ label: 'Labels', items: Object.keys(labelValues).map(wrapLabel) });
    }
    return result;
  };
Example #9
Source File: DataLinkInput.tsx    From grafana-chinese with Apache License 2.0 4 votes vote down vote up
DataLinkInput: React.FC<DataLinkInputProps> = memo(
  ({ value, onChange, suggestions, placeholder = 'http://your-grafana.com/d/000000010/annotations' }) => {
    const editorRef = useRef<Editor>() as RefObject<Editor>;
    const theme = useContext(ThemeContext);
    const styles = getStyles(theme);
    const [showingSuggestions, setShowingSuggestions] = useState(false);
    const [suggestionsIndex, setSuggestionsIndex] = useState(0);
    const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value));
    const prevLinkUrl = usePrevious<Value>(linkUrl);

    // Workaround for https://github.com/ianstormtaylor/slate/issues/2927
    const stateRef = useRef({ showingSuggestions, suggestions, suggestionsIndex, linkUrl, onChange });
    stateRef.current = { showingSuggestions, suggestions, suggestionsIndex, linkUrl, onChange };

    // SelectionReference is used to position the variables suggestion relatively to current DOM selection
    const selectionRef = useMemo(() => new SelectionReference(), [setShowingSuggestions, linkUrl]);

    const onKeyDown = React.useCallback((event: KeyboardEvent, next: () => any) => {
      if (!stateRef.current.showingSuggestions) {
        if (event.key === '=' || event.key === '$' || (event.keyCode === 32 && event.ctrlKey)) {
          return setShowingSuggestions(true);
        }
        return next();
      }

      switch (event.key) {
        case 'Backspace':
        case 'Escape':
          setShowingSuggestions(false);
          return setSuggestionsIndex(0);

        case 'Enter':
          event.preventDefault();
          return onVariableSelect(stateRef.current.suggestions[stateRef.current.suggestionsIndex]);

        case 'ArrowDown':
        case 'ArrowUp':
          event.preventDefault();
          const direction = event.key === 'ArrowDown' ? 1 : -1;
          return setSuggestionsIndex(index => modulo(index + direction, stateRef.current.suggestions.length));
        default:
          return next();
      }
    }, []);

    useEffect(() => {
      // Update the state of the link in the parent. This is basically done on blur but we need to do it after
      // our state have been updated. The duplicity of state is done for perf reasons and also because local
      // state also contains things like selection and formating.
      if (prevLinkUrl && prevLinkUrl.selection.isFocused && !linkUrl.selection.isFocused) {
        stateRef.current.onChange(Plain.serialize(linkUrl));
      }
    }, [linkUrl, prevLinkUrl]);

    const onUrlChange = React.useCallback(({ value }: { value: Value }) => {
      setLinkUrl(value);
    }, []);

    const onVariableSelect = (item: VariableSuggestion, editor = editorRef.current!) => {
      const includeDollarSign = Plain.serialize(editor.value).slice(-1) !== '$';
      if (item.origin !== VariableOrigin.Template || item.value === DataLinkBuiltInVars.includeVars) {
        editor.insertText(`${includeDollarSign ? '$' : ''}\{${item.value}}`);
      } else {
        editor.insertText(`var-${item.value}=$\{${item.value}}`);
      }

      setLinkUrl(editor.value);
      setShowingSuggestions(false);

      setSuggestionsIndex(0);
      stateRef.current.onChange(Plain.serialize(editor.value));
    };

    return (
      <div
        className={cx(
          'gf-form-input',
          css`
            position: relative;
            height: auto;
          `
        )}
      >
        <div className="slate-query-field">
          {showingSuggestions && (
            <Portal>
              <ReactPopper
                referenceElement={selectionRef}
                placement="top-end"
                modifiers={{
                  preventOverflow: { enabled: true, boundariesElement: 'window' },
                  arrow: { enabled: false },
                  offset: { offset: 250 }, // width of the suggestions menu
                }}
              >
                {({ ref, style, placement }) => {
                  return (
                    <div ref={ref} style={style} data-placement={placement}>
                      <DataLinkSuggestions
                        suggestions={stateRef.current.suggestions}
                        onSuggestionSelect={onVariableSelect}
                        onClose={() => setShowingSuggestions(false)}
                        activeIndex={suggestionsIndex}
                      />
                    </div>
                  );
                }}
              </ReactPopper>
            </Portal>
          )}
          <Editor
            schema={SCHEMA}
            ref={editorRef}
            placeholder={placeholder}
            value={stateRef.current.linkUrl}
            onChange={onUrlChange}
            onKeyDown={(event, _editor, next) => onKeyDown(event as KeyboardEvent, next)}
            plugins={plugins}
            className={styles.editor}
          />
        </div>
      </div>
    );
  }
)