@@ -10,6 +10,7 @@ import {
1010} from "lit/decorators" ;
1111import { ifDefined } from "lit/directives/if-defined" ;
1212import { fireEvent } from "../common/dom/fire_event" ;
13+ import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin" ;
1314import { haStyleScrollbar } from "../resources/styles" ;
1415import type { HomeAssistant } from "../types" ;
1516import "./ha-dialog-header" ;
@@ -72,7 +73,7 @@ export type DialogWidth = "small" | "medium" | "large" | "full";
7273 * @see https://github.com/home-assistant/frontend/issues/27143
7374 */
7475@customElement ( "ha-wa-dialog" )
75- export class HaWaDialog extends LitElement {
76+ export class HaWaDialog extends ScrollableFadeMixin ( LitElement ) {
7677 @property ( { attribute : false } ) public hass ! : HomeAssistant ;
7778
7879 @property ( { attribute : "aria-labelledby" } )
@@ -113,6 +114,10 @@ export class HaWaDialog extends LitElement {
113114 @state ( )
114115 private _bodyScrolled = false ;
115116
117+ protected get scrollableElement ( ) : HTMLElement | null {
118+ return this . bodyContainer ;
119+ }
120+
116121 protected updated (
117122 changedProperties : Map < string | number | symbol , unknown >
118123 ) : void {
@@ -161,8 +166,11 @@ export class HaWaDialog extends LitElement {
161166 <slot name= "headerActionItems" slot = "actionItems" > </ slot>
162167 </ ha- dialog- header>
163168 </ slot>
164- <div class= "body ha-scrollbar" @scroll = ${ this . _handleBodyScroll } >
165- <slot> </ slot>
169+ <div class= "content-wrapper" >
170+ <div class= "body ha-scrollbar" @scroll = ${ this . _handleBodyScroll } >
171+ <slot> </ slot>
172+ </ div>
173+ ${ this . renderScrollableFades ( ) }
166174 </ div>
167175 <slot name= "footer" slot = "footer" > </ slot>
168176 </ wa- dialog>
@@ -199,165 +207,179 @@ export class HaWaDialog extends LitElement {
199207 this . _bodyScrolled = ( ev . target as HTMLDivElement ) . scrollTop > 0 ;
200208 }
201209
202- static styles = [
203- haStyleScrollbar ,
204- css `
205- wa-dialog {
206- --full-width : var (--ha-dialog-width-full , min (95vw , var (--safe-width )));
207- --width : min (var (--ha-dialog-width-md , 580px ), var (--full-width ));
208- --spacing : var (--dialog-content-padding , var (--ha-space-6 ));
209- --show-duration : var (--ha-dialog-show-duration , 200ms );
210- --hide-duration : var (--ha-dialog-hide-duration , 200ms );
211- --ha-dialog-surface-background : var (
212- --card-background-color ,
213- var (--ha-color-surface-default )
214- );
215- --wa-color-surface-raised : var (
216- --ha-dialog-surface-background ,
217- var (--card-background-color , var (--ha-color-surface-default ))
218- );
219- --wa-panel-border-radius : var (
220- --ha-dialog-border-radius ,
221- var (--ha-border-radius-3xl )
222- );
223- max-width : var (--ha-dialog-max-width , var (--safe-width ));
224- }
225-
226- : host ([width = "small" ]) wa-dialog {
227- --width : min (var (--ha-dialog-width-sm , 320px ), var (--full-width ));
228- }
229-
230- : host ([width = "large" ]) wa-dialog {
231- --width : min (var (--ha-dialog-width-lg , 1024px ), var (--full-width ));
232- }
233-
234- : host ([width = "full" ]) wa-dialog {
235- --width : var (--full-width );
236- }
237-
238- wa-dialog ::part (dialog ) {
239- min-width : var (--width , var (--full-width ));
240- max-width : var (--width , var (--full-width ));
241- max-height : var (
242- --ha-dialog-max-height ,
243- calc (var (--safe-height ) - var (--ha-space-20 ))
244- );
245- min-height : var (--ha-dialog-min-height );
246- margin-top : var (--dialog-surface-margin-top , auto);
247- /* Used to offset the dialog from the safe areas when space is limited */
248- transform : translate (
249- calc (
250- var (--safe-area-offset-left , var (--ha-space-0 )) - var (
251- --safe-area-offset-right ,
252- var (--ha-space-0 )
253- )
254- ),
255- calc (
256- var (--safe-area-offset-top , var (--ha-space-0 )) - var (
257- --safe-area-offset-bottom ,
258- var (--ha-space-0 )
259- )
260- )
261- );
262- display : flex;
263- flex-direction : column;
264- overflow : hidden;
265- }
266-
267- @media all and (max-width : 450px ), all and (max-height : 500px ) {
268- : host ([type = "standard" ]) {
269- --ha-dialog-border-radius : var (--ha-space-0 );
270-
271- wa-dialog {
272- /* Make the container fill the whole screen width and not the safe width */
273- --full-width : var (--ha-dialog-width-full , 100vw );
274- --width : var (--full-width );
275- }
210+ static get styles ( ) {
211+ return [
212+ ...super . styles ,
213+ haStyleScrollbar ,
214+ css `
215+ wa-dialog {
216+ --full-width : var (
217+ --ha-dialog-width-full ,
218+ min (95vw , var (--safe-width ))
219+ );
220+ --width : min (var (--ha-dialog-width-md , 580px ), var (--full-width ));
221+ --spacing : var (--dialog-content-padding , var (--ha-space-6 ));
222+ --show-duration : var (--ha-dialog-show-duration , 200ms );
223+ --hide-duration : var (--ha-dialog-hide-duration , 200ms );
224+ --ha-dialog-surface-background : var (
225+ --card-background-color ,
226+ var (--ha-color-surface-default )
227+ );
228+ --wa-color-surface-raised : var (
229+ --ha-dialog-surface-background ,
230+ var (--card-background-color , var (--ha-color-surface-default ))
231+ );
232+ --wa-panel-border-radius : var (
233+ --ha-dialog-border-radius ,
234+ var (--ha-border-radius-3xl )
235+ );
236+ max-width : var (--ha-dialog-max-width , var (--safe-width ));
237+ }
238+
239+ : host ([width = "small" ]) wa-dialog {
240+ --width : min (var (--ha-dialog-width-sm , 320px ), var (--full-width ));
241+ }
242+
243+ : host ([width = "large" ]) wa-dialog {
244+ --width : min (var (--ha-dialog-width-lg , 1024px ), var (--full-width ));
245+ }
246+
247+ : host ([width = "full" ]) wa-dialog {
248+ --width : var (--full-width );
249+ }
276250
277- wa-dialog ::part (dialog ) {
278- /* Make the dialog fill the whole screen height and not the safe height */
279- min-height : var (--ha-dialog-min-height , 100vh );
280- min-height : var (--ha-dialog-min-height , 100dvh );
281- max-height : var (--ha-dialog-max-height , 100vh );
282- max-height : var (--ha-dialog-max-height , 100dvh );
283- margin-top : 0 ;
284- margin-bottom : 0 ;
285- /* Use safe area as padding instead of the container size */
286- padding-top : var (--safe-area-inset-top );
287- padding-bottom : var (--safe-area-inset-bottom );
288- padding-left : var (--safe-area-inset-left );
289- padding-right : var (--safe-area-inset-right );
290- /* Reset the transform to center the dialog */
291- transform : none;
251+ wa-dialog ::part (dialog ) {
252+ min-width : var (--width , var (--full-width ));
253+ max-width : var (--width , var (--full-width ));
254+ max-height : var (
255+ --ha-dialog-max-height ,
256+ calc (var (--safe-height ) - var (--ha-space-20 ))
257+ );
258+ min-height : var (--ha-dialog-min-height );
259+ margin-top : var (--dialog-surface-margin-top , auto);
260+ /* Used to offset the dialog from the safe areas when space is limited */
261+ transform : translate (
262+ calc (
263+ var (--safe-area-offset-left , var (--ha-space-0 )) - var (
264+ --safe-area-offset-right ,
265+ var (--ha-space-0 )
266+ )
267+ ),
268+ calc (
269+ var (--safe-area-offset-top , var (--ha-space-0 )) - var (
270+ --safe-area-offset-bottom ,
271+ var (--ha-space-0 )
272+ )
273+ )
274+ );
275+ display : flex;
276+ flex-direction : column;
277+ overflow : hidden;
278+ }
279+
280+ @media all and (max-width : 450px ), all and (max-height : 500px ) {
281+ : host ([type = "standard" ]) {
282+ --ha-dialog-border-radius : var (--ha-space-0 );
283+
284+ wa-dialog {
285+ /* Make the container fill the whole screen width and not the safe width */
286+ --full-width : var (--ha-dialog-width-full , 100vw );
287+ --width : var (--full-width );
288+ }
289+
290+ wa-dialog ::part (dialog ) {
291+ /* Make the dialog fill the whole screen height and not the safe height */
292+ min-height : var (--ha-dialog-min-height , 100vh );
293+ min-height : var (--ha-dialog-min-height , 100dvh );
294+ max-height : var (--ha-dialog-max-height , 100vh );
295+ max-height : var (--ha-dialog-max-height , 100dvh );
296+ margin-top : 0 ;
297+ margin-bottom : 0 ;
298+ /* Use safe area as padding instead of the container size */
299+ padding-top : var (--safe-area-inset-top );
300+ padding-bottom : var (--safe-area-inset-bottom );
301+ padding-left : var (--safe-area-inset-left );
302+ padding-right : var (--safe-area-inset-right );
303+ /* Reset the transform to center the dialog */
304+ transform : none;
305+ }
292306 }
293307 }
294- }
295-
296- .header-title-container {
297- display : flex;
298- align-items : center;
299- }
300-
301- .header-title {
302- margin : 0 ;
303- margin-bottom : 0 ;
304- color : var (--ha-dialog-header-title-color , var (--primary-text-color ));
305- font-size : var (
306- --ha-dialog-header-title-font-size ,
307- var (--ha-font-size-2xl )
308- );
309- line-height : var (
310- --ha-dialog-header-title-line-height ,
311- var (--ha-line-height-condensed )
312- );
313- font-weight : var (
314- --ha-dialog-header-title-font-weight ,
315- var (--ha-font-weight-normal )
316- );
317- overflow : hidden;
318- text-overflow : ellipsis;
319- white-space : nowrap;
320- margin-right : var (--ha-space-3 );
321- }
322-
323- wa-dialog ::part (body ) {
324- padding : 0 ;
325- display : flex;
326- flex-direction : column;
327- max-width : 100% ;
328- overflow : hidden;
329- }
330-
331- .body {
332- position : var (--dialog-content-position , relative);
333- padding : 0 var (--dialog-content-padding , var (--ha-space-6 ))
334- var (--dialog-content-padding , var (--ha-space-6 ))
335- var (--dialog-content-padding , var (--ha-space-6 ));
336- overflow : auto;
337- flex-grow : 1 ;
338- }
339- : host ([flexcontent ]) .body {
340- max-width : 100% ;
341- flex : 1 ;
342- display : flex;
343- flex-direction : column;
344- }
345-
346- wa-dialog ::part (footer ) {
347- padding : var (--ha-space-0 );
348- }
349-
350- ::slotted ([slot = "footer" ]) {
351- display : flex;
352- padding : var (--ha-space-3 ) var (--ha-space-4 ) var (--ha-space-4 )
353- var (--ha-space-4 );
354- gap : var (--ha-space-3 );
355- justify-content : flex-end;
356- align-items : center;
357- width : 100% ;
358- }
359- ` ,
360- ] ;
308+
309+ .header-title-container {
310+ display : flex;
311+ align-items : center;
312+ }
313+
314+ .header-title {
315+ margin : 0 ;
316+ margin-bottom : 0 ;
317+ color : var (--ha-dialog-header-title-color , var (--primary-text-color ));
318+ font-size : var (
319+ --ha-dialog-header-title-font-size ,
320+ var (--ha-font-size-2xl )
321+ );
322+ line-height : var (
323+ --ha-dialog-header-title-line-height ,
324+ var (--ha-line-height-condensed )
325+ );
326+ font-weight : var (
327+ --ha-dialog-header-title-font-weight ,
328+ var (--ha-font-weight-normal )
329+ );
330+ overflow : hidden;
331+ text-overflow : ellipsis;
332+ white-space : nowrap;
333+ margin-right : var (--ha-space-3 );
334+ }
335+
336+ wa-dialog ::part (body ) {
337+ padding : 0 ;
338+ display : flex;
339+ flex-direction : column;
340+ max-width : 100% ;
341+ overflow : hidden;
342+ }
343+
344+ .content-wrapper {
345+ position : relative;
346+ flex : 1 ;
347+ display : flex;
348+ flex-direction : column;
349+ min-height : 0 ;
350+ }
351+
352+ .body {
353+ position : var (--dialog-content-position , relative);
354+ padding : 0 var (--dialog-content-padding , var (--ha-space-6 ))
355+ var (--dialog-content-padding , var (--ha-space-6 ))
356+ var (--dialog-content-padding , var (--ha-space-6 ));
357+ overflow : auto;
358+ flex-grow : 1 ;
359+ }
360+ : host ([flexcontent ]) .body {
361+ max-width : 100% ;
362+ flex : 1 ;
363+ display : flex;
364+ flex-direction : column;
365+ }
366+
367+ wa-dialog ::part (footer ) {
368+ padding : var (--ha-space-0 );
369+ }
370+
371+ ::slotted ([slot = "footer" ]) {
372+ display : flex;
373+ padding : var (--ha-space-3 ) var (--ha-space-4 ) var (--ha-space-4 )
374+ var (--ha-space-4 );
375+ gap : var (--ha-space-3 );
376+ justify-content : flex-end;
377+ align-items : center;
378+ width : 100% ;
379+ }
380+ ` ,
381+ ] ;
382+ }
361383}
362384
363385declare global {
0 commit comments