All files / web/src/lib/character MarkedText.tsx

0% Statements 0/58
0% Branches 0/1
0% Functions 0/1
0% Lines 0/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                                                                                                                     
'use client'

/**
 * Renders text with entity markers as hoverable highlighted spans.
 *
 * Generic version of GeometricText — parameterized on entity ref type
 * via EntityMarkerConfig.
 */

import React, { useMemo } from 'react'
import type { EntityMarkerConfig } from './types'
import { parseEntityMarkers } from './parseEntityMarkers'

interface MarkedTextProps<TEntityRef> {
  text: string
  markers: EntityMarkerConfig<TEntityRef>
  onHighlight: (entity: TEntityRef | null) => void
  /** Optional custom renderer per entity. When absent, uses default blue/bold styling. */
  renderEntity?: (entity: TEntityRef, displayText: string, index: number) => React.ReactNode
}

export function MarkedText<TEntityRef>({
  text,
  markers,
  onHighlight,
  renderEntity,
}: MarkedTextProps<TEntityRef>) {
  const segments = useMemo(() => parseEntityMarkers(text, markers), [text, markers])

  return (
    <>
      {segments.map((seg, i) => {
        if (seg.kind === 'text') {
          return <span key={i}>{seg.text}</span>
        }
        if (renderEntity) {
          return <React.Fragment key={i}>{renderEntity(seg.entity, seg.text, i)}</React.Fragment>
        }
        return (
          <span
            key={i}
            data-element="entity-ref"
            style={{
              color: '#4E79A7',
              fontWeight: 600,
              cursor: 'pointer',
              borderBottom: '1px dotted rgba(78, 121, 167, 0.4)',
            }}
            onMouseEnter={() => onHighlight(seg.entity)}
            onMouseLeave={() => onHighlight(null)}
          >
            {seg.text}
          </span>
        )
      })}
    </>
  )
}