<commit_before>import React, { forwardRef, HTMLAttributes } from 'react';
import { cx, css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
// @ts-ignore
import Highlighter from 'react-highlight-words';

/**
 * @public
 */
export type OnLabelClick = (name: string, value: string | undefined, event: React.MouseEvent<HTMLElement>) => void;

export interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onClick'> {
  name: string;
  active?: boolean;
  loading?: boolean;
  searchTerm?: string;
  value?: string;
  facets?: number;
  onClick?: OnLabelClick;
}

export const LokiLabel = forwardRef<HTMLElement, Props>(
  ({ name, value, hidden, facets, onClick, className, loading, searchTerm, active, style, ...rest }, ref) => {
    const theme = useTheme2();
    const styles = getLabelStyles(theme);
    const searchWords = searchTerm ? [searchTerm] : [];

    const onLabelClick = (event: React.MouseEvent<HTMLElement>) => {
      if (onClick && !hidden) {
        onClick(name, value, event);
      }
    };
    // Using this component for labels and label values. If value is given use value for display text.
    let text = value || name;
    if (facets) {
      text = `${text} (${facets})`;
    }

    return (
      <span
        key={text}
        ref={ref}
        onClick={onLabelClick}
        style={style}
        title={text}
        role="option"
        aria-selected={!!active}
        className={cx(
          styles.base,
          active && styles.active,
          loading && styles.loading,
          hidden && styles.hidden,
          className,
          onClick && !hidden && styles.hover
        )}
        {...rest}
      >
        <Highlighter textToHighlight={text} searchWords={searchWords} highlightClassName={styles.matchHighLight} />
      </span>
    );
  }
);

LokiLabel.displayName = 'LokiLabel';

const getLabelStyles = (theme: GrafanaTheme2) => ({
  base: css`
    cursor: pointer;
    font-size: ${theme.typography.size.sm};
    line-height: ${theme.typography.bodySmall.lineHeight};
    background-color: ${theme.colors.background.secondary};
    vertical-align: baseline;
    color: ${theme.colors.text};
    white-space: nowrap;
    text-shadow: none;
    padding: ${theme.spacing(0.5)};
    border-radius: ${theme.shape.borderRadius()};
    margin-right: ${theme.spacing(1)};<commit_msg>Loki: fix label browser crashing when + typed (#33900)<commit_after>import React, { forwardRef, HTMLAttributes } from 'react';
import { cx, css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
// @ts-ignore
import Highlighter from 'react-highlight-words';

/**
 * @public
 */
export type OnLabelClick = (name: string, value: string | undefined, event: React.MouseEvent<HTMLElement>) => void;

export interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onClick'> {
  name: string;
  active?: boolean;
  loading?: boolean;
  searchTerm?: string;
  value?: string;
  facets?: number;
  onClick?: OnLabelClick;
}

export const LokiLabel = forwardRef<HTMLElement, Props>(
  ({ name, value, hidden, facets, onClick, className, loading, searchTerm, active, style, ...rest }, ref) => {
    const theme = useTheme2();
    const styles = getLabelStyles(theme);
    const searchWords = searchTerm ? [searchTerm] : [];

    const onLabelClick = (event: React.MouseEvent<HTMLElement>) => {
      if (onClick && !hidden) {
        onClick(name, value, event);
      }
    };
    // Using this component for labels and label values. If value is given use value for display text.
    let text = value || name;
    if (facets) {
      text = `${text} (${facets})`;
    }

    return (
      <span
        key={text}
        ref={ref}
        onClick={onLabelClick}
        style={style}
        title={text}
        role="option"
        aria-selected={!!active}
        className={cx(
          styles.base,
          active && styles.active,
          loading && styles.loading,
          hidden && styles.hidden,
          className,
          onClick && !hidden && styles.hover
        )}
        {...rest}
      >
        <Highlighter
          textToHighlight={text}
          searchWords={searchWords}
          autoEscape={true}
          highlightClassName={styles.matchHighLight}
        />
      </span>
    );
  }
);

LokiLabel.displayName = 'LokiLabel';

const getLabelStyles = (theme: GrafanaTheme2) => ({
  base: css`
    cursor: pointer;
    font-size: ${theme.typography.size.sm};
    line-height: ${theme.typography.bodySmall.lineHeight};
    background-color: ${theme.colors.background.secondary};
    vertical-align: baseline;
    color: ${theme.colors.text};
    white-space: nowrap;
    text-shadow: none;
    padding: ${theme.spacing(0.5)};
    border-radius: ${theme.shape.borderRadius()};
    margin-right: ${theme.spacing(1)};
{'fraction_non_alphanumeric': 0.14405223423791064, 'fraction_numerical': 0.0038767598449296063, 'mean_word_length': 2.915335463258786, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5215163', 'n_tokens_mistral': 1485, 'n_tokens_neox': 1481, 'n_words': 359}