@@ -459,21 +459,27 @@ export default class extends Controller implements LiveController {
459
459
const thisPromise = fetch ( `${ url } ${ paramsString . length > 0 ? `?${ paramsString } ` : '' } ` , fetchOptions ) ;
460
460
const reRenderPromise = new ReRenderPromise ( thisPromise , this . unsyncedInputs . clone ( ) ) ;
461
461
this . renderPromiseStack . addPromise ( reRenderPromise ) ;
462
- thisPromise . then ( ( response ) => {
462
+ thisPromise . then ( async ( response ) => {
463
463
if ( action ) {
464
464
this . isActionProcessing = false ;
465
465
}
466
466
467
+ // if the response does not contain a component, render as an error
468
+ const html = await response . text ( ) ;
469
+ if ( response . headers . get ( 'Content-Type' ) !== 'application/vnd.live-component+html' ) {
470
+ this . renderError ( html ) ;
471
+
472
+ return ;
473
+ }
474
+
467
475
// if another re-render is scheduled, do not "run it over"
468
476
if ( this . renderDebounceTimeout ) {
469
477
return ;
470
478
}
471
479
472
480
const isMostRecent = this . renderPromiseStack . removePromise ( thisPromise ) ;
473
481
if ( isMostRecent ) {
474
- response . text ( ) . then ( ( html ) => {
475
- this . _processRerender ( html , response , reRenderPromise . unsyncedInputContainer ) ;
476
- } ) ;
482
+ this . _processRerender ( html , response , reRenderPromise . unsyncedInputContainer ) ;
477
483
}
478
484
} )
479
485
}
@@ -1038,6 +1044,56 @@ export default class extends Controller implements LiveController {
1038
1044
clearInterval ( interval ) ;
1039
1045
} ) ;
1040
1046
}
1047
+
1048
+ // inspired by Livewire!
1049
+ private async renderError ( html : string ) {
1050
+ let modal = document . getElementById ( 'live-component-error' ) ;
1051
+ if ( modal ) {
1052
+ modal . innerHTML = '' ;
1053
+ } else {
1054
+ modal = document . createElement ( 'div' ) ;
1055
+ modal . id = 'live-component-error' ;
1056
+ modal . style . padding = '50px' ;
1057
+ modal . style . backgroundColor = 'rgba(0, 0, 0, .5)' ;
1058
+ modal . style . zIndex = '100000' ;
1059
+ modal . style . position = 'fixed' ;
1060
+ modal . style . width = '100vw' ;
1061
+ modal . style . height = '100vh' ;
1062
+ }
1063
+
1064
+ const iframe = document . createElement ( 'iframe' ) ;
1065
+ iframe . style . borderRadius = '5px' ;
1066
+ iframe . style . width = '100%' ;
1067
+ iframe . style . height = '100%' ;
1068
+ modal . appendChild ( iframe ) ;
1069
+
1070
+ document . body . prepend ( modal ) ;
1071
+ document . body . style . overflow = 'hidden' ;
1072
+ if ( iframe . contentWindow ) {
1073
+ iframe . contentWindow . document . open ( ) ;
1074
+ iframe . contentWindow . document . write ( html ) ;
1075
+ iframe . contentWindow . document . close ( ) ;
1076
+ }
1077
+
1078
+ const closeModal = ( modal : HTMLElement | null ) => {
1079
+ if ( modal ) {
1080
+ modal . outerHTML = ''
1081
+ }
1082
+ document . body . style . overflow = 'visible'
1083
+ }
1084
+
1085
+ // close on click
1086
+ modal . addEventListener ( 'click' , ( ) => closeModal ( modal ) ) ;
1087
+
1088
+ // close on escape
1089
+ modal . setAttribute ( 'tabindex' , '0' ) ;
1090
+ modal . addEventListener ( 'keydown' , e => {
1091
+ if ( e . key === 'Escape' ) {
1092
+ closeModal ( modal ) ;
1093
+ }
1094
+ } ) ;
1095
+ modal . focus ( ) ;
1096
+ }
1041
1097
}
1042
1098
1043
1099
/**
0 commit comments