Repository: h2oai/wave
File: ui/src/text_annotator.tsx (TypeScript)

Code before:
      }
    </div>
  ),
  XTextAnnotator = ({ model: { name, title, tags, items, trigger, readonly, smart_selection = true } }: { model: TextAnnotator }) => {
    const
      [activeTag, setActiveTag] = React.useState<S | undefined>(readonly ? undefined : tags[0]?.name),
      [hoveredTagIdx, setHoveredTagIdx] = React.useState<U | null>(),
      tagColorMap = tags.reduce((map, t) => {
        map.set(t.name, t.color)
        return map
      }, new Map<S, S>()),
      [tokens, setTokens] = React.useState(items.reduce((arr, { text, tag }) => {
        // If the smart_selection is True, split by any non-letter character.
        text.split(smart_selection ? /(?=[^a-z0-9])/ig : "").forEach((textItem) => {
          const
            start = arr.length === 0 ? 0 : arr[arr.length - 1].end + 1,
            end = arr.length === 0 ? textItem.length - 1 : arr[arr.length - 1].end + textItem.length
          if (/[^a-z]/i.test(textItem)) {
            arr.push({ text: textItem.substring(0, 1), tag, start, end: start })
            if (textItem.substring(1) !== '') arr.push({ text: textItem.substring(1), tag, start: start + 1, end: end + 1 })
          } else {
            arr.push({ text: textItem, tag, start, end })
          }
        })
        return arr
      }, [] as (TextAnnotatorItem & { start: number, end: number })[])),
      submitWaveArgs = () => {
        let currentText = ''
        let currentTag: S | undefined
        wave.args[name] = tokens.reduce((arr, { text, tag }, idx, tokens) => {
          if (idx === tokens.length - 1) {
            if (tag !== currentTag) {
              arr.push({ text: currentText, tag: currentTag })
              arr.push({ text, tag })
            }
            else {
              arr.push({ text: currentText + text, tag })
            }
          }
          else if (idx !== 0 && tag !== currentTag) {
            arr.push({ text: currentText, tag: currentTag })
            currentText = text
          } else {
            currentText += text
          }
          currentTag = tag
          return arr
        }, [] as TextAnnotatorItem[]) as unknown as Rec[]
        if (trigger) wave.push()
      },
      activateTag = (tagName: S) => () => setActiveTag(tagName),

Review comment (suggestion):
Nit
```suggestion
      }, [] as (TextAnnotatorItem & { start: U, end: U })[])),
```

Code after:
  const AnnotatorTags = ({ tags, activateTag, activeTag }: AnnotatorTagsProps) => (
    <div className={css.tags}>
      {
        tags.map(({ name, color, label }) => {
          const style = stylesheet({
            tag: {
              background: cssVar(color),
              color: getContrast(color),
            },
            activeTag: {
              border: border(2, cssVar('$themePrimary')),
              borderRadius: 6
            }
          })
          return (
            <div key={name} data-test={name} className={clas(css.tagWrapper, activeTag === name ? style.activeTag : '')}>
              <div className={clas(css.tag, style.tag, 'wave-s12')} onClick={activateTag(name)}>{label}</div>
            </div>
          )
        })
      }
    </div>
  ),
  XTextAnnotator = ({ model: { name, title, tags, items, trigger, readonly } }: { model: TextAnnotator }) => {
    const
      [activeTag, setActiveTag] = React.useState<S | undefined>(readonly ? undefined : tags[0]?.name),
      [hoveredTagIdx, setHoveredTagIdx] = React.useState<U | null>(),
      [smartSelection, setSmartSelection] = React.useState(true),
      startElPropsRef = React.useRef<TokenMouseEventProps>(),
      tagColorMap = new Map(tags.map(t => [t.name, t.color])),
      [tokens, setTokens] = React.useState(items.reduce((tokenArr, { text, tag }) => {
        // Split by any non-letter.
        text.split(/([^a-z])/ig).filter(word => word !== '').forEach(textItem => {
          const
            start = tokenArr.length === 0 ? 0 : tokenArr[tokenArr.length - 1].end + 1,
            end = tokenArr.length === 0 ? textItem.length - 1 : tokenArr[tokenArr.length - 1].end + textItem.length

          tokenArr.push(...textItem.split('').map(char => ({ text: char, tag, start, end })))
        })
        return tokenArr
      }, [] as TokenProps[])),
      submitWaveArgs = () => {
        let currentText = ''
        let currentTag: S | undefined
        wave.args[name] = tokens.reduce((arr, { text, tag }, idx, tokens) => {
          if (idx === tokens.length - 1) {
            if (tag !== currentTag) {
              arr.push({ text: currentText, tag: currentTag })
              arr.push({ text, tag })
            }
            else {