Skip to content

Commit

Permalink
close the gap on modal components
Browse files Browse the repository at this point in the history
  • Loading branch information
pontus-github committed Dec 20, 2024
1 parent 681e857 commit 6732674
Show file tree
Hide file tree
Showing 15 changed files with 533 additions and 93 deletions.
15 changes: 6 additions & 9 deletions libs/angular/src/v-angular/modal/dialog/dialog.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
class="sdv-modal-dialog__container"
class="modal-dialog__container"
*transloco="let t"
#dialog
role="dialog"
Expand All @@ -10,17 +10,14 @@
<header class="modal-dialog__heading">
<h3 [attr.id]="dialogTitleId">{{ t(heading || title || '') }}</h3>
<button
type="button"
data-thook="dialog-close"
(click)="onAction($event, 'close')"
(keydown.enter)="onAction($event, 'close')"
class="close"
[attr.aria-label]="closeButtonAriaLabel"
class="nggv-modal-slideout__close"
>
<gds-icon-cross-small
*nggCoreElement
width="24"
height="24"
></gds-icon-cross-small>
<span className="sr-only">Close</span>
<i></i>
</button>
</header>
<section class="modal-dialog__body" [attr.id]="dialogBodyId">
Expand Down Expand Up @@ -61,4 +58,4 @@ <h3 [attr.id]="dialogTitleId">{{ t(heading || title || '') }}</h3>
</footer>
</div>

<div class="sdv-modal-backdrop"></div>
<div class="nggv-backdrop"></div>
56 changes: 47 additions & 9 deletions libs/angular/src/v-angular/modal/dialog/dialog.component.scss
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
@use '../../../../../chlorophyll/scss/components/modal/mixins' as mixins;
@use '../../../../../chlorophyll/scss/components/backdrop' as backdrop;
@use '../../../../../chlorophyll/scss/components/button';

@use '../../../../../chlorophyll/scss/components/close/mixins' as close;
@use '../../../../../chlorophyll/scss/common' as common;
@use '../../../../../chlorophyll/scss/components/button/mixins' as button;

