Skip to content

Commit

Permalink
feat(modal, wizard): add full-screen size option
Browse files Browse the repository at this point in the history
A full-screen modal or wizard will take up all available screen space
except for some padding on all four sides.

Other changes:
- adjust static css-only modal story styles to accommodate full-screen modals
- add an option for long content inside the modal to test scrolling within the modal

CDE-1789
  • Loading branch information
kevinbuhmann committed Mar 26, 2024
1 parent cab5c7b commit 4b19c42
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 8 deletions.
24 changes: 21 additions & 3 deletions .storybook/stories/modal/modal-static.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default {
}),
],
argTypes: {
size: { defaultValue: 'md', control: { type: 'radio', options: ['sm', 'md', 'lg', 'xl'] } },
size: { defaultValue: 'md', control: { type: 'radio', options: ['sm', 'md', 'lg', 'xl', 'full-screen'] } },
},
args: {
title: 'Small Modal',
Expand All @@ -33,8 +33,17 @@ const ModalStaticTemplate: Story = args => ({
position: relative;
padding: 24px;
}
.backdrop-example-container.full-screen {
padding: 0;
height: 400px;
}
.modal.static {
position: relative;
}
.modal:not(.modal-full-screen).static {
padding: 72px;
}
Expand All @@ -46,8 +55,8 @@ const ModalStaticTemplate: Story = args => ({
left: 0;
}
</style>
<div class="backdrop-example-container">
<div class="modal static">
<div class="backdrop-example-container" [ngClass]="{ 'full-screen': size === 'full-screen' }">
<div class="modal modal-{{ size }} static">
<div class="modal-dialog modal-{{ size }}" role="dialog" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -99,3 +108,12 @@ export const ExtraLargeModal: StoryObj = {
size: 'xl',
},
};

export const FullScreenModal: StoryObj = {
render: ModalStaticTemplate,
args: {
title: 'Full-Screen Modal',
body: 'This is a full-screen modal.',
size: 'full-screen',
},
};
21 changes: 20 additions & 1 deletion .storybook/stories/modal/modal.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default {
// inputs
clrModalCloseButtonAriaLabel: { type: 'string', defaultValue: commonStringsDefault.close },
clrModalLabelledById: { defaultValue: '' },
clrModalSize: { defaultValue: 'md', control: { type: 'radio', options: ['sm', 'md', 'lg', 'xl'] } },
clrModalSize: { defaultValue: 'md', control: { type: 'radio', options: ['sm', 'md', 'lg', 'xl', 'full-screen'] } },
clrModalSkipAnimation: { defaultValue: false, control: { type: 'boolean' } },
// outputs
clrModalAlternateClose: { control: { disable: true } },
Expand All @@ -44,6 +44,7 @@ export default {
title: 'Modal Title',
body: 'Hello World!',
showLongPageContent: true,
showLongModalContent: false,
},
};

Expand Down Expand Up @@ -71,6 +72,12 @@ const ModalTemplate: Story = args => ({
<h3 class="modal-title">{{ title }}</h3>
<div class="modal-body">
{{ body }}
<div *ngIf="showLongModalContent" cds-layout="m-t:md">
This list is provided to demonstrate scrolling capability within the modal.
<ul>
<li *ngFor="let _ of createArray(100); let i = index">{{ i + 1 }}</li>
</ul>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="clrModalOpen = false">Cancel</button>
Expand Down Expand Up @@ -133,6 +140,18 @@ export const OpenExtraLargeModal: StoryObj = {
},
};

export const OpenFullScreenModal: StoryObj = {
render: ModalTemplate,
play: removeFocusOutline,
args: {
clrModalOpen: true,
clrModalSize: 'full-screen',
title: 'Full-Screen Modal',
body: 'This is a full-screen modal.',
showLongPageContent: false,
},
};

function removeFocusOutline({ canvasElement }: StoryContext) {
// remove keyboard focus outline from modal title
canvasElement.querySelector<HTMLElement>(':focus').blur();
Expand Down
12 changes: 11 additions & 1 deletion .storybook/stories/wizard/wizard.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export default {
clrWizardPreventDefaultNext: { defaultValue: false },
clrWizardPreventDefaultCancel: { defaultValue: false },
clrWizardStepnavAriaLabel: { defaultValue: commonStringsDefault.wizardStepnavAriaLabel },
clrWizardSize: { defaultValue: 'xl', control: { type: 'inline-radio', options: ['sm', 'md', 'lg', 'xl'] } },
clrWizardSize: {
defaultValue: 'xl',
control: { type: 'inline-radio', options: ['sm', 'md', 'lg', 'xl', 'full-screen'] },
},
// outputs
clrWizardOpenChange: { control: { disable: true } },
clrWizardCurrentPageChanged: { control: { disable: true } },
Expand Down Expand Up @@ -109,3 +112,10 @@ const WizardTemplate: Story = args => ({
export const Wizard: StoryObj = {
render: WizardTemplate,
};

export const FullScreenWizard: StoryObj = {
render: WizardTemplate,
args: {
clrWizardSize: 'full-screen',
},
};
31 changes: 31 additions & 0 deletions projects/angular/src/modal/_modal.clarity.scss
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,35 @@
.modal .modal-nav {
display: none;
}

// full-screen modals
.modal.modal-full-screen {
padding: modal-variables.$clr-modal-default-space;

.modal-dialog {
display: flex;
width: 100%;
height: 100%;

.modal-content-wrapper {
display: flex;
flex-grow: 1;
}

// This cannot be nested inside `.modal-content-wrapper` because that class is not documented for static css-only modals.
.modal-content {
display: flex;
flex-direction: column;
flex-grow: 1;
}

.modal-body-wrapper,
// This is needed because the `.modal-body-wrapper` class is not documented for static css-only modals.
.modal-body {
// Fill space to push footer to bottom.
flex-grow: 1;
max-height: 100%;
}
}
}
}
2 changes: 1 addition & 1 deletion projects/angular/src/modal/modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
~ The full license information can be found in LICENSE in the root directory of this project.
-->

<div class="modal" *ngIf="_open">
<div *ngIf="_open" class="modal" [class.modal-full-screen]="size == 'full-screen'">
<!--fixme: revisit when ngClass works with exit animation-->
<div
cdkTrapFocus
Expand Down
6 changes: 6 additions & 0 deletions projects/angular/src/modal/modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ describe('Modal', () => {

expect(compiled.querySelector('.modal-sm')).toBeNull();
expect(compiled.querySelector('.modal-lg')).not.toBeNull();

fixture.componentInstance.size = 'full-screen';
fixture.detectChanges();

expect(compiled.querySelector('.modal-lg')).toBeNull();
expect(compiled.querySelector('.modal-full-screen')).not.toBeNull();
}));

it('supports a clrModalClosable option', fakeAsync(() => {
Expand Down
9 changes: 8 additions & 1 deletion projects/demo/src/app/modal/modal-angular-show.demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@

<p>
Try it live:
<clr-toggle-container>
<label>Size</label>
<clr-toggle-wrapper>
<label>Full Screen</label>
<input clrToggle type="checkbox" [(ngModel)]="fullScreen" name="full-screen" />
</clr-toggle-wrapper>
</clr-toggle-container>
<button class="btn btn-primary" (click)="basic = true">Show modal</button>
</p>
<clr-modal [(clrModalOpen)]="basic">
<clr-modal [clrModalSize]="fullScreen ? 'full-screen' : 'md'" [(clrModalOpen)]="basic">
<h3 class="modal-title">I have a nice title</h3>
<div class="modal-body">
<p>But not much to say...</p>
Expand Down
1 change: 1 addition & 0 deletions projects/demo/src/app/modal/modal-angular-show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Component } from '@angular/core';
export class ModalAngularShowDemo {
// Booleans to open each example modal
basic = false;
fullScreen = false;

onModalClose() {
console.log('modal change event');
Expand Down
10 changes: 9 additions & 1 deletion projects/demo/src/app/wizard/wizard-basic.demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@
~ The full license information can be found in LICENSE in the root directory of this project.
-->

<clr-toggle-container>
<label>Size</label>
<clr-toggle-wrapper>
<label>Full Screen</label>
<input clrToggle type="checkbox" [(ngModel)]="fullScreen" name="full-screen" />
</clr-toggle-wrapper>
</clr-toggle-container>

<button class="btn btn-primary" (click)="wizard.open()">Open Wizard</button>

<clr-wizard #wizard [(clrWizardOpen)]="open">
<clr-wizard #wizard [clrWizardSize]="fullScreen ? 'full-screen' : 'xl'" [(clrWizardOpen)]="open">
<clr-wizard-title>Wizard Title</clr-wizard-title>

<clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
Expand Down
1 change: 1 addition & 0 deletions projects/demo/src/app/wizard/wizard-basic.demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ import { ClrWizard } from '@clr/angular';
export class WizardBasicDemo {
@ViewChild('wizard') wizard: ClrWizard;
open = false;
fullScreen = false;
}
3 changes: 3 additions & 0 deletions tests/screenshot-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export const ScreenshotOptions: ScreenshotOptionsT = {
'modal--open-extra-large-modal': {
fullPageScreenshot: true,
},
'modal--open-full-screen-modal': {
fullPageScreenshot: true,
},
'signpost--opened': {
fullPageScreenshot: true,
},
Expand Down

0 comments on commit 4b19c42

Please sign in to comment.