123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- import React, { useEffect, useRef, useState } from 'react'
- import type { ComponentProps, FC } from 'react'
- import { useTranslation } from 'react-i18next'
- import { ChunkingMode } from '@/models/datasets'
- import classNames from '@/utils/classnames'
- import { Markdown } from '@/app/components/base/markdown'
- type IContentProps = ComponentProps<'textarea'>
- const Textarea: FC<IContentProps> = React.memo(({
- value,
- placeholder,
- className,
- disabled,
- ...rest
- }) => {
- return (
- <textarea
- className={classNames(
- 'disabled:bg-transparent inset-0 outline-none border-none appearance-none resize-none w-full overflow-y-auto',
- className,
- )}
- placeholder={placeholder}
- value={value}
- disabled={disabled}
- {...rest}
- />
- )
- })
- Textarea.displayName = 'Textarea'
- type IAutoResizeTextAreaProps = ComponentProps<'textarea'> & {
- containerRef: React.RefObject<HTMLDivElement>
- labelRef: React.RefObject<HTMLDivElement>
- }
- const AutoResizeTextArea: FC<IAutoResizeTextAreaProps> = React.memo(({
- className,
- placeholder,
- value,
- disabled,
- containerRef,
- labelRef,
- ...rest
- }) => {
- const textareaRef = useRef<HTMLTextAreaElement>(null)
- const observerRef = useRef<ResizeObserver>()
- const [maxHeight, setMaxHeight] = useState(0)
- useEffect(() => {
- const textarea = textareaRef.current
- if (!textarea)
- return
- textarea.style.height = 'auto'
- const lineHeight = Number.parseInt(getComputedStyle(textarea).lineHeight)
- const textareaHeight = Math.max(textarea.scrollHeight, lineHeight)
- textarea.style.height = `${textareaHeight}px`
- }, [value])
- useEffect(() => {
- const container = containerRef.current
- const label = labelRef.current
- if (!container || !label)
- return
- const updateMaxHeight = () => {
- const containerHeight = container.clientHeight
- const labelHeight = label.clientHeight
- const padding = 32
- const space = 12
- const maxHeight = Math.floor((containerHeight - 2 * labelHeight - padding - space) / 2)
- setMaxHeight(maxHeight)
- }
- updateMaxHeight()
- observerRef.current = new ResizeObserver(updateMaxHeight)
- observerRef.current.observe(container)
- return () => {
- observerRef.current?.disconnect()
- }
- }, [])
- return (
- <textarea
- ref={textareaRef}
- className={classNames(
- 'disabled:bg-transparent inset-0 outline-none border-none appearance-none resize-none w-full',
- className,
- )}
- style={{
- maxHeight,
- }}
- placeholder={placeholder}
- value={value}
- disabled={disabled}
- {...rest}
- />
- )
- })
- AutoResizeTextArea.displayName = 'AutoResizeTextArea'
- type IQATextAreaProps = {
- question: string
- answer?: string
- onQuestionChange: (question: string) => void
- onAnswerChange?: (answer: string) => void
- isEditMode?: boolean
- }
- const QATextArea: FC<IQATextAreaProps> = React.memo(({
- question,
- answer,
- onQuestionChange,
- onAnswerChange,
- isEditMode = true,
- }) => {
- const { t } = useTranslation()
- const containerRef = useRef<HTMLDivElement>(null)
- const labelRef = useRef<HTMLDivElement>(null)
- return (
- <div ref={containerRef} className='h-full overflow-hidden'>
- <div ref={labelRef} className='text-text-tertiary text-xs font-medium mb-1'>QUESTION</div>
- <AutoResizeTextArea
- className='text-text-secondary text-sm tracking-[-0.07px] caret-[#295EFF]'
- value={question}
- placeholder={t('datasetDocuments.segment.questionPlaceholder') || ''}
- onChange={e => onQuestionChange(e.target.value)}
- disabled={!isEditMode}
- containerRef={containerRef}
- labelRef={labelRef}
- />
- <div className='text-text-tertiary text-xs font-medium mb-1 mt-6'>ANSWER</div>
- <AutoResizeTextArea
- className='text-text-secondary text-sm tracking-[-0.07px] caret-[#295EFF]'
- value={answer}
- placeholder={t('datasetDocuments.segment.answerPlaceholder') || ''}
- onChange={e => onAnswerChange?.(e.target.value)}
- disabled={!isEditMode}
- autoFocus
- containerRef={containerRef}
- labelRef={labelRef}
- />
- </div>
- )
- })
- QATextArea.displayName = 'QATextArea'
- type IChunkContentProps = {
- question: string
- answer?: string
- onQuestionChange: (question: string) => void
- onAnswerChange?: (answer: string) => void
- isEditMode?: boolean
- docForm: ChunkingMode
- }
- const ChunkContent: FC<IChunkContentProps> = ({
- question,
- answer,
- onQuestionChange,
- onAnswerChange,
- isEditMode,
- docForm,
- }) => {
- const { t } = useTranslation()
- if (docForm === ChunkingMode.qa) {
- return <QATextArea
- question={question}
- answer={answer}
- onQuestionChange={onQuestionChange}
- onAnswerChange={onAnswerChange}
- isEditMode={isEditMode}
- />
- }
- if (!isEditMode) {
- return (
- <Markdown
- className='h-full w-full !text-text-secondary'
- content={question}
- customDisallowedElements={['input']}
- />
- )
- }
- return (
- <Textarea
- className='h-full w-full pb-6 body-md-regular text-text-secondary tracking-[-0.07px] caret-[#295EFF]'
- value={question}
- placeholder={t('datasetDocuments.segment.contentPlaceholder') || ''}
- onChange={e => onQuestionChange(e.target.value)}
- disabled={!isEditMode}
- autoFocus
- />
- )
- }
- ChunkContent.displayName = 'ChunkContent'
- export default React.memo(ChunkContent)
|