♻️ Simplify text bubble content shape

Remove html and plainText field because it was redundant

Closes #386
This commit is contained in:
Baptiste Arnaud
2023-04-13 17:04:21 +02:00
parent 2cbf8348c3
commit e0a9824913
70 changed files with 545 additions and 1030 deletions

View File

@@ -1,28 +1,25 @@
import { Flex } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { TextBubbleBlock } from '@typebot.io/schemas'
import React from 'react'
import { isEmpty } from '@typebot.io/lib'
import { parseVariableHtmlTags } from '@/features/variables/helpers/parseVariableHtmlTags'
import { PlateBlock } from './plate/PlateBlock'
type Props = {
block: TextBubbleBlock
}
export const TextBubbleContent = ({ block }: Props) => {
const { typebot } = useTypebot()
const isEmpty = block.content.richText.length === 0
return (
<Flex
w="90%"
flexDir={'column'}
opacity={block.content.html === '' ? '0.5' : '1'}
opacity={isEmpty ? '0.5' : '1'}
className="slate-html-container"
color={isEmpty(block.content.plainText) ? 'gray.500' : 'inherit'}
dangerouslySetInnerHTML={{
__html: isEmpty(block.content.plainText)
? `<p>Click to edit...</p>`
: parseVariableHtmlTags(block.content.html, typebot?.variables ?? []),
}}
/>
color={isEmpty ? 'gray.500' : 'inherit'}
>
{block.content.richText.map((element, idx) => (
<PlateBlock key={idx} element={element} />
))}
</Flex>
)
}

View File

@@ -3,14 +3,8 @@ import React, { useEffect, useRef, useState } from 'react'
import { Plate, PlateProvider, usePlateEditorRef } from '@udecode/plate-core'
import { editorStyle, platePlugins } from '@/lib/plate'
import { BaseEditor, BaseSelection, Transforms } from 'slate'
import {
defaultTextBubbleContent,
TextBubbleContent,
Variable,
} from '@typebot.io/schemas'
import { Variable } from '@typebot.io/schemas'
import { ReactEditor } from 'slate-react'
import { serializeHtml } from '@udecode/plate-serializer-html'
import { parseHtmlStringToPlainText } from '../utils'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { colors } from '@/lib/theme'
import { useOutsideClick } from '@/hooks/useOutsideClick'
@@ -20,7 +14,7 @@ import { TextEditorToolBar } from './TextEditorToolBar'
type TextBubbleEditorContentProps = {
id: string
textEditorValue: TElement[]
onClose: (newContent: TextBubbleContent) => void
onClose: (newContent: TElement[]) => void
}
const TextBubbleEditorContent = ({
@@ -37,7 +31,7 @@ const TextBubbleEditorContent = ({
const textEditorRef = useRef<HTMLDivElement>(null)
const closeEditor = () => onClose(convertValueToBlockContent(textEditorValue))
const closeEditor = () => onClose(textEditorValue)
useOutsideClick({
ref: textEditorRef,
@@ -67,18 +61,6 @@ const TextBubbleEditorContent = ({
}
}
const convertValueToBlockContent = (value: TElement[]): TextBubbleContent => {
if (value.length === 0) defaultTextBubbleContent
const html = serializeHtml(editor, {
nodes: value,
})
return {
html,
richText: value,
plainText: parseHtmlStringToPlainText(html),
}
}
const handleVariableSelected = (variable?: Variable) => {
setIsVariableDropdownOpen(false)
if (!rememberedSelection.current || !variable) return
@@ -170,7 +152,7 @@ const TextBubbleEditorContent = ({
type TextBubbleEditorProps = {
id: string
initialValue: TElement[]
onClose: (newContent: TextBubbleContent) => void
onClose: (newContent: TElement[]) => void
}
export const TextBubbleEditor = ({

View File

@@ -0,0 +1,27 @@
import { TElement, TText, TDescendant } from '@udecode/plate-common'
import { PlateText } from './PlateText'
export const PlateBlock = ({ element }: { element: TElement | TText }) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (element.text) return <PlateText {...(element as any)} />
switch (element.type) {
case 'a': {
return (
<a href={element.url as string} target="_blank" className="slate-a">
{(element.children as TDescendant[])?.map((child, idx) => (
<PlateBlock key={idx} element={child} />
))}
</a>
)
}
default: {
return (
<div>
{(element.children as TDescendant[])?.map((child, idx) => (
<PlateBlock key={idx} element={child} />
))}
</div>
)
}
}
}

View File

@@ -0,0 +1,38 @@
export const PlateText = ({
text,
bold,
italic,
underline,
}: {
text: string
bold?: boolean
italic?: boolean
underline?: boolean
}) => {
let className = ''
if (bold) className += 'slate-bold'
if (italic) className += ' slate-italic'
if (underline) className += ' slate-underline'
if (className)
return (
<span className={className}>
<PlateTextContent text={text} />
</span>
)
return <PlateTextContent text={text} />
}
const PlateTextContent = ({ text }: { text: string }) => (
<>
{text.split(/\{\{(.*?\}\})/g).map((str, idx) => {
if (str.endsWith('}}')) {
return (
<span className="slate-variable" key={idx}>
{str.trim().slice(0, -2)}
</span>
)
}
return str
})}
</>
)

View File

@@ -1,17 +0,0 @@
import { Parser } from 'htmlparser2'
import { isNotEmpty } from '@typebot.io/lib'
export const parseHtmlStringToPlainText = (html: string): string => {
let plainText = ''
const parser = new Parser({
onopentag(name) {
if (name === 'div' && isNotEmpty(plainText)) plainText += '\n'
},
ontext(text) {
plainText += `${text}`
},
})
parser.write(html)
parser.end()
return plainText
}