@@ -55,21 +55,120 @@ const FullscreenGlobalStyle = createGlobalStyle`
5555 }
5656` ;
5757
58- /* Global z-index fixes for Editor.js popovers (may render at body level) */
58+ /* Global z-index and visibility fixes for Editor.js */
5959const EditorJSGlobalStyles = createGlobalStyle `
60- /* Popover rendered at document body */
61- body > .ce-popover,
62- body > .ce-popover--opened,
63- body > .ce-popover__container,
64- body > .ce-settings,
65- body > .ce-conversion-toolbar,
66- body > .ce-inline-toolbar {
60+ /* ============================================
61+ INLINE TOOLBAR - EditorJS 2.31
62+ Structure: .ce-inline-toolbar > .ce-popover--inline > .ce-popover__items > .ce-popover-item-html > .ce-inline-tool
63+ ============================================ */
64+
65+ /* Hide "Nothing found" message when inline tools ARE present */
66+ .ce-popover--inline .ce-popover__nothing-found-message {
67+ display: none !important;
68+ }
69+
70+ /* Inline Toolbar Popover - horizontal layout for tool buttons */
71+ .ce-popover--inline.ce-popover--opened {
72+ display: block !important;
73+ opacity: 1 !important;
74+ visibility: visible !important;
6775 z-index: 99999 !important;
76+ background: white !important;
77+ border: 1px solid #e2e8f0 !important;
78+ border-radius: 8px !important;
79+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12) !important;
80+ padding: 4px !important;
6881 }
6982
70- /* Ensure popovers are visible above Strapi modals */
71- .ce-popover,
72- .ce-popover--opened {
83+ .ce-popover--inline .ce-popover__container {
84+ display: block !important;
85+ }
86+
87+ /* Items container - HORIZONTAL layout for inline tools */
88+ .ce-popover--inline .ce-popover__items {
89+ display: flex !important;
90+ flex-direction: row !important;
91+ flex-wrap: wrap !important;
92+ align-items: center !important;
93+ gap: 2px !important;
94+ opacity: 1 !important;
95+ visibility: visible !important;
96+ }
97+
98+ /* Custom HTML wrapper for inline tools */
99+ .ce-popover--inline .ce-popover-item-html {
100+ display: flex !important;
101+ opacity: 1 !important;
102+ visibility: visible !important;
103+ }
104+
105+ /* The actual inline tool buttons (Bold, Italic, etc.) */
106+ .ce-popover--inline .ce-inline-tool {
107+ display: flex !important;
108+ align-items: center !important;
109+ justify-content: center !important;
110+ width: 32px !important;
111+ height: 32px !important;
112+ opacity: 1 !important;
113+ visibility: visible !important;
114+ background: transparent !important;
115+ border: none !important;
116+ border-radius: 6px !important;
117+ cursor: pointer !important;
118+ color: #64748b !important;
119+ transition: background 0.15s ease, color 0.15s ease !important;
120+ }
121+
122+ .ce-popover--inline .ce-inline-tool:hover {
123+ background: #f1f5f9 !important;
124+ color: #334155 !important;
125+ }
126+
127+ .ce-popover--inline .ce-inline-tool--active {
128+ background: #ede9fe !important;
129+ color: #7C3AED !important;
130+ }
131+
132+ .ce-popover--inline .ce-inline-tool svg {
133+ width: 18px !important;
134+ height: 18px !important;
135+ }
136+
137+ /* Convert-to button (block type changer) */
138+ .ce-popover--inline .ce-popover-item[data-item-name="convert-to"] {
139+ display: flex !important;
140+ align-items: center !important;
141+ padding: 4px 8px !important;
142+ border-radius: 6px !important;
143+ cursor: pointer !important;
144+ }
145+
146+ .ce-popover--inline .ce-popover-item[data-item-name="convert-to"]:hover {
147+ background: #f1f5f9 !important;
148+ }
149+
150+ /* Separator line between convert-to and inline tools */
151+ .ce-popover--inline .ce-popover-item-separator {
152+ width: 1px !important;
153+ height: 24px !important;
154+ background: #e2e8f0 !important;
155+ margin: 0 4px !important;
156+ }
157+
158+ .ce-popover--inline .ce-popover-item-separator__line {
159+ display: none !important;
160+ }
161+
162+ /* ============================================
163+ GLOBAL Z-INDEX FOR ALL EDITOR POPOVERS
164+ ============================================ */
165+
166+ body > .ce-popover,
167+ body > .ce-inline-toolbar,
168+ .ce-popover--opened,
169+ .ce-inline-toolbar,
170+ .ce-settings,
171+ .ce-conversion-toolbar {
73172 z-index: 99999 !important;
74173 }
75174
@@ -940,19 +1039,29 @@ const EditorWrapper = styled.div`
9401039 TOOLBAR INSIDE EDITOR - Position Fix
9411040 ============================================ */
9421041
943- /* Centered content area */
1042+ /* Content area - full container width */
9441043 .codex-editor__redactor {
9451044 padding-bottom: 100px !important;
9461045 padding-left: 0 !important;
947- margin: 0 auto !important;
948- max-width: 800px !important;
1046+ padding-right: 0 !important;
1047+ margin: 0 !important;
1048+ max-width: 100% !important;
1049+ width: 100% !important;
9491050 }
9501051
951- /* Content blocks - centered */
1052+ /* Content blocks - full width, no centering */
9521053 .ce-block__content {
953- max-width: 100%;
954- margin: 0 auto;
955- padding: 0 16px;
1054+ max-width: 100% !important;
1055+ margin: 0 !important;
1056+ padding: 0 16px !important;
1057+ }
1058+
1059+ /* Paragraph and other editable elements - full width */
1060+ .ce-paragraph,
1061+ .ce-header,
1062+ .cdx-block {
1063+ max-width: 100% !important;
1064+ width: 100% !important;
9561065 }
9571066
9581067 /* ============================================
@@ -1001,18 +1110,20 @@ const EditorWrapper = styled.div`
10011110 border-radius: 6px;
10021111 }
10031112
1004- /* Toolbar positioning - centered with content */
1113+ /* Toolbar positioning - full width */
10051114 .ce-toolbar__content {
1006- max-width: 800px ;
1007- margin: 0 auto ;
1008- padding: 0 16px;
1115+ max-width: 100% !important ;
1116+ margin: 0 !important ;
1117+ padding: 0 16px !important ;
10091118 }
10101119
10111120 .ce-toolbar {
1012- left: 50% !important;
1013- transform: translateX(-50%) !important;
1121+ left: 0 !important;
1122+ right: 0 !important;
1123+ transform: none !important;
10141124 width: 100% !important;
1015- max-width: 832px !important;
1125+ max-width: 100% !important;
1126+ padding-left: 8px !important;
10161127 }
10171128
10181129 .ce-toolbar__plus {
@@ -2152,6 +2263,8 @@ const Editor = forwardRef(({
21522263 if ( ! collabEnabled || ! editorInstanceRef . current || ! yTextMap ) return ;
21532264
21542265 const editor = editorInstanceRef . current ;
2266+ if ( ! editor . blocks || typeof editor . blocks . getBlocksCount !== 'function' ) return ;
2267+
21552268 const blockCount = editor . blocks . getBlocksCount ( ) ;
21562269
21572270 console . log ( '[Magic Editor X] [CHAR-SYNC] Binding' , blockCount , 'blocks to Y.Text' ) ;
@@ -2720,6 +2833,13 @@ const Editor = forwardRef(({
27202833 pendingRenderRef . current = pendingRenderRef . current || true ;
27212834 return ;
27222835 }
2836+
2837+ // Ensure blocks API is available
2838+ if ( ! editor . blocks || typeof editor . blocks . getBlocksCount !== 'function' ) {
2839+ console . warn ( '[Magic Editor X] Editor blocks API not ready for renderFromYDoc' ) ;
2840+ pendingRenderRef . current = pendingRenderRef . current || true ;
2841+ return ;
2842+ }
27232843
27242844 // Prevent echo loops
27252845 if ( isApplyingRemoteRef . current ) {
@@ -3075,6 +3195,8 @@ const Editor = forwardRef(({
30753195 }
30763196
30773197 const editor = editorInstanceRef . current ;
3198+ if ( ! editor . blocks || typeof editor . blocks . getBlocksCount !== 'function' ) return ;
3199+
30783200 const lastIndex = editor . blocks . getBlocksCount ( ) ;
30793201
30803202 editor . blocks . insert ( blockType , { } , { } , lastIndex , true ) ;
@@ -3145,6 +3267,23 @@ const Editor = forwardRef(({
31453267 }
31463268 }
31473269
3270+ // Debug: Log registered tools to verify inline tools are loaded
3271+ console . log ( '[Magic Editor X] Registered tools:' , Object . keys ( tools ) ) ;
3272+
3273+ // Check each tool for isInline property
3274+ const inlineTools = Object . entries ( tools ) . filter ( ( [ name , config ] ) => {
3275+ const toolClass = config . class || config ;
3276+ const isInline = toolClass ?. isInline === true ;
3277+ if ( isInline ) {
3278+ console . log ( `[Magic Editor X] Found inline tool: ${ name } ` , toolClass ) ;
3279+ }
3280+ return isInline ;
3281+ } ) . map ( ( [ name ] ) => name ) ;
3282+
3283+ console . log ( '[Magic Editor X] Inline tools found:' , inlineTools ) ;
3284+ console . log ( '[Magic Editor X] Marker isInline:' , tools . marker ?. class ?. isInline ) ;
3285+ console . log ( '[Magic Editor X] Bold isInline:' , tools . bold ?. class ?. isInline ) ;
3286+
31483287 const editor = new EditorJS ( {
31493288 holder : editorRef . current ,
31503289 tools,
@@ -3153,28 +3292,40 @@ const Editor = forwardRef(({
31533292 placeholder : customPlaceholder ,
31543293 minHeight : 200 ,
31553294 autofocus : false ,
3295+ // Note: Do NOT set inlineToolbar here - each block tool controls its own inline toolbar
3296+ // The inline tools (bold, italic, marker, etc.) are automatically available when block tools have inlineToolbar: true
31563297
31573298 onReady : async ( ) => {
31583299 isReadyRef . current = true ;
31593300 setIsReady ( true ) ;
31603301 console . log ( '[Magic Editor X] [READY] Editor onReady fired' ) ;
31613302 console . log ( '[Magic Editor X] [READY] Editor holder:' , editorRef . current ?. id ) ;
31623303
3163- // Initialize Undo/Redo plugin
3164- try {
3165- initUndoRedo ( editor ) ;
3166- console . log ( '[Magic Editor X] [SUCCESS] Undo/Redo initialized' ) ;
3167- } catch ( e ) {
3168- console . warn ( '[Magic Editor X] Could not initialize Undo/Redo:' , e ) ;
3169- }
3170-
3171- // Initialize Drag & Drop plugin
3172- try {
3173- initDragDrop ( editor ) ;
3174- console . log ( '[Magic Editor X] [SUCCESS] Drag & Drop initialized' ) ;
3175- } catch ( e ) {
3176- console . warn ( '[Magic Editor X] Could not initialize Drag & Drop:' , e ) ;
3177- }
3304+ // Initialize Undo/Redo and Drag & Drop plugins with longer delay
3305+ // These plugins require the editor to be fully ready with blocks API available
3306+ setTimeout ( ( ) => {
3307+ try {
3308+ if ( editor && editor . blocks && typeof editor . blocks . getBlocksCount === 'function' ) {
3309+ initUndoRedo ( editor ) ;
3310+ console . log ( '[Magic Editor X] [SUCCESS] Undo/Redo initialized' ) ;
3311+ } else {
3312+ console . warn ( '[Magic Editor X] Editor blocks API not ready for Undo/Redo' ) ;
3313+ }
3314+ } catch ( e ) {
3315+ console . warn ( '[Magic Editor X] Could not initialize Undo/Redo:' , e ) ;
3316+ }
3317+
3318+ try {
3319+ if ( editor && editor . blocks && typeof editor . blocks . getBlocksCount === 'function' ) {
3320+ initDragDrop ( editor ) ;
3321+ console . log ( '[Magic Editor X] [SUCCESS] Drag & Drop initialized' ) ;
3322+ } else {
3323+ console . warn ( '[Magic Editor X] Editor blocks API not ready for Drag & Drop' ) ;
3324+ }
3325+ } catch ( e ) {
3326+ console . warn ( '[Magic Editor X] Could not initialize Drag & Drop:' , e ) ;
3327+ }
3328+ } , 500 ) ;
31783329
31793330 if ( pendingRenderRef . current ) {
31803331 try {
@@ -3206,6 +3357,68 @@ const Editor = forwardRef(({
32063357 bindAllBlocksToYText ( ) ;
32073358 } , 100 ) ;
32083359 }
3360+
3361+ // WEBTOOLS LINK CLICK HANDLER
3362+ // When clicking on an existing link, open the link picker directly for editing
3363+ if ( isWebtoolsAvailable && webtoolsOpenLinkPicker && editorRef . current ) {
3364+ const handleLinkClick = async ( e ) => {
3365+ // Find if click was on an anchor tag or inside one
3366+ const anchor = e . target . closest ( 'a' ) ;
3367+
3368+ if ( anchor && editorRef . current ?. contains ( anchor ) ) {
3369+ // Prevent default link navigation
3370+ e . preventDefault ( ) ;
3371+ e . stopPropagation ( ) ;
3372+
3373+ const existingHref = anchor . href || '' ;
3374+ const existingText = anchor . textContent || '' ;
3375+
3376+ console . log ( '[Magic Editor X] Link clicked, opening editor:' , existingHref ) ;
3377+
3378+ try {
3379+ // Select the link text for editing
3380+ const selection = window . getSelection ( ) ;
3381+ const range = document . createRange ( ) ;
3382+ range . selectNodeContents ( anchor ) ;
3383+ selection . removeAllRanges ( ) ;
3384+ selection . addRange ( range ) ;
3385+
3386+ // Open the Webtools Link Picker with existing values
3387+ const result = await webtoolsOpenLinkPicker ( {
3388+ initialText : existingText ,
3389+ initialHref : existingHref ,
3390+ } ) ;
3391+
3392+ if ( result && result . href ) {
3393+ // Update the link
3394+ anchor . href = result . href ;
3395+ if ( result . label && result . label !== existingText ) {
3396+ anchor . textContent = result . label ;
3397+ }
3398+ console . log ( '[Magic Editor X] Link updated:' , result . href ) ;
3399+ } else if ( result === null ) {
3400+ // User cancelled - keep the link as-is
3401+ console . log ( '[Magic Editor X] Link edit cancelled' ) ;
3402+ }
3403+ } catch ( err ) {
3404+ console . error ( '[Magic Editor X] Error editing link:' , err ) ;
3405+ }
3406+ }
3407+ } ;
3408+
3409+ // Add click listener to the editor container
3410+ editorRef . current . addEventListener ( 'click' , handleLinkClick ) ;
3411+
3412+ // Store cleanup function
3413+ const cleanup = ( ) => {
3414+ editorRef . current ?. removeEventListener ( 'click' , handleLinkClick ) ;
3415+ } ;
3416+
3417+ // Store for cleanup on unmount
3418+ if ( ! editorRef . current . _linkClickCleanup ) {
3419+ editorRef . current . _linkClickCleanup = cleanup ;
3420+ }
3421+ }
32093422 } ,
32103423
32113424 onChange : async ( api ) => {
@@ -3255,6 +3468,13 @@ const Editor = forwardRef(({
32553468 console . log ( '[Magic Editor X] [CLEANUP] Editor component unmounting, destroying editor' ) ;
32563469 isReadyRef . current = false ;
32573470 setIsReady ( false ) ;
3471+
3472+ // Cleanup link click handler
3473+ if ( editorRef . current ?. _linkClickCleanup ) {
3474+ editorRef . current . _linkClickCleanup ( ) ;
3475+ delete editorRef . current . _linkClickCleanup ;
3476+ }
3477+
32583478 if ( editorInstanceRef . current && editorInstanceRef . current . destroy ) {
32593479 try {
32603480 editorInstanceRef . current . destroy ( ) ;
0 commit comments