@ -10,7 +10,7 @@ import Placeholder from '@tiptap/extension-placeholder'
import { TaskItem } from '@/helpers/dbTiptapExtensions/task-item'
import { TaskItem } from '@/helpers/dbTiptapExtensions/task-item'
import { Link } from '@/helpers/dbTiptapExtensions/links'
import { Link } from '@/helpers/dbTiptapExtensions/links'
import type { RichTextBubbleMenuOptions } from '#imports'
import type { RichTextBubbleMenuOptions } from '#imports'
import { IsExpandedFormOpenInj , IsFormInj , IsGridInj , ReadonlyInj , RowHeightInj } from '#imports'
import { IsExpandedFormOpenInj , IsFormInj , IsGridInj , IsSurveyFormInj , ReadonlyInj , RowHeightInj } from '#imports'
const props = withDefaults (
const props = withDefaults (
defineProps < {
defineProps < {
@ -26,13 +26,14 @@ const props = withDefaults(
hiddenBubbleMenuOptions ? : RichTextBubbleMenuOptions [ ]
hiddenBubbleMenuOptions ? : RichTextBubbleMenuOptions [ ]
} > ( ) ,
} > ( ) ,
{
{
isFormField : false ,
hiddenBubbleMenuOptions : ( ) => [ ] ,
hiddenBubbleMenuOptions : ( ) => [ ] ,
} ,
} ,
)
)
const emits = defineEmits ( [ 'update:value' ] )
const emits = defineEmits ( [ 'update:value' , 'focus' , 'blur' ] )
const { hiddenBubbleMenuOptions } = toRefs ( props )
const { isFormField , hiddenBubbleMenuOptions } = toRefs ( props )
const isExpandedFormOpen = inject ( IsExpandedFormOpenInj , ref ( false ) ) !
const isExpandedFormOpen = inject ( IsExpandedFormOpenInj , ref ( false ) ) !
@ -44,8 +45,12 @@ const isForm = inject(IsFormInj, ref(false))
const isGrid = inject ( IsGridInj , ref ( false ) )
const isGrid = inject ( IsGridInj , ref ( false ) )
const isSurveyForm = inject ( IsSurveyFormInj , ref ( false ) )
const isFocused = ref ( false )
const isFocused = ref ( false )
const keys = useMagicKeys ( )
const turndownService = new TurndownService ( { } )
const turndownService = new TurndownService ( { } )
turndownService . addRule ( 'lineBreak' , {
turndownService . addRule ( 'lineBreak' , {
@ -124,7 +129,7 @@ const vModel = useVModel(props, 'value', emits, { defaultValue: '' })
const tiptapExtensions = [
const tiptapExtensions = [
StarterKit . configure ( {
StarterKit . configure ( {
heading : props . isFormField ? false : undefined ,
heading : isFormField . value ? false : undefined ,
} ) ,
} ) ,
TaskList ,
TaskList ,
TaskItem . configure ( {
TaskItem . configure ( {
@ -145,16 +150,18 @@ const editor = useEditor({
. turndown ( editor . getHTML ( ) . replaceAll ( /<p><\/p>/g , '<br />' ) )
. turndown ( editor . getHTML ( ) . replaceAll ( /<p><\/p>/g , '<br />' ) )
. replaceAll ( /\n\n<br \/>\n\n/g , '<br>\n\n' )
. replaceAll ( /\n\n<br \/>\n\n/g , '<br>\n\n' )
vModel . value = props . isFormField && markdown === '<br />' ? '' : markdown
vModel . value = isFormField . value && markdown === '<br />' ? '' : markdown
} ,
} ,
editable : ! props . readOnly ,
editable : ! props . readOnly ,
autofocus : props . autofocus ,
autofocus : props . autofocus ,
onFocus : ( ) => {
onFocus : ( ) => {
isFocused . value = true
isFocused . value = true
emits ( 'focus' )
} ,
} ,
onBlur : ( e ) => {
onBlur : ( e ) => {
if ( ! ( e ? . event ? . relatedTarget as HTMLElement ) ? . closest ( '.bubble-menu, .nc-textarea-rich-editor' ) ) {
if ( ! ( e ? . event ? . relatedTarget as HTMLElement ) ? . closest ( '.bubble-menu, .nc-textarea-rich-editor' ) ) {
isFocused . value = false
isFocused . value = false
emits ( 'blur' )
}
}
} ,
} ,
} )
} )
@ -185,13 +192,19 @@ const setEditorContent = (contentMd: any, focusEndOfDoc?: boolean) => {
} , 100 )
} , 100 )
}
}
const onFocusWrapper = ( ) => {
if ( isForm . value && ! isFormField . value && ! props . readOnly && ! keys . shift . value ) {
editor . value ? . chain ( ) . focus ( ) . run ( )
}
}
if ( props . syncValueChange ) {
if ( props . syncValueChange ) {
watch ( [ vModel , editor ] , ( ) => {
watch ( [ vModel , editor ] , ( ) => {
setEditorContent ( vModel . value )
setEditorContent ( vModel . value )
} )
} )
}
}
if ( props . isFormField ) {
if ( isFormField . value ) {
watch ( [ props , editor ] , ( ) => {
watch ( [ props , editor ] , ( ) => {
if ( props . readOnly ) {
if ( props . readOnly ) {
editor . value ? . setEditable ( false )
editor . value ? . setEditable ( false )
@ -206,7 +219,7 @@ watch(editorDom, () => {
setEditorContent ( vModel . value , true )
setEditorContent ( vModel . value , true )
if ( props . isFormField ) return
if ( ( isForm . value && ! isSurveyForm . value ) || isFormField . value ) return
/ / F o c u s e d i t o r a f t e r e d i t o r i s m o u n t e d
/ / F o c u s e d i t o r a f t e r e d i t o r i s m o u n t e d
setTimeout ( ( ) => {
setTimeout ( ( ) => {
editor . value ? . chain ( ) . focus ( ) . run ( )
editor . value ? . chain ( ) . focus ( ) . run ( )
@ -220,6 +233,7 @@ useEventListener(
const targetEl = e ? . relatedTarget as HTMLElement
const targetEl = e ? . relatedTarget as HTMLElement
if ( targetEl ? . classList ? . contains ( 'tiptap' ) || ! targetEl ? . closest ( '.bubble-menu, .nc-textarea-rich-editor' ) ) {
if ( targetEl ? . classList ? . contains ( 'tiptap' ) || ! targetEl ? . closest ( '.bubble-menu, .nc-textarea-rich-editor' ) ) {
isFocused . value = false
isFocused . value = false
emits ( 'blur' )
}
}
} ,
} ,
true ,
true ,
@ -228,7 +242,7 @@ useEventListener(
< template >
< template >
< div
< div
class = "h-full focus:outline-none"
class = "nc-rich-text h-full focus:outline-none"
: class = " {
: class = " {
'flex flex-col flex-grow nc-rich-text-full' : fullMode ,
'flex flex-col flex-grow nc-rich-text-full' : fullMode ,
'nc-rich-text-embed flex flex-col pl-1 w-full' : ! fullMode ,
'nc-rich-text-embed flex flex-col pl-1 w-full' : ! fullMode ,
@ -237,6 +251,7 @@ useEventListener(
'nc-rich-text-grid' : isGrid ,
'nc-rich-text-grid' : isGrid ,
} "
} "
: tabindex = "readOnlyCell || isFormField ? -1 : 0"
: tabindex = "readOnlyCell || isFormField ? -1 : 0"
@ focus = "onFocusWrapper"
>
>
< div v-if ="renderAsText" class="truncate" >
< div v-if ="renderAsText" class="truncate" >
< span v-if ="editor" > {{ editor ? .getText ( ) ? ? ' ' }} < / span >
< span v-if ="editor" > {{ editor ? .getText ( ) ? ? ' ' }} < / span >
@ -244,17 +259,22 @@ useEventListener(
< template v-else >
< template v-else >
< div
< div
v - if = "showMenu && !readOnly && !isFormField"
v - if = "showMenu && !readOnly && !isFormField"
class = "absolute top-0 right-0.5 xs:hidden "
class = "absolute top-0 right-0.5"
: class = " {
: class = " {
'max-w-[calc(100%_-_198px)] flex justify-end rounded-tr-2xl overflow-hidden' : fullMode ,
'flex rounded-tr-2xl overflow-hidden w-full' : fullMode || isForm ,
'max-w-[calc(100%_-_198px)]' : fullMode ,
'justify-start left-0.5' : isForm ,
'justify-end xs:hidden' : ! isForm ,
} "
} "
>
>
< div class = "nc-longtext-scrollbar" >
< div class = "scrollbar-thin scrollbar-thumb-gray-200 hover:scrollbar-thumb-gray-300 scrollbar-track-transparent " >
< CellRichTextSelectedBubbleMenu v -if = " editor " :editor ="editor" embed -mode :is-form-field ="isFormField" / >
< CellRichTextSelectedBubbleMenu v -if = " editor " :editor ="editor" embed -mode :is-form-field ="isFormField" / >
< / div >
< / div >
< / div >
< / div >
< CellRichTextSelectedBubbleMenuPopup v -if = " editor & & ! isFormField " :editor ="editor" / >
< CellRichTextSelectedBubbleMenuPopup v -if = " editor & & ! isFormField & & ! isForm " :editor ="editor" / >
< CellRichTextLinkOptions v -if = " editor " :editor ="editor" / >
< CellRichTextLinkOptions v -if = " editor " :editor ="editor" / >
< EditorContent
< EditorContent
ref = "editorDom"
ref = "editorDom"
: editor = "editor"
: editor = "editor"
@ -444,18 +464,21 @@ useEventListener(
font - weight : 700 ;
font - weight : 700 ;
font - size : 1.85 rem ;
font - size : 1.85 rem ;
margin - bottom : 0.1 rem ;
margin - bottom : 0.1 rem ;
line - height : 36 px ;
}
}
h2 {
h2 {
font - weight : 600 ;
font - weight : 600 ;
font - size : 1.55 rem ;
font - size : 1.55 rem ;
margin - bottom : 0.1 em ;
margin - bottom : 0.1 em ;
line - height : 30 px ;
}
}
h3 {
h3 {
font - weight : 600 ;
font - weight : 600 ;
font - size : 1.15 rem ;
font - size : 1.15 rem ;
margin - bottom : 0.1 em ;
margin - bottom : 0.1 em ;
line - height : 24 px ;
}
}
blockquote {
blockquote {