11import { FC as FunctionComponent , useState , useEffect , useMemo } from "react" ;
2-
32import { Flex , Field } from "@strapi/design-system" ;
43import type { Schema } from "@strapi/types" ;
5- import MDEditor , { commands , ICommand } from "@uiw/react-md-editor" ;
4+ import { commands , ICommand } from "@uiw/react-md-editor" ;
65import { useIntl } from "react-intl" ;
76import { styled } from "styled-components" ;
8-
97import "@uiw/react-markdown-preview/markdown.css" ;
10-
11- import { PLUGIN_ID } from '../utils/pluginId' ;
8+ import { PLUGIN_ID } from '../utils/pluginId' ;
129import MediaLib from "./MediaLib" ;
1310import { useField } from "@strapi/strapi/admin" ;
14- import assetsToMarkdown from '../utils/assetsToMarkdown' ;
11+ import assetsToMarkdown from "../utils/assetsToMarkdown" ;
12+ import CustomMDEditor from "./CustomMDEditor" ;
1513
1614const Wrapper = styled . div `
1715 flex-basis: 100%;
@@ -62,7 +60,7 @@ const Wrapper = styled.div`
6260 }
6361` ;
6462
65- interface EditorProps {
63+ interface FieldProps {
6664 name : string ;
6765 onChange : ( e : { target : { name : string ; value : string } } ) => void ;
6866 value : string ;
@@ -81,7 +79,12 @@ interface EditorProps {
8179 labelAction ?: React . ReactNode ; //TO FIX TO CHECK
8280}
8381
84- const Editor : FunctionComponent < EditorProps > = ( {
82+ interface CursorPosition {
83+ start : number ;
84+ end : number ;
85+ }
86+
87+ const CustomField : FunctionComponent < FieldProps > = ( {
8588 attribute,
8689 name,
8790 disabled,
@@ -92,26 +95,38 @@ const Editor: FunctionComponent<EditorProps> = ({
9295 intlLabel,
9396} ) => {
9497 // const { formatMessage } = useIntl();
95- const { onChange, value } : any = useField ( name ) ;
98+ const field : any = useField ( name ) ;
99+
96100 const formatMessage = ( message : { id : string ; defaultMessage : string } ) =>
97101 message ?. defaultMessage ?? "" ;
98102 const [ mediaLibVisible , setMediaLibVisible ] = useState ( false ) ;
99- const [ mediaLibSelection , setMediaLibSelection ] = useState ( - 1 ) ;
103+ const [ cursorPosition , setCursorPosition ] = useState < CursorPosition | null > ( null ) ;
100104
101105 const handleToggleMediaLib = ( ) => setMediaLibVisible ( ( prev ) => ! prev ) ;
102106
107+ const updateFieldValue = ( value :any ) => {
108+ field . onChange ( { target : { name, value : value } } ) ;
109+ }
110+
103111 const handleChangeAssets = ( assets : Schema . Attribute . MediaValue < true > ) => {
104112
105- const output = value + assetsToMarkdown ( assets ) ;
113+ let output ;
114+ const assetsString = assetsToMarkdown ( assets ) ;
106115
107- onChange ( { target : { name, value : output } } ) ;
116+ if ( cursorPosition ) {
117+ output = field . value . slice ( 0 , cursorPosition . start ) + assetsString + field . value . slice ( cursorPosition . end ) ;
118+ } else {
119+ output = field . value + assetsString ;
120+ }
121+
122+ updateFieldValue ( output ) ;
108123 handleToggleMediaLib ( ) ;
109124 } ;
110125
111- const [ configs , setConfigs ] = useState < { toolbarCommands ?: string [ ] } > ( { } ) ;
126+ const [ config , setConfig ] = useState < { toolbarCommands ?: string [ ] } > ( { } ) ;
112127
113128 const toolbarCommands = useMemo ( ( ) => {
114- const strapiMediaLibrary : ICommand = {
129+ const mediaLibraryButton : ICommand = {
115130 name : "media" ,
116131 keyCommand : "media" ,
117132 buttonProps : { "aria-label" : "Insert media" } ,
@@ -124,37 +139,19 @@ const Editor: FunctionComponent<EditorProps> = ({
124139 </ svg >
125140 ) ,
126141 execute : ( state , _api ) => {
127- setMediaLibSelection ( state . selection . end ) ;
142+ setCursorPosition ( state . selection ) ;
128143 handleToggleMediaLib ( ) ;
129144 } ,
130145 } ;
131- if ( ! configs ?. toolbarCommands ) {
132- return [
133- commands . title2 ,
134- commands . title3 ,
135- commands . title4 ,
136- commands . title5 ,
137- commands . title6 ,
138- commands . divider ,
139- commands . bold ,
140- commands . codeBlock ,
141- commands . italic ,
142- commands . strikethrough ,
143- commands . hr ,
144- commands . group ,
146+ if ( ! config ?. toolbarCommands ) {
147+ return [ ...commands . getCommands ( ) ,
145148 commands . divider ,
146- commands . link ,
147- commands . quote ,
148- commands . code ,
149- strapiMediaLibrary ,
150- commands . unorderedListCommand ,
151- commands . orderedListCommand ,
152- commands . checkedListCommand ,
149+ mediaLibraryButton
153150 ] as ICommand [ ] ;
154151 }
155- const customCommands = configs ?. toolbarCommands
152+ const customCommands = config ?. toolbarCommands
156153 ?. map ( ( config ) => {
157- if ( config === "strapiMediaLibrary " ) return strapiMediaLibrary ;
154+ if ( config === "mediaLibraryButton " ) return mediaLibraryButton ;
158155 if (
159156 config in commands &&
160157 commands [ config as unknown as keyof typeof commands ]
@@ -167,48 +164,46 @@ const Editor: FunctionComponent<EditorProps> = ({
167164 . filter ( ( command ) : command is ICommand => command !== undefined ) ;
168165
169166 return customCommands ;
170- } , [ JSON . stringify ( configs ) ] ) ;
167+ } , [ JSON . stringify ( config ) ] ) ;
171168
172169 useEffect ( ( ) => {
173170 fetch ( `/${ PLUGIN_ID } ` )
174171 . then ( ( response ) => response . json ( ) )
175172 . then ( ( data ) => {
176- setConfigs ( data ) ;
173+ setConfig ( data ) ;
177174 } ) ;
178175 } , [ ] ) ;
179176
180177 return (
181178 < Field . Root
182- name = { name }
183- id = { name }
184- error = { error }
185- hint = { description && formatMessage ( description ) }
179+ name = { name }
180+ id = { name }
181+ error = { error }
182+ hint = { description && formatMessage ( description ) }
186183 >
187- < Flex spacing = { 1 } alignItems = "normal" style = { { ' flexDirection' : ' column' } } >
188- < Field . Label action = { labelAction } required = { required } >
189- { intlLabel ? formatMessage ( intlLabel ) : name }
190- </ Field . Label >
184+ < Flex spacing = { 1 } alignItems = "normal" style = { { flexDirection : " column" } } >
185+ < Field . Label action = { labelAction } required = { required } >
186+ { intlLabel ? formatMessage ( intlLabel ) : name }
187+ </ Field . Label >
191188 < Wrapper >
192- < MDEditor
189+ < CustomMDEditor
193190 hidden = { disabled }
191+ value = { field . value }
192+ onChange = { updateFieldValue }
194193 commands = { toolbarCommands }
195- value = { value || "" }
196- onChange = { ( newValue ) => {
197- onChange ( { target : { name, value : newValue || "" } } ) ;
198- } }
199194 />
200195 </ Wrapper >
201196 < Field . Hint />
202197 < Field . Error />
203198 </ Flex >
204199 < MediaLib
205- /*allowedTypes={['images']}*/
206- isOpen = { mediaLibVisible }
207- onChange = { handleChangeAssets }
208- onToggle = { handleToggleMediaLib }
200+ /*allowedTypes={['images']}*/
201+ isOpen = { mediaLibVisible }
202+ onChange = { handleChangeAssets }
203+ onToggle = { handleToggleMediaLib }
209204 />
210205 </ Field . Root >
211206 ) ;
212207} ;
213208
214- export { Editor } ;
209+ export { CustomField } ;
0 commit comments