@@ -349,6 +349,10 @@ export function createSimpleBlock(config) {
349349 } ) ;
350350 break ;
351351
352+ case 'image' :
353+ input = this . _createImageField ( field ) ;
354+ break ;
355+
352356 default : // text input
353357 input = document . createElement ( 'input' ) ;
354358 input . type = field . type || 'text' ;
@@ -374,6 +378,174 @@ export function createSimpleBlock(config) {
374378 return container ;
375379 }
376380
381+ /**
382+ * Create image field with Media Library integration
383+ * @param {object } field - Field configuration
384+ * @returns {HTMLElement }
385+ */
386+ _createImageField ( field ) {
387+ const wrapper = document . createElement ( 'div' ) ;
388+ wrapper . style . cssText = `
389+ border: 2px dashed #e2e8f0;
390+ border-radius: 8px;
391+ padding: 16px;
392+ text-align: center;
393+ background: #fafbfc;
394+ transition: all 0.2s ease;
395+ ` ;
396+
397+ // Image preview
398+ const preview = document . createElement ( 'div' ) ;
399+ preview . className = 'image-preview' ;
400+ preview . style . cssText = `
401+ margin-bottom: 12px;
402+ min-height: 60px;
403+ display: flex;
404+ align-items: center;
405+ justify-content: center;
406+ ` ;
407+
408+ const img = document . createElement ( 'img' ) ;
409+ img . style . cssText = `
410+ max-width: 100%;
411+ max-height: 150px;
412+ border-radius: 6px;
413+ display: none;
414+ ` ;
415+
416+ const placeholder = document . createElement ( 'div' ) ;
417+ placeholder . innerHTML = `
418+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5">
419+ <rect x="3" y="3" width="18" height="18" rx="2"/>
420+ <circle cx="8.5" cy="8.5" r="1.5"/>
421+ <path d="M21 15l-5-5L5 21"/>
422+ </svg>
423+ <p style="margin: 8px 0 0; color: #94a3b8; font-size: 13px;">No image selected</p>
424+ ` ;
425+ placeholder . style . cssText = 'text-align: center;' ;
426+
427+ preview . appendChild ( img ) ;
428+ preview . appendChild ( placeholder ) ;
429+
430+ // Update preview based on current data
431+ const updatePreview = ( url ) => {
432+ if ( url ) {
433+ img . src = url ;
434+ img . style . display = 'block' ;
435+ placeholder . style . display = 'none' ;
436+ wrapper . style . borderStyle = 'solid' ;
437+ wrapper . style . borderColor = '#c4b5fd' ;
438+ } else {
439+ img . style . display = 'none' ;
440+ placeholder . style . display = 'block' ;
441+ wrapper . style . borderStyle = 'dashed' ;
442+ wrapper . style . borderColor = '#e2e8f0' ;
443+ }
444+ } ;
445+
446+ // Initial state
447+ const currentValue = this . data [ field . name ] ;
448+ if ( currentValue && typeof currentValue === 'object' ) {
449+ updatePreview ( currentValue . url ) ;
450+ } else if ( typeof currentValue === 'string' && currentValue ) {
451+ updatePreview ( currentValue ) ;
452+ }
453+
454+ // Buttons container
455+ const buttons = document . createElement ( 'div' ) ;
456+ buttons . style . cssText = 'display: flex; gap: 8px; justify-content: center;' ;
457+
458+ // Select button
459+ const selectBtn = document . createElement ( 'button' ) ;
460+ selectBtn . type = 'button' ;
461+ selectBtn . textContent = 'Select Image' ;
462+ selectBtn . style . cssText = `
463+ padding: 8px 16px;
464+ background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
465+ color: white;
466+ border: none;
467+ border-radius: 6px;
468+ font-size: 13px;
469+ font-weight: 600;
470+ cursor: pointer;
471+ transition: all 0.2s ease;
472+ ` ;
473+ selectBtn . addEventListener ( 'mouseenter' , ( ) => {
474+ selectBtn . style . transform = 'translateY(-1px)' ;
475+ selectBtn . style . boxShadow = '0 4px 12px rgba(124, 58, 237, 0.35)' ;
476+ } ) ;
477+ selectBtn . addEventListener ( 'mouseleave' , ( ) => {
478+ selectBtn . style . transform = 'translateY(0)' ;
479+ selectBtn . style . boxShadow = 'none' ;
480+ } ) ;
481+
482+ // Remove button
483+ const removeBtn = document . createElement ( 'button' ) ;
484+ removeBtn . type = 'button' ;
485+ removeBtn . textContent = 'Remove' ;
486+ removeBtn . style . cssText = `
487+ padding: 8px 16px;
488+ background: transparent;
489+ color: #ef4444;
490+ border: 1px solid #fecaca;
491+ border-radius: 6px;
492+ font-size: 13px;
493+ font-weight: 600;
494+ cursor: pointer;
495+ transition: all 0.2s ease;
496+ display: ${ this . data [ field . name ] ? 'inline-block' : 'none' } ;
497+ ` ;
498+ removeBtn . addEventListener ( 'click' , ( ) => {
499+ this . data [ field . name ] = null ;
500+ updatePreview ( null ) ;
501+ removeBtn . style . display = 'none' ;
502+ } ) ;
503+
504+ // Handle select button click - dispatch custom event
505+ selectBtn . addEventListener ( 'click' , ( ) => {
506+ if ( this . readOnly ) return ;
507+
508+ // Create a unique callback ID
509+ const callbackId = `image_field_${ Date . now ( ) } _${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ;
510+
511+ // Store callback globally for Media Library to call
512+ window . __MAGIC_EDITOR_IMAGE_CALLBACKS__ = window . __MAGIC_EDITOR_IMAGE_CALLBACKS__ || { } ;
513+ window . __MAGIC_EDITOR_IMAGE_CALLBACKS__ [ callbackId ] = ( files ) => {
514+ if ( files && files . length > 0 ) {
515+ const file = files [ 0 ] ;
516+ const imageData = {
517+ url : file . url ,
518+ alt : file . alt || file . name || '' ,
519+ width : file . width ,
520+ height : file . height ,
521+ id : file . id ,
522+ documentId : file . documentId ,
523+ } ;
524+ this . data [ field . name ] = imageData ;
525+ updatePreview ( imageData . url ) ;
526+ removeBtn . style . display = 'inline-block' ;
527+ }
528+ // Cleanup
529+ delete window . __MAGIC_EDITOR_IMAGE_CALLBACKS__ [ callbackId ] ;
530+ } ;
531+
532+ // Dispatch event to open Media Library
533+ window . dispatchEvent ( new CustomEvent ( 'magic-editor-open-media-lib' , {
534+ detail : { callbackId, fieldName : field . name , allowedTypes : [ 'images' ] }
535+ } ) ) ;
536+ } ) ;
537+
538+ buttons . appendChild ( selectBtn ) ;
539+ buttons . appendChild ( removeBtn ) ;
540+
541+ wrapper . appendChild ( preview ) ;
542+ if ( ! this . readOnly ) {
543+ wrapper . appendChild ( buttons ) ;
544+ }
545+
546+ return wrapper ;
547+ }
548+
377549 /**
378550 * Escape HTML special characters
379551 * @param {string } text - Text to escape
0 commit comments