@@ -43,6 +43,7 @@ const FILTER_ID = 'add-filter';
4343 styleUrl : 'filter.style.scss' ,
4444} )
4545export class FilterPanel {
46+ private dialog ?: HTMLDialogElement ;
4647 private filterCaptionsInternal : FilterCaptions = {
4748 title : 'Filter by' ,
4849 ok : 'Close' ,
@@ -187,22 +188,67 @@ export class FilterPanel {
187188 ) ;
188189 }
189190
191+ componentDidRender ( ) {
192+ this . syncDialog ( ) ;
193+ }
194+
195+ private syncDialog ( ) {
196+ if ( ! this . dialog ) {
197+ return ;
198+ }
199+
200+ if ( ! this . changes ) {
201+ if ( this . dialog . open ) {
202+ this . dialog . close ( ) ;
203+ }
204+ return ;
205+ }
206+
207+ if ( ! this . dialog . open ) {
208+ this . dialog . show ( ) ;
209+ }
210+
211+ if ( this . changes . autoCorrect !== false ) {
212+ requestAnimationFrame ( ( ) => this . autoCorrect ( this . dialog ) ) ;
213+ }
214+ }
215+
190216 private autoCorrect ( el ?: HTMLElement | null ) {
191217 if ( ! el ) {
192218 return ;
193219 }
194220
195- const revoGrid = el . closest ( 'revo-grid' ) ;
196- if ( ! revoGrid ) {
221+ const pos = el . getBoundingClientRect ( ) ;
222+ const maxLeft = Math . max ( 0 , window . innerWidth - pos . width ) ;
223+ const maxTop = Math . max ( 0 , window . innerHeight - pos . height ) ;
224+
225+ if ( pos . left > maxLeft ) {
226+ el . style . left = `${ maxLeft } px` ;
227+ }
228+
229+ if ( pos . top > maxTop ) {
230+ el . style . top = `${ maxTop } px` ;
231+ }
232+ }
233+
234+ private onDialogMouseDown ( e : MouseEvent ) {
235+ if (
236+ ! this . closeOnOutsideClick ||
237+ e . target !== this . dialog ||
238+ ! this . dialog
239+ ) {
197240 return ;
198241 }
199242
200- const pos = el . getBoundingClientRect ( ) ;
201- const gridPos = revoGrid . getBoundingClientRect ( ) ;
202- const maxLeft = gridPos . right - pos . width ;
243+ const rect = this . dialog . getBoundingClientRect ( ) ;
244+ const isInside =
245+ e . clientX >= rect . left &&
246+ e . clientX <= rect . right &&
247+ e . clientY >= rect . top &&
248+ e . clientY <= rect . bottom ;
203249
204- if ( pos . left > maxLeft && el . offsetLeft ) {
205- el . style . left = ` ${ maxLeft - ( el . parentElement ?. getBoundingClientRect ( ) . left ?? 0 ) } px` ;
250+ if ( ! isInside ) {
251+ this . onCancel ( ) ;
206252 }
207253 }
208254
@@ -469,13 +515,9 @@ export class FilterPanel {
469515 }
470516
471517 render ( ) {
472- if ( ! this . changes ) {
473- return < Host style = { { display : 'none' } } > </ Host > ;
474- }
475518 const style = {
476- display : 'block' ,
477- left : `${ this . changes . x } px` ,
478- top : `${ this . changes . y } px` ,
519+ left : `${ this . changes ?. x ?? 0 } px` ,
520+ top : `${ this . changes ?. y ?? 0 } px` ,
479521 } ;
480522
481523 const capts = Object . assign (
@@ -484,72 +526,78 @@ export class FilterPanel {
484526 ) ;
485527
486528 return (
487- < Host
488- style = { style }
489- ref = { el => {
490- this . changes ?. autoCorrect !== false && this . autoCorrect ( el ) ;
491- } }
492- >
493- < slot slot = "header" />
494- { this . changes . extraContent ?.( this . changes ) || '' }
495-
496- { this . changes ?. hideDefaultFilters !== true && (
497- [
498- < label > { capts . title } </ label > ,
499- < div class = "filter-holder" > { this . getFilterItemsList ( ) } </ div > ,
500- < div class = "add-filter" >
501- < select
502- id = { FILTER_ID }
503- class = "select-css"
504- onChange = { e => this . onAddNewFilter ( e ) }
505- >
506- { this . renderSelectOptions ( this . currentFilterType ) }
507- </ select >
508- </ div >
509- ]
510- ) }
511-
512- < slot />
513- < div class = "filter-actions" >
514- { this . disableDynamicFiltering && [
515- < button
516- id = "revo-button-save"
517- aria-label = "save"
518- class = "revo-button green"
519- onClick = { ( ) => this . onSave ( ) }
520- >
521- { capts . save }
522- </ button > ,
523- < button
524- id = "revo-button-ok"
525- aria-label = "ok"
526- class = "revo-button green"
527- onClick = { ( ) => this . onCancel ( ) }
528- >
529- { capts . cancel }
530- </ button > ,
531- ] }
532- { ! this . disableDynamicFiltering && [
533- < button
534- id = "revo-button-ok"
535- aria-label = "ok"
536- class = "revo-button green"
537- onClick = { ( ) => this . onCancel ( ) }
538- >
539- { capts . ok }
540- </ button > ,
541-
542- < button
543- id = "revo-button-reset"
544- aria-label = "reset"
545- class = "revo-button outline"
546- onClick = { ( ) => this . onReset ( ) }
547- >
548- { capts . reset }
549- </ button > ,
529+ < Host >
530+ < dialog
531+ class = "filter-panel-dialog"
532+ style = { style }
533+ ref = { el => ( this . dialog = el ) }
534+ onCancel = { e => {
535+ e . preventDefault ( ) ;
536+ this . onCancel ( ) ;
537+ } }
538+ onMouseDown = { e => this . onDialogMouseDown ( e ) }
539+ >
540+ { this . changes && [
541+ < slot slot = "header" /> ,
542+ this . changes . extraContent ?.( this . changes ) || '' ,
543+
544+ this . changes ?. hideDefaultFilters !== true && [
545+ < label > { capts . title } </ label > ,
546+ < div class = "filter-holder" > { this . getFilterItemsList ( ) } </ div > ,
547+ < div class = "add-filter" >
548+ < select
549+ id = { FILTER_ID }
550+ class = "select-css"
551+ onChange = { e => this . onAddNewFilter ( e ) }
552+ >
553+ { this . renderSelectOptions ( this . currentFilterType ) }
554+ </ select >
555+ </ div > ,
556+ ] ,
557+
558+ < slot /> ,
559+ < div class = "filter-actions" >
560+ { this . disableDynamicFiltering && [
561+ < button
562+ id = "revo-button-save"
563+ aria-label = "save"
564+ class = "revo-button green"
565+ onClick = { ( ) => this . onSave ( ) }
566+ >
567+ { capts . save }
568+ </ button > ,
569+ < button
570+ id = "revo-button-ok"
571+ aria-label = "ok"
572+ class = "revo-button green"
573+ onClick = { ( ) => this . onCancel ( ) }
574+ >
575+ { capts . cancel }
576+ </ button > ,
577+ ] }
578+ { ! this . disableDynamicFiltering && [
579+ < button
580+ id = "revo-button-ok"
581+ aria-label = "ok"
582+ class = "revo-button green"
583+ onClick = { ( ) => this . onCancel ( ) }
584+ >
585+ { capts . ok }
586+ </ button > ,
587+
588+ < button
589+ id = "revo-button-reset"
590+ aria-label = "reset"
591+ class = "revo-button outline"
592+ onClick = { ( ) => this . onReset ( ) }
593+ >
594+ { capts . reset }
595+ </ button > ,
596+ ] }
597+ </ div > ,
598+ < slot slot = "footer" /> ,
550599 ] }
551- </ div >
552- < slot slot = "footer" />
600+ </ dialog >
553601 </ Host >
554602 ) ;
555603 }
0 commit comments