<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import {components} from 'react-select'
import _get from 'lodash/get'
import {html} from 'tocco-util'

import Popover from '../Popover'
import ClickableWrapper from './ClickableWrapper'
import {StyledSingleValueWrapper} from './StyledComponents'

export const SingleValue = props => {
  const {
    data,
    selectProps,
    isDisabled,
    children
  } = props
  const {
    tooltips,
    loadTooltip,
    DetailLink
  } = selectProps
  const tooltip = _get(tooltips, data.key, null)
  const content = DetailLink
    ? <ClickableWrapper onMouseDown={e => {
      e.stopPropagation()
      e.preventDefault()
    }}>
      <DetailLink entityKey={data.key}>{children}</DetailLink>
    </ClickableWrapper>
    : children

  return (
    <components.SingleValue {...props}>
      <StyledSingleValueWrapper
        onMouseOver={() => loadTooltip && !tooltip && loadTooltip(data.key)}
        isDisabled={isDisabled}
      >
        <Popover content={tooltip
          ? <div dangerouslySetInnerHTML={{__html: html.sanitizeHtml(tooltip)}}/>
          : null}>
          {content}
        </Popover>
      </StyledSingleValueWrapper>
    </components.SingleValue>
  )
}

SingleValue.propTypes = {
  children: PropTypes.node,
  data: PropTypes.object,
  isDisabled: PropTypes.bool,
  selectProps: PropTypes.shape({
    tooltips: PropTypes.objectOf(PropTypes.string),
    loadTooltip: PropTypes.func,
    DetailLink: PropTypes.func
  })
}

export default SingleValue
<commit_msg>fix(tocco-ui): fix performance bottleneck on linked select values<commit_after>import React, {memo} from 'react'
import PropTypes from 'prop-types'
import {components} from 'react-select'
import _get from 'lodash/get'
import _omit from 'lodash/omit'
import _omitBy from 'lodash/omitBy'
import {html, js} from 'tocco-util'

import Popover from '../Popover'
import ClickableWrapper from './ClickableWrapper'
import {StyledSingleValueWrapper} from './StyledComponents'

/**
 * For better performance in tabbing through
 * React-Select fields on Safari the SingleValue should not
 * re-render onFocus and onBlur.
 * Re-render is triggered by the `DetailLink` component which could be ignored
 */
const ignoredAttributes = ['linkComp']
const areEqual = (prevProps, nextProps) => {
  const diff = js.difference(prevProps, nextProps)
  const clean = _omitBy(_omit(diff, ignoredAttributes), v => Object.keys(v).length === 0)
  return Object.entries(clean).length === 0
}

const Content = memo(({linkComp: DetailLink, entityKey, children}) => (DetailLink
  ? <ClickableWrapper onMouseDown={e => {
    e.stopPropagation()
    e.preventDefault()
  }}>
    <DetailLink entityKey={entityKey}>{children}</DetailLink>
  </ClickableWrapper>
  : children),
areEqual)

Content.propTypes = {
  children: PropTypes.node,
  entityKey: PropTypes.string,
  linkComp: PropTypes.func
}

export const SingleValue = props => {
  const {
    data,
    selectProps,
    isDisabled,
    children
  } = props
  const {
    tooltips,
    loadTooltip,
    DetailLink
  } = selectProps
  const tooltip = _get(tooltips, data.key, null)

  return (
    <components.SingleValue {...props}>
      <StyledSingleValueWrapper
        onMouseOver={() => loadTooltip && !tooltip && loadTooltip(data.key)}
        isDisabled={isDisabled}
      >
        <Popover content={tooltip
          ? <div dangerouslySetInnerHTML={{__html: html.sanitizeHtml(tooltip)}}/>
          : null}>
          <Content linkComp={DetailLink} entityKey={data.key}>{children}</Content>
        </Popover>
      </StyledSingleValueWrapper>
    </components.SingleValue>
  )
}

SingleValue.propTypes = {
  children: PropTypes.node,
  data: PropTypes.object,
  isDisabled: PropTypes.bool,
  selectProps: PropTypes.shape({
    tooltips: PropTypes.objectOf(PropTypes.string),
    loadTooltip: PropTypes.func,
    DetailLink: PropTypes.func
  })
}

export default SingleValue

{'fraction_non_alphanumeric': 0.11867408906882591, 'fraction_numerical': 0.0005060728744939271, 'mean_word_length': 3.6892052194543297, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 36, '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': '4031850', 'n_tokens_mistral': 1193, 'n_tokens_neox': 1191, 'n_words': 281}