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:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>`,
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
})),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user