:host {
--sg-hsl-contrast: 0deg, 0%, 0%;
--background-hsl: 0deg, 0%, 0%;
--grey-500: rgb(222, 222, 222);
--text-primary-color: rgb(51, 51, 51);
--gds-ref-pallet-base200: hsl(0, 0%, 91%);
--gds-sys-color-base: hsl(0, 0%, 20%);
--gds-sys-shape-corner-round: 50%;
--gds-sys-color-font : hsl(0, 0%, 20%);

--sg-modal-box-shadow: 0 0.125rem 0.375rem rgba(0, 0, 0, 0.15);
--sg-modal-background: #fff;
--sg-z-index-modal: 1050;
--sg-modal-backdrop-background: rgba(0, 0, 0, 0.5);
--sg-z-index-modal-backdrop: 1040;


--sg-border-radius: 0.25rem;
--sg-border-width: 1px;
--sg-border-color: hsl(0, 0%, 53%);
@include mixins.dialog-modal-wrapper();

.sdv-modal-dialog__container {
.modal-dialog__container {
@include mixins.modal();
@include mixins.dialog-modal();
}

.modal-dialog__heading {
box-sizing: border-box;
@include mixins.modal-header();

button {
display: grid;
place-content: center;
}
}

.modal-dialog__body {
Expand All @@ -28,7 +45,28 @@
box-sizing: border-box;
}

.sdv-modal-backdrop {
@include backdrop.add-backdrop(rgba(0, 0, 0, 0.35), 999);

.nggv-backdrop {
@include mixins.modal-backdrop;
}

.nggv-modal-slideout__close {
@include close.close;
}

.modal-dialog__actions{
button {
@include button.reset;
@include button.base;
}
.submit {
@include button.primary;
}
.secondary {
@include button.secondary;
}
.danger {
@include button.danger-color;
}
}
}
50 changes: 41 additions & 9 deletions libs/angular/src/v-angular/modal/dialog/dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Input,
OnInit,
Output,
Renderer2,
ViewChild,
} from '@angular/core'

Expand All @@ -27,11 +28,23 @@ export class NgvDialogComponent implements OnInit {
@ViewChild('dialog') dialogRef: ElementRef | undefined

/** Special property used for selecting DOM elements during automated UI testing. */
@HostBinding('attr.data-thook') @Input() thook = 'dialog'
@HostBinding('attr.data-thook') @Input() thook: string | null | undefined = 'dialog'
/** @internal */
@HostBinding('class.sdv-modal-dialog') baseClass = true
/** @internal Defines the default visibility state of the dialog. */
@HostBinding('class.-active') @Input() shown = false
@HostBinding('class.-active') _shown = false;
@Input() set shown(value: boolean) {
this._shown = value;
if (value) {
this.hideOverflow();
} else {
this.resetOverflow();
}
}
get shown() {
return this._shown;
}

/** @internal */
@HostBinding('attr.aria-hidden') get ariaHidden() {
return !this.shown
Expand All @@ -53,9 +66,12 @@ export class NgvDialogComponent implements OnInit {
@Input() payload: any = {}

@Input() dialogTitleId!: string
@Input() dialogBodyId!: string
/** Pass the null if you don't want dialog body to be announced by the screen reader */
@Input() dialogBodyId!: string | null;
/** It gives an ability for parent component to control if modal should be closed on esc button click. */
@Input() closeModalOnEscape = true
/** Aria label for the Close button with "X" icon, in the header */
@Input() closeButtonAriaLabel?: string;

_buttons: DialogButtons | undefined
/** Buttons are defined as a key-value pair where key is one of "positive|neutral|negative" and value is the button label. */
Expand All @@ -74,13 +90,16 @@ export class NgvDialogComponent implements OnInit {
protected _firstFocusable: HTMLElement | undefined
protected _lastFocusable: HTMLElement | undefined

constructor(private renderer: Renderer2) {}

ngOnInit() {
this.dialogTitleId =
this.dialogTitleId ?? 'sdv-dialog-title-' + window.nggv?.nextId()
this.dialogBodyId =
this.dialogBodyId ?? 'sdv-dialog-body-' + window.nggv?.nextId()
if (this.dialogBodyId !== null) {
this.dialogBodyId = this.dialogBodyId ?? 'sdv-dialog-body-' + window.nggv?.nextId();
}

this.shown = this.initiallyShown
this._shown = this.initiallyShown;
if (this.shown) this._limitFocusable()
}

Expand All @@ -106,8 +125,9 @@ export class NgvDialogComponent implements OnInit {
}

open(opener?: HTMLElement) {
this.shown = true
this._shown = true
this._previous = opener || (document.activeElement as HTMLElement)
this.hideOverflow();
this._limitFocusable()
return true
}
Expand All @@ -120,7 +140,7 @@ export class NgvDialogComponent implements OnInit {
)
this._firstFocusable = focusable[0]
this._lastFocusable = focusable[focusable.length - 1]
if (this._lastFocusable) this._lastFocusable.focus()
if (this._firstFocusable) this._firstFocusable.focus();
})
}

Expand All @@ -137,7 +157,10 @@ export class NgvDialogComponent implements OnInit {
}
this.nggvCloseEvent.emit(emitEvent)
}
this.shown = false

this.resetOverflow();

this._shown = false;
window.setTimeout(() => {
if (this._previous) this._previous.focus()
this._previous = undefined
Expand Down Expand Up @@ -167,4 +190,13 @@ export class NgvDialogComponent implements OnInit {
}
}
}

// to prevent background scrolling when modal is open
private hideOverflow(): void {
this.renderer.setStyle(document.body, 'overflow', 'hidden');
}

private resetOverflow(): void {
this.renderer.removeStyle(document.body, 'overflow');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const Template: StoryFn<NgvDialogComponent> = (args: any) => ({
export const Primary = Template.bind({})
Primary.args = {
initiallyShown: true,
closeButtonAriaLabel: 'Close dialog',
buttons: {
negative: 'button_cancel',
neutral: 'button_apply',
Expand Down
35 changes: 25 additions & 10 deletions libs/angular/src/v-angular/modal/fold-out/fold-out.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,36 @@
<button
data-thook="fold-out-toggle"
class="fold-out-button"
[ngClass]="{'no-text': !text}"
(click)="toggleVisibility($event)"
[attr.aria-expanded]="shown"
[attr.aria-label]="ariaLabel">
<ng-container *ngTemplateOutlet="text ? withText : default">
</ng-container>
</button>

<div #childrenContainer
class="nggv-fold-out__popover"
[ngClass]="{ 'flex-right': alignOptions === 'right' }"
[class.nggv-fold-out__popover-expanded]="shown"
>
<ng-content></ng-content>
</div>
</div>

<ng-template #withText>
{{ text }}
<gds-icon-dot-grid-one-horizontal
width="24"
height="24"
*nggCoreElement
></gds-icon-dot-grid-one-horizontal>
</button>
</ng-template>

<div
class="gds-fold-out__popover"
[ngClass]="{ 'flex-right': alignOptions === 'right' }"
[class.gds-fold-out__popover-expanded]="shown"
(click)="toggleVisibility($event, false)"
>
<ng-content></ng-content>
</div>
</div>
<ng-template #default>
<gds-icon-dot-grid-one-horizontal
width="24"
height="24"
*nggCoreElement
></gds-icon-dot-grid-one-horizontal>
<ng-template>
27 changes: 24 additions & 3 deletions libs/angular/src/v-angular/modal/fold-out/fold-out.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
@use '../../../../../chlorophyll/scss/components/dropdown/mixins' as dropdown;

:host {
--grey-400: rgb(233, 233, 233);
--grey-500: rgb(222, 222, 222);

.flex-right {
right: 0;
}
Expand All @@ -18,13 +21,14 @@
border-color: transparent;
color: var(--gds-ref-pallet-base800);
display: flex;
align-items: center;
gap: 0.5rem;
line-height: 0.75;
padding-inline: 0.4375rem;
width: auto;
}

.gds-fold-out__popover {
.nggv-fold-out__popover {
@include card.card();
width: fit-content;
display: none;
Expand All @@ -42,17 +46,34 @@
display: flex;
gap: 0.75rem;
user-select: none;
&.delete-option {
color: tokens.get(tokens.$red, 0);
}
}

::ng-deep .nggv-field-dropdown__options__label:hover,
::ng-deep .nggv-field-dropdown__options__label:focus-visible {
background-color: var(--grey-400);
::ng-deep .nggv-field-dropdown__options__label:focus-visible,
::ng-deep .nggv-field-dropdown__options__label[aria-focus='true'] {
background-color: var(--grey-400);
}

::ng-deep .nggv-field-dropdown__options__label.delete-option:hover,
::ng-deep .nggv-field-dropdown__options__label.delete-option:focus-visible,
::ng-deep .nggv-field-dropdown__options__label.delete-option[aria-focus='true'] {
background-color: tokens.get(tokens.$red, 1);
color: common.most-legible-color(tokens.get(tokens.$red, 1));
}


::ng-deep .nggv-field-dropdown__options__label:active {
background-color: var(--grey-500);
}

::ng-deep .nggv-field-dropdown__options__label.delete-option:active {
background-color: tokens.get(tokens.$red, 0);
color: common.most-legible-color(tokens.get(tokens.$red, 0));
}

::ng-deep .nggv-field-dropdown__options__label:focus-visible {
outline-color: #000;
outline-offset: -0.25rem;
Expand Down
Loading

0 comments on commit 6732674

Please sign in to comment.