@ -147,6 +147,7 @@ export const BlockNode = ({
|
||||
|
||||
return isEditing && isTextBubbleBlock(block) ? (
|
||||
<TextBubbleEditor
|
||||
id={block.id}
|
||||
initialValue={block.content.richText}
|
||||
onClose={handleCloseEditor}
|
||||
/>
|
||||
|
@ -1,15 +1,14 @@
|
||||
import { Flex, Stack, useOutsideClick } from '@chakra-ui/react'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
Plate,
|
||||
PlateProvider,
|
||||
selectEditor,
|
||||
TEditor,
|
||||
TElement,
|
||||
Value,
|
||||
withPlate,
|
||||
usePlateEditorRef,
|
||||
} from '@udecode/plate-core'
|
||||
import { editorStyle, platePlugins } from 'libs/plate'
|
||||
import { BaseEditor, BaseSelection, createEditor, Transforms } from 'slate'
|
||||
import { BaseEditor, BaseSelection, Transforms } from 'slate'
|
||||
import { ToolBar } from './ToolBar'
|
||||
import { parseHtmlStringToPlainText } from 'services/utils'
|
||||
import { defaultTextBubbleContent, TextBubbleContent, Variable } from 'models'
|
||||
@ -17,30 +16,25 @@ import { VariableSearchInput } from 'components/shared/VariableSearchInput'
|
||||
import { ReactEditor } from 'slate-react'
|
||||
import { serializeHtml } from '@udecode/plate-serializer-html'
|
||||
|
||||
type Props = {
|
||||
initialValue: TElement[]
|
||||
type TextBubbleEditorContentProps = {
|
||||
id: string
|
||||
textEditorValue: TElement[]
|
||||
onClose: (newContent: TextBubbleContent) => void
|
||||
}
|
||||
|
||||
export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
const randomEditorId = useMemo(() => Math.random().toString(), [])
|
||||
const editor = useMemo(
|
||||
() =>
|
||||
withPlate(createEditor() as TEditor<Value>, {
|
||||
id: randomEditorId,
|
||||
plugins: platePlugins,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
)
|
||||
const [value, setValue] = useState(initialValue)
|
||||
const TextBubbleEditorContent = ({
|
||||
id,
|
||||
textEditorValue,
|
||||
onClose,
|
||||
}: TextBubbleEditorContentProps) => {
|
||||
const editor = usePlateEditorRef()
|
||||
const varDropdownRef = useRef<HTMLDivElement | null>(null)
|
||||
const rememberedSelection = useRef<BaseSelection | null>(null)
|
||||
const [isVariableDropdownOpen, setIsVariableDropdownOpen] = useState(false)
|
||||
|
||||
const textEditorRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const closeEditor = () => onClose(convertValueToBlockContent(value))
|
||||
const closeEditor = () => onClose(convertValueToBlockContent(textEditorValue))
|
||||
|
||||
useOutsideClick({
|
||||
ref: textEditorRef,
|
||||
@ -94,10 +88,6 @@ export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
ReactEditor.focus(editor as unknown as ReactEditor)
|
||||
}
|
||||
|
||||
const handleChangeEditorContent = (val: TElement[]) => {
|
||||
setValue(val)
|
||||
setIsVariableDropdownOpen(false)
|
||||
}
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.shiftKey) return
|
||||
if (e.key === 'Enter') closeEditor()
|
||||
@ -115,12 +105,9 @@ export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
spacing={0}
|
||||
cursor="text"
|
||||
>
|
||||
<ToolBar
|
||||
editor={editor}
|
||||
onVariablesButtonClick={() => setIsVariableDropdownOpen(true)}
|
||||
/>
|
||||
<ToolBar onVariablesButtonClick={() => setIsVariableDropdownOpen(true)} />
|
||||
<Plate
|
||||
id={randomEditorId}
|
||||
id={id}
|
||||
editableProps={{
|
||||
style: editorStyle,
|
||||
autoFocus: true,
|
||||
@ -136,13 +123,6 @@ export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
},
|
||||
onKeyDown: handleKeyDown,
|
||||
}}
|
||||
initialValue={
|
||||
initialValue.length === 0
|
||||
? [{ type: 'p', children: [{ text: '' }] }]
|
||||
: initialValue
|
||||
}
|
||||
onChange={handleChangeEditorContent}
|
||||
editor={editor}
|
||||
/>
|
||||
{isVariableDropdownOpen && (
|
||||
<Flex
|
||||
@ -164,3 +144,36 @@ export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
type TextBubbleEditorProps = {
|
||||
id: string
|
||||
initialValue: TElement[]
|
||||
onClose: (newContent: TextBubbleContent) => void
|
||||
}
|
||||
|
||||
export const TextBubbleEditor = ({
|
||||
id,
|
||||
initialValue,
|
||||
onClose,
|
||||
}: TextBubbleEditorProps) => {
|
||||
const [textEditorValue, setTextEditorValue] = useState(initialValue)
|
||||
|
||||
return (
|
||||
<PlateProvider
|
||||
id={id}
|
||||
plugins={platePlugins}
|
||||
initialValue={
|
||||
initialValue.length === 0
|
||||
? [{ type: 'p', children: [{ text: '' }] }]
|
||||
: initialValue
|
||||
}
|
||||
onChange={setTextEditorValue}
|
||||
>
|
||||
<TextBubbleEditorContent
|
||||
id={id}
|
||||
textEditorValue={textEditorValue}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</PlateProvider>
|
||||
)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
MARK_ITALIC,
|
||||
MARK_UNDERLINE,
|
||||
} from '@udecode/plate-basic-marks'
|
||||
import { getPluginType, PlateEditor, Value } from '@udecode/plate-core'
|
||||
import { getPluginType, usePlateEditorRef } from '@udecode/plate-core'
|
||||
import { LinkToolbarButton } from '@udecode/plate-ui-link'
|
||||
import { MarkToolbarButton } from '@udecode/plate-ui-toolbar'
|
||||
import {
|
||||
@ -16,15 +16,11 @@ import {
|
||||
} from 'assets/icons'
|
||||
|
||||
type Props = {
|
||||
editor: PlateEditor<Value>
|
||||
onVariablesButtonClick: () => void
|
||||
} & StackProps
|
||||
|
||||
export const ToolBar = ({
|
||||
editor,
|
||||
onVariablesButtonClick,
|
||||
...props
|
||||
}: Props) => {
|
||||
export const ToolBar = ({ onVariablesButtonClick, ...props }: Props) => {
|
||||
const editor = usePlateEditorRef()
|
||||
const handleVariablesButtonMouseDown = (e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
onVariablesButtonClick()
|
||||
|
@ -21,6 +21,13 @@ export const platePlugins = createPlugins(
|
||||
createUnderlinePlugin(),
|
||||
createLinkPlugin({
|
||||
renderAfterEditable: PlateFloatingLink,
|
||||
options: {
|
||||
isUrl: (url: string) =>
|
||||
url.startsWith('http') ||
|
||||
url.startsWith('mailto') ||
|
||||
url.startsWith('tel') ||
|
||||
url.startsWith('sms'),
|
||||
},
|
||||
}),
|
||||
],
|
||||
{
|
||||
|
@ -31,13 +31,13 @@
|
||||
"@sentry/nextjs": "7.15.0",
|
||||
"@stripe/stripe-js": "1.41.0",
|
||||
"@tanstack/react-table": "8.5.15",
|
||||
"@udecode/plate-basic-marks": "16.8.0",
|
||||
"@udecode/plate-basic-marks": "18.2.0",
|
||||
"@udecode/plate-common": "^7.0.2",
|
||||
"@udecode/plate-core": "16.8.0",
|
||||
"@udecode/plate-link": "16.9.0",
|
||||
"@udecode/plate-serializer-html": "16.8.0",
|
||||
"@udecode/plate-ui-link": "16.9.0",
|
||||
"@udecode/plate-ui-toolbar": "16.8.0",
|
||||
"@udecode/plate-core": "18.2.0",
|
||||
"@udecode/plate-link": "18.2.0",
|
||||
"@udecode/plate-serializer-html": "18.2.0",
|
||||
"@udecode/plate-ui-link": "18.2.0",
|
||||
"@udecode/plate-ui-toolbar": "18.2.0",
|
||||
"aws-sdk": "2.1233.0",
|
||||
"bot-engine": "workspace:*",
|
||||
"browser-image-compression": "2.0.0",
|
||||
@ -70,7 +70,7 @@
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-draggable": "4.4.5",
|
||||
"slate": "0.82.1",
|
||||
"slate": "0.84.0",
|
||||
"slate-history": "0.66.0",
|
||||
"slate-hyperscript": "0.77.0",
|
||||
"slate-react": "0.83.2",
|
||||
|
Reference in New Issue
Block a user