Skip to content

Commit ed8ccbe

Browse files
authored
Add scrollable fade mixin to ha-wa-dialog (#28346)
1 parent 420f88f commit ed8ccbe

File tree

1 file changed

+181
-159
lines changed

1 file changed

+181
-159
lines changed

src/components/ha-wa-dialog.ts

Lines changed: 181 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from "lit/decorators";
1111
import { ifDefined } from "lit/directives/if-defined";
1212
import { fireEvent } from "../common/dom/fire_event";
13+
import { ScrollableFadeMixin } from "../mixins/scrollable-fade-mixin";
1314
import { haStyleScrollbar } from "../resources/styles";
1415
import type { HomeAssistant } from "../types";
1516
import "./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

363385
declare global {

0 commit comments

Comments
 (0)