11let commandsInstalled : boolean ;
2+ const triggers = new WeakMap < Element , Element > ( ) ;
23
34export function installCommands ( ) {
45 if ( commandsInstalled ) return ;
56 commandsInstalled = true ;
67 if ( 'commandFor' in HTMLButtonElement . prototype ) return ;
78 addEventListener ( 'click' , commandClickHandler ) ;
9+ addEventListener ( 'toggle' , dialogToggleHandler , true ) ;
10+ addEventListener ( 'show' , dialogToggleHandler , true ) ;
811}
912
1013function elementTarget ( node : EventTarget ) {
@@ -13,6 +16,46 @@ function elementTarget(node: EventTarget) {
1316 : ( ( node as Node ) . parentNode as Element ) ;
1417}
1518
19+ function positionDialog ( target : HTMLDialogElement , trigger : Element ) {
20+ const a = trigger . getBoundingClientRect ( ) ;
21+ const t = target . style . transform ;
22+ target . style . setProperty ( 'transform' , 'none' ) ;
23+ const d = target . getBoundingClientRect ( ) ;
24+ if ( t ) target . style . setProperty ( 'transform' , t ) ;
25+ else target . style . removeProperty ( 'transform' ) ;
26+ target . style . setProperty ( '--p-anchor-left' , `${ a . left } px` ) ;
27+ target . style . setProperty ( '--p-anchor-top' , `${ a . top } px` ) ;
28+ target . style . setProperty ( '--p-anchor-width' , `${ a . width } px` ) ;
29+ target . style . setProperty ( '--p-anchor-height' , `${ a . height } px` ) ;
30+ target . style . setProperty ( '--p-content-width' , `${ d . width } px` ) ;
31+ target . style . setProperty ( '--p-content-height' , `${ d . height } px` ) ;
32+ const flipX = a . left + d . width > innerWidth && a . left + a . width > d . width ;
33+ const flipY =
34+ a . top + a . height + d . height > innerHeight && a . top > d . height ;
35+ let flip = '' ;
36+ if ( flipX ) flip += ' x' ;
37+ if ( flipY ) flip += ' y' ;
38+ target . setAttribute ( 'data-flip' , flip ) ;
39+ }
40+
41+ let resizeInstalled : boolean ;
42+ function ensureResize ( ) {
43+ if ( resizeInstalled ) return ;
44+ resizeInstalled = true ;
45+ addEventListener (
46+ 'resize' ,
47+ ( ) => {
48+ document
49+ . querySelectorAll < HTMLDialogElement > ( 'dialog[p][open]' )
50+ . forEach ( ( el ) => {
51+ const trig = triggers . get ( el ) ;
52+ if ( trig ) positionDialog ( el , trig ) ;
53+ } ) ;
54+ } ,
55+ { passive : true } ,
56+ ) ;
57+ }
58+
1659function commandClickHandler ( e : MouseEvent ) {
1760 const el = elementTarget ( e . target ! ) ;
1861 const trigger = el . closest < Element > ( '[command]' ) ;
@@ -37,9 +80,19 @@ function commandClickHandler(e: MouseEvent) {
3780 }
3881
3982 const method = command . replace ( / - ( [ a - z ] ) / g, ( _ , c ) => c . toUpperCase ( ) ) ;
83+ if ( target instanceof HTMLDialogElement ) triggers . set ( target , trigger ) ;
4084 ( target as any ) [ method ] ?.( ) ;
4185}
4286
87+ function dialogToggleHandler ( e : Event ) {
88+ const target = e . target as Element ;
89+ if ( target instanceof HTMLDialogElement && target . open ) {
90+ const trig = triggers . get ( target ) ;
91+ if ( trig ) positionDialog ( target , trig ) ;
92+ ensureResize ( ) ;
93+ }
94+ }
95+
4396let dialogsDropdownsInstalled : boolean ;
4497export function installDialogsDropdowns ( ) {
4598 if ( dialogsDropdownsInstalled ) return ;
0 commit comments