1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[CL-725] dialog adjustments (#15660)

* update dialog spacing/borders

* update scroll bottom threshold

* add shadow to dialog

* adjust simple dialog shadow

* update scroll util comment

* add background input to other dialog stories

* assign initial value to isScrollable

* add larger padding on alt background content

* update tab border color

* update tab content padding

* update tab content spacing

* revert tab border color change

* bring back tab border color changes

* update web header border to match new tab border

* add background to props in story
This commit is contained in:
Bryan Cunningham
2025-08-11 11:33:09 -04:00
committed by GitHub
parent d3c6ba9f4b
commit af12e376f7
9 changed files with 49 additions and 22 deletions

View File

@@ -1,18 +1,18 @@
@let isDrawer = dialogRef?.isDrawer;
<section
class="tw-flex tw-w-full tw-flex-col tw-self-center tw-overflow-hidden tw-border tw-border-solid tw-border-secondary-300 tw-bg-background tw-text-main"
[ngClass]="[width, isDrawer ? 'tw-h-screen tw-border-t-0' : 'tw-rounded-xl']"
class="tw-flex tw-w-full tw-flex-col tw-self-center tw-overflow-hidden tw-border tw-border-solid tw-border-secondary-100 tw-bg-background tw-text-main"
[ngClass]="[width, isDrawer ? 'tw-h-screen tw-border-t-0' : 'tw-rounded-xl tw-shadow-lg']"
@fadeIn
cdkTrapFocus
cdkTrapFocusAutoCapture
>
@let showHeaderBorder = !isDrawer || background() === "alt" || bodyHasScrolledFrom().top;
@let showHeaderBorder = bodyHasScrolledFrom().top;
<header
class="tw-flex tw-justify-between tw-items-center tw-gap-4 tw-border-0 tw-border-b tw-border-solid"
class="tw-flex tw-justify-between tw-items-center tw-gap-4 tw-border-0 tw-border-b tw-border-solid tw-py-3 tw-ps-6 tw-pe-4"
[ngClass]="{
'tw-p-4 has-[[biticonbutton]]:tw-pe-2': !isDrawer,
'tw-px-6 tw-py-4 has-[[biticonbutton]]:tw-pe-4': isDrawer,
'tw-border-secondary-300': showHeaderBorder,
'tw-border-secondary-100': showHeaderBorder,
'tw-border-transparent': !showHeaderBorder,
}"
>
@@ -59,25 +59,25 @@
<div
cdkScrollable
[ngClass]="{
'tw-p-4': !disablePadding() && !isDrawer,
'tw-px-6 tw-py-4': !disablePadding() && isDrawer,
'tw-py-2 tw-ps-6 tw-pe-6': !disablePadding(),
'tw-overflow-y-auto': !loading(),
'tw-invisible tw-overflow-y-hidden': loading(),
'tw-py-4': background() === 'alt',
}"
>
<ng-content select="[bitDialogContent]"></ng-content>
</div>
</div>
@let showFooterBorder = !isDrawer || background() === "alt" || bodyHasScrolledFrom().bottom;
@let showFooterBorder =
(!bodyHasScrolledFrom().top && isScrollable) || bodyHasScrolledFrom().bottom;
<footer
class="tw-flex tw-flex-row tw-items-center tw-gap-2 tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-bg-background"
[ngClass]="[isDrawer ? 'tw-px-6 tw-py-4' : 'tw-p-4']"
class="tw-flex tw-flex-row tw-items-center tw-gap-2 tw-border-0 tw-border-t tw-border-solid tw-bg-background tw-py-5 tw-ps-6 tw-pe-4"
[ngClass]="{
'tw-px-6 tw-py-4': isDrawer,
'tw-p-4 has-[[biticonbutton]]:tw-pe-2': !isDrawer,
'tw-border-secondary-300': showFooterBorder,
'tw-border-transparent': !showFooterBorder,
'tw-border-secondary-100': showFooterBorder,
}"
>
<ng-content select="[bitDialogFooter]"></ng-content>

View File

@@ -1,7 +1,15 @@
import { CdkTrapFocus } from "@angular/cdk/a11y";
import { CdkScrollable } from "@angular/cdk/scrolling";
import { CommonModule } from "@angular/common";
import { Component, HostBinding, inject, viewChild, input, booleanAttribute } from "@angular/core";
import {
Component,
HostBinding,
inject,
viewChild,
input,
booleanAttribute,
AfterViewInit,
} from "@angular/core";
import { I18nPipe } from "@bitwarden/ui-common";
@@ -31,10 +39,11 @@ import { DialogTitleContainerDirective } from "../directives/dialog-title-contai
CdkScrollable,
],
})
export class DialogComponent {
export class DialogComponent implements AfterViewInit {
protected dialogRef = inject(DialogRef, { optional: true });
private scrollableBody = viewChild.required(CdkScrollable);
protected bodyHasScrolledFrom = hasScrolledFrom(this.scrollableBody);
protected isScrollable = false;
/** Background color */
readonly background = input<"default" | "alt">("default");
@@ -96,4 +105,13 @@ export class DialogComponent {
}
}
}
ngAfterViewInit() {
this.isScrollable = this.canScroll();
}
canScroll(): boolean {
const el = this.scrollableBody().getElementRef().nativeElement as HTMLElement;
return el.scrollHeight > el.clientHeight;
}
}

View File

@@ -64,6 +64,13 @@ export default {
disable: true,
},
},
background: {
options: ["alt", "default"],
control: { type: "radio" },
table: {
defaultValue: "default",
},
},
},
parameters: {
design: {
@@ -144,7 +151,7 @@ export const ScrollingContent: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<bit-dialog title="Scrolling Example" [dialogSize]="dialogSize" [loading]="loading" [disablePadding]="disablePadding">
<bit-dialog title="Scrolling Example" [background]="background" [dialogSize]="dialogSize" [loading]="loading" [disablePadding]="disablePadding">
<span bitDialogContent>
Dialog body text goes here.<br />
<ng-container *ngFor="let _ of [].constructor(100)">
@@ -168,7 +175,7 @@ export const TabContent: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<bit-dialog title="Tab Content Example" [dialogSize]="dialogSize" [disablePadding]="disablePadding">
<bit-dialog title="Tab Content Example" [background]="background" [dialogSize]="dialogSize" [disablePadding]="disablePadding">
<span bitDialogContent>
<bit-tab-group>
<bit-tab label="First Tab">First Tab Content</bit-tab>
@@ -205,7 +212,7 @@ export const WithCards: Story = {
},
template: /*html*/ `
<form [formGroup]="formObj">
<bit-dialog background="alt" [dialogSize]="dialogSize" [title]="title" [subtitle]="subtitle" [loading]="loading" [disablePadding]="disablePadding">
<bit-dialog [dialogSize]="dialogSize" [background]="background" [title]="title" [subtitle]="subtitle" [loading]="loading" [disablePadding]="disablePadding">
<ng-container bitDialogContent>
<bit-section>
<bit-section-header>
@@ -269,5 +276,6 @@ export const WithCards: Story = {
dialogSize: "default",
title: "Default",
subtitle: "Subtitle",
background: "alt",
},
};

View File

@@ -1,5 +1,5 @@
<div
class="tw-my-4 tw-pb-6 tw-pt-8 tw-flex tw-max-h-screen tw-w-96 tw-max-w-90vw tw-flex-col tw-overflow-hidden tw-rounded-3xl tw-border tw-border-solid tw-border-secondary-100 tw-shadow-xl tw-bg-text-contrast tw-text-main"
class="tw-my-4 tw-pb-6 tw-pt-8 tw-flex tw-max-h-screen tw-w-96 tw-max-w-90vw tw-flex-col tw-overflow-hidden tw-rounded-3xl tw-border tw-border-solid tw-border-secondary-100 tw-shadow-lg tw-bg-text-contrast tw-text-main"
@fadeIn
>
<div class="tw-flex tw-px-6 tw-flex-col tw-items-center tw-gap-2 tw-text-center">

View File

@@ -7,7 +7,7 @@ import { Component } from "@angular/core";
selector: "bit-tab-header",
host: {
class:
"tw-h-16 tw-ps-4 tw-bg-background-alt tw-flex tw-items-end tw-border-0 tw-border-b tw-border-solid tw-border-secondary-300",
"tw-h-16 tw-ps-4 tw-bg-background-alt tw-flex tw-items-end tw-border-0 tw-border-b tw-border-solid tw-border-secondary-100",
},
template: `<ng-content></ng-content>`,
})

View File

@@ -84,7 +84,7 @@ export class TabListItemDirective implements FocusableOption {
get activeClassList(): string[] {
return [
"tw--mb-px",
"tw-border-x-secondary-300",
"tw-border-x-secondary-100",
"tw-border-t-primary-600",
"tw-border-b",
"tw-border-b-background",

View File

@@ -29,7 +29,7 @@
}
</div>
</bit-tab-header>
<div class="tw-px-4 tw-pt-5">
<div class="tw-px-6 tw-pt-5">
@for (tab of tabs; track tab; let i = $index) {
<bit-tab-body
role="tabpanel"

View File

@@ -26,7 +26,8 @@ export const hasScrolledFrom = (scrollable?: Signal<CdkScrollable>): Signal<Scro
startWith(null),
map(() => ({
top: _scrollable.measureScrollOffset("top") > 0,
bottom: _scrollable.measureScrollOffset("bottom") > 0,
// Using 1 as the threshold here because `_scrollable.measureScrollOffset("bottom")` returns '0.5' at the bottom most position in Chrome
bottom: _scrollable.measureScrollOffset("bottom") > 1,
})),
),
),